Initial commit.
[redact.git] / lib / redact / redact.rb
1 #--
2 # $Id: redact.rb 1 2005-03-26 01:32:38Z tilman $
3 #
4 # Copyright (c) 2005 Tilman Sauerbeck (tilman at code-monkey de)
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining
7 # a copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the Software, and to
11 # permit persons to whom the Software is furnished to do so, subject to
12 # the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25 require "eet"
26 require "imlib2"
27 require "redact/part"
28 require "redact/program"
29
30 class Object
31         undef :id
32 end
33
34 class String
35         def to_embryo(collection)
36                 unless strip.length > 0
37                         raise(Redact::RedactError, "invalid embryo code")
38                 end
39
40                 s = strip.dup
41
42                 {"part" => collection.parts,
43                  "program" => collection.programs}.each do |entity, ary|
44                         s.gsub!(/#{entity.upcase}:\"(.*?)\"/) do |m|
45                                 found = ary.find { |(k, p)| p.name == $1 }
46                                 if found.nil?
47                                         raise(Redact::RedactError,
48                                               "#{entity} not found - #{$1}")
49                                 else
50                                         found.last.id
51                                 end
52                         end
53                 end
54
55                 s
56         end
57 end
58
59 module Redact
60         VERSION = "0.0.1"
61
62         class RedactError < StandardError; end
63
64         class Edje
65                 attr_reader :collections, :data, :collection_dir, :image_dir,
66                             :font_dir
67
68                 def initialize
69                         clear
70                 end
71
72                 def clear
73                         @font_dir = FontDirectory.new
74                         @image_dir = ImageDirectory.new
75                         @collection_dir = CollectionDirectory.new
76
77                         @collections = Hash.new do |h, k|
78                                 c = Collection.new(k, h.size)
79
80                                 @collection_dir << CollectionDirectoryEntry.new(c)
81                                 h[k] = c
82                         end
83
84                         @data = DataHash.new
85                 end
86
87                 def collection(name)
88                         c = @collections[name]
89
90                         block_given? ? (yield c) : c
91                 end
92
93                 def to_eet_name
94                         "Edje_File"
95                 end
96
97                 def to_eet_properties
98                         {"compiler" => ["redact"],
99                          "version" => [2],
100                          "feature_ver" => [1],
101                          "font_dir" => [@font_dir, :sub],
102                          "image_dir" => [@image_dir, :sub],
103                          "collection_dir" => [@collection_dir, :sub],
104                          "data" => [@data]}
105                 end
106         end
107
108         class DataHash < Hash
109                 def [](key)
110                         super.value
111                 end
112
113                 def []=(key, value)
114                         super(key, HashEntry.new(key, value))
115                 end
116         end
117
118         class HashEntry
119                 attr_reader :key, :value
120
121                 def initialize(key, value)
122                         @key = key.to_str.dup.freeze
123                         @value = value.to_str.dup.freeze
124                 end
125
126                 def to_eet_name
127                         "Edje_Data"
128                 end
129         end
130
131         class FontDirectory < Array
132                 def to_eet_name
133                         "Edje_Font_Directory"
134                 end
135
136                 def to_eet_properties
137                         {"entries" => [self]}
138                 end
139         end
140
141         class FontDirectoryEntry
142                 attr_reader :filename
143
144                 def initialize(filename)
145                         @filename = filename.to_str.dup.freeze
146                 end
147
148                 def to_eet_name
149                         "Edje_Font_Directory_Entry"
150                 end
151
152                 def to_eet_properties
153                         {"entry" => [@filename]}
154                 end
155         end
156
157         class ImageDirectory < Array
158                 def <<(entry)
159                         super
160
161                         entry.id = size - 1
162                 end
163
164                 def to_eet_name
165                         "Edje_Image_Directory"
166                 end
167
168                 def to_eet_properties
169                         {"entries" => [self]}
170                 end
171         end
172
173         class ImageDirectoryEntry
174                 attr_reader :filename, :image, :id
175
176                 def initialize(filename)
177                         @filename = filename.to_str.dup.freeze
178                         @image = Imlib2::Image.load(@filename)
179                         @id = -1
180                         @source_type = 1 # COMP
181                         @source_param = 1 # COMP
182                 end
183
184                 def id=(id)
185                         if id < 0
186                                 raise(ArgumentError, "invalid ID - #{id}")
187                         elsif @id != -1
188                                 raise(RedactError, "ID already set")
189                         else
190                                 @id = id
191                         end
192                 end
193
194                 def to_eet_name
195                         "Edje_Image_Directory_Entry"
196                 end
197
198                 def to_eet_properties
199                         {"entry" => [@filename],
200                          "source_type" => [@source_type],
201                          "source_param" => [@source_param],
202                          "id" => [@id]}
203                 end
204         end
205
206         class CollectionDirectory < Array
207                 def to_eet_name
208                         "Edje_Part_Collection_Directory"
209                 end
210
211                 def to_eet_properties
212                         {"entries" => [self]}
213                 end
214         end
215
216         class CollectionDirectoryEntry
217                 def initialize(col)
218                         @name = col.name.to_str.dup.freeze
219                         @id = col.id
220                 end
221
222                 def to_eet_name
223                         "Edje_Part_Collection_Directory_Entry"
224                 end
225
226                 def to_eet_properties
227                         {"entry" => [@name],
228                          "id" => [@id]}
229                 end
230         end
231
232         class Collection
233                 attr_reader :name, :id, :data, :min, :max, :parts, :programs
234                 attr_accessor :script
235
236                 def initialize(name, id)
237                         @name = name.to_str.dup.freeze
238                         @id = id
239
240                         @min = [0, 0]
241                         @max = [0, 0]
242                         @data = DataHash.new
243
244                         @parts = {}
245                         @programs = {}
246
247                         @script = nil
248                 end
249
250                 def part(name, type = :invalid)
251                         p = @parts[name]
252                         if p.nil?
253                                 klass = case type
254                                 when :rect
255                                         Part
256                                 when :swallow
257                                         SwallowPart
258                                 when :text
259                                         TextPart
260                                 when :image
261                                         ImagePart
262                                 else
263                                         raise(ArgumentError,
264                                               "invalid program type - #{type.to_s}")
265                                 end
266
267                                 p = klass.new(self, @parts.size, name)
268                                 @parts[name] = p
269                         end
270
271                         block_given? ? (yield p) : p
272                 end
273
274                 def program(name, type = :invalid)
275                         p = @programs[name]
276                         if p.nil?
277                                 klass = case type
278                                 when :base
279                                         Program
280                                 when :set_state
281                                         SetStateProgram
282                                 when :stop_program
283                                         StopProgramProgram
284                                 when :emit_signal
285                                         EmitSignalProgram
286                                 when :exec_script
287                                         ExecScriptProgram
288                                 else
289                                         raise(ArgumentError,
290                                               "invalid program type - #{type.to_s}")
291                                 end
292
293                                 p = klass.new(self, @programs.size, name)
294                                 @programs[name] = p
295                         end
296
297                         block_given? ? (yield p) : p
298                 end
299
300                 def set_size(w, h)
301                         set_min(w, h)
302                         set_max(w, h)
303                 end
304
305                 def set_min(w, h)
306                         @min = [w, h]
307                 end
308
309                 def set_max(w, h)
310                         @max = [w, h]
311                 end
312
313                 def has_embryo?(search_programs = true)
314                         if !@script.nil? && @script.to_str.strip.length > 0
315                                 true
316                         elsif search_programs
317                                 p = @programs.find do |(k, p)|
318                                         p.is_a?(ExecScriptProgram)
319                                 end
320
321                                 !p.nil?
322                         end
323                 end
324
325                 def to_eet_name
326                         "Edje_Part_Collection"
327                 end
328
329                 def to_eet_properties
330                         # sort parts and programs by id, since edje doesn't sort
331                         # them on load
332                         parts = @parts.to_a.map { |(key, value)| value }.sort
333                         programs = @programs.to_a.map { |(key, value)| value }.sort
334
335                         {"id" => [@id],
336                          "parts" => [parts],
337                          "programs" => [programs],
338                          "data" => [@data],
339                          "prop.min.w" => [@min[0]],
340                          "prop.min.h" => [@min[1]],
341                          "prop.max.w" => [@max[0]],
342                          "prop.max.h" => [@max[1]]}
343                 end
344         end
345
346         EDJE = Redact::Edje.new
347 end