Updated NEWS for 0.1.3.
[redact.git] / lib / redact / redact.rb
1 #--
2 # $Id: redact.rb 53 2005-06-11 13:21: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 # :nodoc:
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.1.2"
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) # :yields: collection
88                         c = @collections[name]
89
90                         block_given? ? (yield c) : c
91                 end
92
93                 protected
94                 def to_eet_name
95                         "Edje_File"
96                 end
97
98                 def to_eet_properties
99                         {"compiler" => ["redact"],
100                          "version" => [2],
101                          "feature_ver" => [1],
102                          "font_dir" => [@font_dir, :sub],
103                          "image_dir" => [@image_dir, :sub],
104                          "collection_dir" => [@collection_dir, :sub],
105                          "data" => [@data]}
106                 end
107         end
108
109         class DataHash < Hash # :nodoc:
110                 def [](key)
111                         super.value
112                 end
113
114                 def []=(key, value)
115                         super(key, HashEntry.new(key, value))
116                 end
117         end
118
119         class HashEntry # :nodoc:
120                 attr_reader :key, :value
121
122                 def initialize(key, value)
123                         @key = key.to_str.dup.freeze
124                         @value = value.to_str.dup.freeze
125                 end
126
127                 protected
128                 def to_eet_name
129                         "Edje_Data"
130                 end
131         end
132
133         class FontDirectory < Array # :nodoc:
134                 protected
135                 def to_eet_name
136                         "Edje_Font_Directory"
137                 end
138
139                 def to_eet_properties
140                         {"entries" => [self]}
141                 end
142         end
143
144         class FontDirectoryEntry # :nodoc:
145                 attr_reader :save_as, :filename, :alias
146
147                 def initialize(fn_alias, filename)
148                         @save_as = fn_alias.to_str.dup.freeze
149                         @filename = filename.to_str.dup.freeze
150                         @alias = "Edje." + fn_alias.sub(/.[^.]+$/, "").freeze
151                 end
152
153                 protected
154                 def to_eet_name
155                         "Edje_Font_Directory_Entry"
156                 end
157
158                 def to_eet_properties
159                         {"entry" => [@alias]}
160                 end
161         end
162
163         class ImageDirectory < Array # :nodoc:
164                 def <<(entry)
165                         super
166
167                         entry.id = size - 1
168                 end
169
170                 protected
171                 def to_eet_name
172                         "Edje_Image_Directory"
173                 end
174
175                 def to_eet_properties
176                         {"entries" => [self]}
177                 end
178         end
179
180         class ImageDirectoryEntry # :nodoc:
181                 attr_reader :filename, :image, :id
182
183                 def initialize(im_alias, filename)
184                         @alias = im_alias.to_str.dup.freeze
185                         @filename = filename.to_str.dup.freeze
186                         @image = Imlib2::Image.load(@filename)
187                         @id = -1
188                         @source_type = 1 # COMP
189                         @source_param = 1 # COMP
190                 end
191
192                 def id=(id)
193                         if id < 0
194                                 raise(ArgumentError, "invalid ID - #{id}")
195                         elsif @id != -1
196                                 raise(RedactError, "ID already set")
197                         else
198                                 @id = id
199                         end
200                 end
201
202                 protected
203                 def to_eet_name
204                         "Edje_Image_Directory_Entry"
205                 end
206
207                 def to_eet_properties
208                         {"entry" => [@alias],
209                          "source_type" => [@source_type],
210                          "source_param" => [@source_param],
211                          "id" => [@id]}
212                 end
213         end
214
215         class CollectionDirectory < Array # :nodoc:
216                 protected
217                 def to_eet_name
218                         "Edje_Part_Collection_Directory"
219                 end
220
221                 def to_eet_properties
222                         {"entries" => [self]}
223                 end
224         end
225
226         class CollectionDirectoryEntry # :nodoc:
227                 def initialize(col)
228                         @name = col.name.to_str.dup.freeze
229                         @id = col.id
230                 end
231
232                 protected
233                 def to_eet_name
234                         "Edje_Part_Collection_Directory_Entry"
235                 end
236
237                 def to_eet_properties
238                         {"entry" => [@name],
239                          "id" => [@id]}
240                 end
241         end
242
243         class Collection
244                 attr_reader :name, :id, :data, :min, :max, :parts, :programs,
245                             :script
246
247                 def initialize(name, id)
248                         @name = name.to_str.dup.freeze
249                         @id = id
250
251                         @min = [0, 0]
252                         @max = [0, 0]
253                         @data = DataHash.new
254
255                         @parts = {}
256                         @programs = {}
257
258                         @script = nil
259                 end
260
261                 def script=(v)
262                         @script = v.to_str.dup
263                 end
264
265                 def part(name, type = :invalid) # :yields: part
266                         p = @parts[name]
267                         if p.nil?
268                                 klass = case type
269                                 when :rect
270                                         Part
271                                 when :swallow
272                                         SwallowPart
273                                 when :text
274                                         TextPart
275                                 when :image
276                                         ImagePart
277                                 else
278                                         raise(ArgumentError,
279                                               "invalid part type - #{type.to_s}")
280                                 end
281
282                                 p = klass.new(self, @parts.size, name)
283                                 @parts[name] = p
284                         end
285
286                         block_given? ? (yield p) : p
287                 end
288
289                 def program(name, type = :invalid) # :yields: program
290                         p = @programs[name]
291                         if p.nil?
292                                 klass = case type
293                                 when :base
294                                         Program
295                                 when :set_state
296                                         SetStateProgram
297                                 when :stop_program
298                                         StopProgramProgram
299                                 when :emit_signal
300                                         EmitSignalProgram
301                                 when :exec_script
302                                         ExecScriptProgram
303                                 else
304                                         raise(ArgumentError,
305                                               "invalid program type - #{type.to_s}")
306                                 end
307
308                                 p = klass.new(self, @programs.size, name)
309                                 @programs[name] = p
310                         end
311
312                         block_given? ? (yield p) : p
313                 end
314
315                 def set_size(w, h)
316                         set_min(w, h)
317                         set_max(w, h)
318                 end
319
320                 def set_min(w, h)
321                         @min = [w, h]
322                 end
323
324                 def set_max(w, h)
325                         @max = [w, h]
326                 end
327
328                 def has_embryo?(search_programs = true)
329                         if !@script.nil? && @script.to_str.strip.length > 0
330                                 true
331                         elsif search_programs
332                                 p = @programs.find do |(k, p)|
333                                         p.is_a?(ExecScriptProgram)
334                                 end
335
336                                 !p.nil?
337                         end
338                 end
339
340                 protected
341                 def to_eet_name
342                         "Edje_Part_Collection"
343                 end
344
345                 def to_eet_properties
346                         # sort parts and programs by id, since edje doesn't sort
347                         # them on load
348                         parts = @parts.to_a.map { |(key, value)| value }.sort
349                         programs = @programs.to_a.map { |(key, value)| value }.sort
350
351                         {"id" => [@id],
352                          "parts" => [parts],
353                          "programs" => [programs],
354                          "data" => [@data],
355                          "prop.min.w" => [@min[0]],
356                          "prop.min.h" => [@min[1]],
357                          "prop.max.w" => [@max[0]],
358                          "prop.max.h" => [@max[1]]}
359                 end
360         end
361
362         EDJE = Redact::Edje.new
363 end