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