2 # Copyright (c) 2005 Tilman Sauerbeck (tilman at code-monkey de)
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:
12 # The above copyright notice and this permission notice shall be
13 # included in all copies or substantial portions of the Software.
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.
32 attr_reader :collection, :id, :name, :dragable, :clip,
33 :mouse_events, :repeat_events
35 def initialize(collection, id, name)
36 @collection = collection
39 @name = name.to_str.dup.freeze
40 @type = TYPE_RECTANGLE
42 @repeat_events = false
44 @dragable = Dragable.new(self)
46 @descriptions = Hash.new do |h, k|
47 desc, value = k.split("\0")
50 h[k] = description_class.new(desc, value)
58 def mouse_events=(val)
59 @mouse_events = (val == true)
62 def repeat_events=(val)
63 @repeat_events = (val == true)
68 raise(ArgumentError, "cannot clip part to itself")
69 elsif !part.nil? && part.collection != @collection
70 raise(ArgumentError, "items not in the same collection")
76 def description(name = "default", value = 0.0) # :yields: desc
77 d = @descriptions[desc_key(name, value)]
79 block_given? ? (yield d) : d
92 other_desc = @descriptions.dup
93 other_desc.delete(desc_key("default", 0.0))
95 confine_id = @dragable.confine.nil? ?
96 -1 : @dragable.confine.id
100 "type" => [@type, :char],
101 "effect" => [0, :char],
102 "mouse_events" => [@mouse_events],
103 "repeat_events" => [@repeat_events],
104 "clip_to_id" => [@clip.nil? ? -1 : @clip.id],
105 "default_desc" => [description("default", 0.0)],
106 "other_desc" => [other_desc],
107 "dragable.x" => [@dragable.enabled[0], :char],
108 "dragable.step_x" => [@dragable.step[0]],
109 "dragable.count_x" => [@dragable.count[0]],
110 "dragable.y" => [@dragable.enabled[1], :char],
111 "dragable.step_y" => [@dragable.step[1]],
112 "dragable.count_y" => [@dragable.count[1]],
113 "dragable.events_id" => [-1],
114 "dragable.counfine_id" => [confine_id]} # not a typo!
118 def desc_key(name, value)
119 name + "\0" + value.to_s
123 class SwallowPart < Part
124 def initialize(collection, id, name)
131 class TextPart < Part
132 attr_accessor :effect
134 def initialize(collection, id, name)
139 @use_alternate_font_metrics = false
142 def use_alternate_font_metrics=(b)
143 @use_alternate_font_metrics = (b == true)
147 def description_class
151 def to_eet_properties
152 effect = case @effect
156 when :soft_outline: 3
159 when :outline_shadow: 6
160 when :outline_soft_shadow: 7
162 raise(RedactError, "invalid effect value - #{@effect}")
166 {"effect" => [effect, :char],
167 "use_alternate_font_metrics" => [@use_alternate_font_metrics, :char]})
171 class ImagePart < Part
172 def initialize(collection, id, name)
179 def description_class
185 attr_reader :enabled, :step, :count, :confine
190 @enabled = [false, false]
198 raise(ArgumentError, "cannot confine part to itself")
199 elsif !part.nil? && part.collection != @part.collection
200 raise(ArgumentError, "items not in the same collection")
208 attr_reader :rel, :to_id, :offset
210 def initialize(rel, offset)
211 @rel = [rel.to_f, rel.to_f]
213 @offset = [offset, offset]
217 @rel = [x.to_f, y.to_f]
228 def set_to(part_x, part_y = part_x)
229 @to_id = [part_x.nil? ? -1 : part_x.id,
230 part_y.nil? ? -1 : part_y.id]
235 attr_reader :rel, :aspect, :step, :visible, :color_class
236 attr_accessor :aspect_preference
238 def initialize(name = "default", value = 0.0)
239 @name = name.to_str.dup.freeze
240 @value = value.freeze
247 @aspect_preference = :none
248 @rel = [Relation.new(0.0, 0), Relation.new(1.0, -1)]
249 @color = [].fill(255, 0..3)
254 unless other.is_a?(Description)
255 raise(ArgumentError, "Cannot inherit from description")
258 prot = ["@name", "@value"]
260 (instance_variables - prot).each do |v|
261 n = other.instance_variable_get(v.intern)
263 instance_variable_set(v.intern, n)
268 @visible = (v == true)
272 @color_class = v.to_str.dup
275 def set_step(x = 0, y = 0)
279 def set_aspect(x = 0.0, y = 0.0)
283 def set_align(x = 0.5, y = 0.5)
301 @color = parse_hex_color(c)
305 def parse_hex_color(c)
306 md = c.match(/^#?(([[:xdigit:]]{2}){1,4})$/)
308 raise(ArgumentError, "Argument is not a hex string")
311 pairs = md.captures.shift.split(/(..)/).delete_if do |item|
315 pairs.push("00") while pairs.length < 3
316 pairs.push("ff") if pairs.length == 3
318 pairs.map { |p| p.hex }
322 "Edje_Part_Description"
325 def to_eet_properties
326 asp_pref = case @aspect_preference
332 raise(RedactError, "invalid aspect preference value - " +
333 @aspect_preference.to_s)
336 {"state.name" => [@name],
337 "state.value" => [@value, :double],
338 "visible" => [@visible],
339 "align.x" => [@align[0], :double],
340 "align.y" => [@align[1], :double],
341 "min.w" => [@min[0]],
342 "min.h" => [@min[1]],
343 "max.w" => [@max[0]],
344 "max.h" => [@max[1]],
345 "step.x" => [@step[0]],
346 "step.y" => [@step[1]],
347 "aspect.min" => [@aspect[0], :double],
348 "aspect.max" => [@aspect[1], :double],
349 "aspect.prefer" => [asp_pref, :char],
350 "rel1.relative_x" => [@rel[0].rel[0], :double],
351 "rel1.relative_y" => [@rel[0].rel[1], :double],
352 "rel1.offset_x" => [@rel[0].offset[0]],
353 "rel1.offset_y" => [@rel[0].offset[1]],
354 "rel1.id_x" => [@rel[0].to_id[0]],
355 "rel1.id_y" => [@rel[0].to_id[1]],
356 "rel2.relative_x" => [@rel[1].rel[0], :double],
357 "rel2.relative_y" => [@rel[1].rel[1], :double],
358 "rel2.offset_x" => [@rel[1].offset[0]],
359 "rel2.offset_y" => [@rel[1].offset[1]],
360 "rel2.id_x" => [@rel[1].to_id[0]],
361 "rel2.id_y" => [@rel[1].to_id[1]],
362 "color_class" => [@color_class],
363 "color.r" => [@color[0], :char],
364 "color.g" => [@color[1], :char],
365 "color.b" => [@color[2], :char],
366 "color.a" => [@color[3], :char],
370 "image.tween_list" => [nil],
375 "border.no_fill" => [false],
376 "fill.smooth" => [true],
377 "fill.pos_rel_x" => [0.0, :double],
378 "fill.pos_abs_x" => [0],
379 "fill.rel_x" => [1.0, :double],
381 "fill.pos_rel_y" => [0.0, :double],
382 "fill.pos_abs_y" => [0],
383 "fill.rel_y" => [1.0, :double],
387 "color2.r" => [0, :char],
388 "color2.g" => [0, :char],
389 "color2.b" => [0, :char],
390 "color2.a" => [255, :char],
391 "color3.r" => [0, :char],
392 "color3.g" => [0, :char],
393 "color3.b" => [0, :char],
394 "color3.a" => [128, :char],
396 "text.text_class" => [""],
399 "text.fit_x" => [false],
400 "text.fit_y" => [false],
403 "text.align.x" => [0.0, :double],
404 "text.align.y" => [0.0, :double],
405 "text.id_source" => [-1],
406 "text.id_text_source" => [-1]}
411 def initialize(image)
423 im2 = find_image(im.to_str.strip)
424 raise(RedactError, "cannot find image - #{im}") if im2.nil?
426 image = EDJE.image_dir.find { |e| e.filename == im2 }
428 image = ImageDirectoryEntry.new(im, im2)
429 EDJE.image_dir << image
432 super(Tween.new(image))
437 [".", OPTIONS.image_dir].each do |d|
438 f2 = File.join(d, file)
439 return Pathname.new(f2).cleanpath.to_s if File.file?(f2)
447 class ImageDescription < Description
448 attr_reader :image, :auto_rel, :tweens, :border_fill_middle,
449 :fill_smooth, :fill_pos_rel, :fill_pos_abs,
452 def initialize(name = "default", value = 0.0)
457 @border = [0, 0, 0, 0]
458 @border_fill_middle = true
461 @fill_pos_rel = [0.0, 0.0]
462 @fill_pos_abs = [0, 0]
463 @fill_rel = [1.0, 1.0]
469 def border_fill_middle=(var)
470 @border_fill_middle = (var == true)
474 im2 = find_image(im.to_str.strip)
475 raise(RedactError, "cannot find image - #{im}") if im2.nil?
477 return if !@image.nil? && im2 == @image.filename
479 @image = EDJE.image_dir.find { |e| e.filename == im2 }
481 @image = ImageDirectoryEntry.new(im, im2)
482 EDJE.image_dir << @image
485 self.auto_rel = @auto_rel
491 if @auto_rel && !@image.nil?
494 @rel[1].set_rel(0.0, 0.0)
495 @rel[1].set_offset(off[0] + @image.image.width - 1,
496 off[1] + @image.image.height - 1)
500 def set_border(l = 0, r = 0, t = 0, b = 0)
501 @border = [l, r, t, b]
505 @fill_smooth = (v == true)
508 def set_fill_pos_rel(x, y)
509 @fill_pos_rel = [x.to_f, y.to_f]
512 def set_fill_pos_abs(x, y)
513 @fill_pos_abs = [x.to_i, y.to_i]
516 def set_fill_rel(x, y)
517 @fill_rel = [x.to_f, y.to_f]
520 def set_fill_abs(x, y)
521 @fill_abs = [x.to_i, y.to_i]
525 def to_eet_properties
527 {"image.id" => [@image.nil? ? -1 : @image.id],
528 "image.tween_list" => [@tweens],
529 "border.l" => [@border[0]],
530 "border.r" => [@border[1]],
531 "border.t" => [@border[2]],
532 "border.b" => [@border[3]],
533 "border.no_fill" => [!@border_fill_middle],
534 "fill.smooth" => [@fill_smooth],
535 "fill.pos_rel_x" => [@fill_pos_rel[0], :double],
536 "fill.pos_abs_x" => [@fill_pos_abs[0]],
537 "fill.rel_x" => [@fill_rel[0], :double],
538 "fill.abs_x" => [@fill_abs[0]],
539 "fill.pos_rel_y" => [@fill_pos_rel[1], :double],
540 "fill.pos_abs_y" => [@fill_pos_abs[1]],
541 "fill.rel_y" => [@fill_rel[1], :double],
542 "fill.abs_y" => [@fill_abs[1]]})
547 [".", OPTIONS.image_dir].each do |d|
548 f2 = File.join(d, file)
549 return Pathname.new(f2).cleanpath.to_s if File.file?(f2)
556 class TextDescription < Description
557 attr_reader :font, :text, :font_size, :text_class
559 def initialize(name = "default", value = 0.0)
562 @outline_color = [0, 0, 0, 255]
563 @shadow_color = [0, 0, 0, 128]
568 @fit = [false, false]
569 @text_min = [false, false]
570 @text_max = [false, false]
571 @text_align = [0.5, 0.5]
573 @text_id_text_source = -1
581 @font_size = v.to_int
585 @text_class = v.to_str.dup
588 def set_fit(x = false, y = false)
592 def set_text_min(x = false, y = false)
596 def set_text_max(x = false, y = false)
600 def set_text_align(x = 0.5, y = 0.5)
606 md = f.match(/.*\.ttf$/)
609 raise(RedactError, "cannot find font - #{f}") if f2.nil?
611 found = EDJE.font_dir.find { |font| font.filename == f2 }
613 EDJE.font_dir << FontDirectoryEntry.new(f, f2)
614 @font = EDJE.font_dir.last.alias
623 def outline_color=(c)
624 @outline_color = parse_hex_color(c)
628 @shadow_color = parse_hex_color(c)
632 def to_eet_properties
634 {"color2.r" => [@outline_color[0], :char],
635 "color2.g" => [@outline_color[1], :char],
636 "color2.b" => [@outline_color[2], :char],
637 "color2.a" => [@outline_color[3], :char],
638 "color3.r" => [@shadow_color[0], :char],
639 "color3.g" => [@shadow_color[1], :char],
640 "color3.b" => [@shadow_color[2], :char],
641 "color3.a" => [@shadow_color[3], :char],
642 "text.text" => [@text],
643 "text.text_class" => [@text_class],
644 "text.font" => [@font],
645 "text.size" => [@font_size],
646 "text.fit_x" => [@fit[0]],
647 "text.fit_y" => [@fit[1]],
648 "text.min_x" => [@text_min[0]],
649 "text.min_y" => [@text_min[1]],
650 "text.max_x" => [@text_max[0]],
651 "text.max_y" => [@text_max[1]],
652 "text.align.x" => [@text_align[0], :double],
653 "text.align.y" => [@text_align[1], :double],
654 "text.id_source" => [@text_id_source],
655 "text.id_text_source" => [@text_id_text_source]})
660 [".", OPTIONS.font_dir].each do |d|
661 f2 = File.join(d, file)
662 return Pathname.new(f2).cleanpath.to_s if File.file?(f2)