+#--
+# $Id: part.rb 1 2005-03-26 01:32:38Z tilman $
+#
+# Copyright (c) 2005 Tilman Sauerbeck (tilman at code-monkey de)
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+module Redact
+ class Part
+ TYPE_RECTANGLE = 1
+ TYPE_TEXT = 2
+ TYPE_IMAGE = 3
+ TYPE_SWALLOW = 4
+
+ include Comparable
+
+ attr_reader :collection, :id, :name, :dragable, :clip
+ attr_accessor :mouse_events, :repeat_events
+
+ def initialize(collection, id, name)
+ @collection = collection
+ @id = id
+
+ @name = name.to_str.dup.freeze
+ @type = TYPE_RECTANGLE
+ @mouse_events = true
+ @repeat_events = false
+ @clip = nil
+ @dragable = Dragable.new(self)
+
+ @descriptions = Hash.new do |h, k|
+ desc, value = k.split("\0")
+ value = value.to_f
+
+ h[k] = description_class.new(desc, value)
+ end
+ end
+
+ def <=>(b)
+ @id <=> b.id
+ end
+
+ def clip=(part)
+ if self == part
+ raise(ArgumentError, "cannot clip part to itself")
+ elsif part.nil?
+ @clip = nil
+ elsif part.collection != @collection
+ raise(ArgumentError, "parts' collections not identical")
+ else
+ @clip = part
+ end
+ end
+
+ def description(name = "default", value = 0.0)
+ d = @descriptions[desc_key(name, value)]
+
+ block_given? ? (yield d) : d
+ end
+
+ protected
+ def description_class
+ Description
+ end
+
+ def to_eet_name
+ "Edje_Part"
+ end
+
+ def to_eet_properties
+ other_desc = @descriptions.dup
+ other_desc.delete(desc_key("default", 0.0))
+
+ confine_id = @dragable.confine.nil? ?
+ -1 : @dragable.confine.id
+
+ {"name" => [@name],
+ "id" => [@id],
+ "type" => [@type, :char],
+ "effect" => [0, :char],
+ "mouse_events" => [@mouse_events],
+ "repeat_events" => [@repeat_events],
+ "clip_to_id" => [@clip.nil? ? -1 : @clip.id],
+ "default_desc" => [description("default", 0.0)],
+ "other_desc" => [other_desc],
+ "dragable.x" => [@dragable.enabled[0], :char],
+ "dragable.step_x" => [@dragable.step[0]],
+ "dragable.count_x" => [@dragable.count[0]],
+ "dragable.y" => [@dragable.enabled[1], :char],
+ "dragable.step_y" => [@dragable.step[1]],
+ "dragable.count_y" => [@dragable.count[1]],
+ "dragable.counfine_id" => [confine_id]} # not a typo!
+ end
+
+ private
+ def desc_key(name, value)
+ name + "\0" + value.to_s
+ end
+ end
+
+ class SwallowPart < Part
+ def initialize(collection, id, name)
+ super
+
+ @type = TYPE_SWALLOW
+ end
+ end
+
+ class TextPart < Part
+ EFFECT_NONE = 0
+ EFFECT_PLAIN = 1
+ EFFECT_OUTLINE = 2
+ EFFECT_SOFT_OUTLINE = 3
+ EFFECT_SHADOW = 4
+ EFFECT_SOFT_SHADOW = 5
+ EFFECT_OUTLINE_SHADOW = 6
+ EFFECT_OUTLINE_SOFT_SHADOW = 7
+
+ attr_accessor :effect
+
+ def initialize(collection, id, name)
+ super
+
+ @type = TYPE_TEXT
+ @effect = EFFECT_NONE
+ end
+
+ protected
+ def description_class
+ TextDescription
+ end
+
+ def to_eet_properties
+ super.merge!({"effect" => [@effect, :char]})
+ end
+ end
+
+ class ImagePart < Part
+ def initialize(collection, id, name)
+ super
+
+ @type = TYPE_IMAGE
+ end
+
+ protected
+ def description_class
+ ImageDescription
+ end
+ end
+
+ class Dragable
+ attr_reader :enabled, :step, :count, :confine
+
+ def initialize(part)
+ @part= part
+
+ @enabled = [false, false]
+ @step = [0, 0]
+ @count = [0, 0]
+ @confine = nil
+ end
+
+ def confine=(part)
+ if part == self
+ raise(ArgumentError, "cannot confine part to itself")
+ elsif !part.nil? && part.collection != @part.collection
+ raise(ArgumentError, "parts' collections not identical")
+ else
+ @confine = part
+ end
+ end
+ end
+
+ class Relation
+ attr_reader :rel, :to_id, :offset
+
+ def initialize(rel, offset)
+ @rel = [rel, rel]
+ @to_id = [-1, -1]
+ @offset = [offset, offset]
+ end
+
+ def set_rel(x, y)
+ @rel = [x, y]
+ end
+
+ def set_offset(x, y)
+ @offset = [x, y]
+ end
+
+ def to=(part)
+ @to_id = [].fill(part.nil? ? -1 : part.id, 0..1)
+ end
+ end
+
+ class Description
+ attr_reader :rel
+ attr_accessor :visible
+
+ def initialize(name = "default", value = 0.0)
+ @name = name.to_str.dup.freeze
+ @value = value.freeze
+ @visible = true
+ @align = [0.5, 0.5]
+ @min = [0, 0]
+ @max = [-1, -1]
+ @step_x = 0
+ @step_y = 0
+ @rel = [Relation.new(0.0, 0), Relation.new(1.0, -1)]
+ @color = [].fill(255, 0..3)
+ @color_class = ""
+ end
+
+ def set_align(x = 0.5, y = 0.5)
+ @align = [x, y]
+ end
+
+ def set_size(w, h)
+ set_min(w, h)
+ set_max(w, h)
+ end
+
+ def set_min(w, h)
+ @min = [w, h]
+ end
+
+ def set_max(w, h)
+ @max = [w, h]
+ end
+
+ def color=(c)
+ @color = parse_hex_color(c)
+ end
+
+ protected
+ def parse_hex_color(c)
+ md = c.match(/^#?(([[:xdigit:]]{2}){1,4})$/)
+ if md.nil?
+ raise(ArgumentError, "Argument is not a hex string")
+ end
+
+ pairs = md.captures.shift.split(/(..)/).delete_if do |item|
+ item == ""
+ end
+
+ pairs.push("00") while pairs.length < 3
+ pairs.push("ff") if pairs.length == 3
+
+ pairs.map { |p| p.hex }
+ end
+
+ def to_eet_name
+ "Edje_Part_Description"
+ end
+
+ def to_eet_properties
+ {"state.name" => [@name],
+ "state.value" => [@value, :double],
+ "visible" => [@visible],
+ "align.x" => [@align[0], :double],
+ "align.y" => [@align[1], :double],
+ "min.w" => [@min[0]],
+ "min.h" => [@min[1]],
+ "max.w" => [@max[0]],
+ "max.h" => [@max[1]],
+ "step.x" => [@step_x],
+ "step.y" => [@step_y],
+ "aspect.min" => [0.0, :double],
+ "aspect.max" => [0.0, :double],
+ "aspect.prefer" => [0, :char],
+ "rel1.relative_x" => [@rel[0].rel[0], :double],
+ "rel1.relative_y" => [@rel[0].rel[1], :double],
+ "rel1.offset_x" => [@rel[0].offset[0]],
+ "rel1.offset_y" => [@rel[0].offset[1]],
+ "rel1.id_x" => [@rel[0].to_id[0]],
+ "rel1.id_y" => [@rel[0].to_id[1]],
+ "rel2.relative_x" => [@rel[1].rel[0], :double],
+ "rel2.relative_y" => [@rel[1].rel[1], :double],
+ "rel2.offset_x" => [@rel[1].offset[0]],
+ "rel2.offset_y" => [@rel[1].offset[1]],
+ "rel2.id_x" => [@rel[1].to_id[0]],
+ "rel2.id_y" => [@rel[1].to_id[1]],
+ "color_class" => [@color_class],
+ "color.r" => [@color[0], :char],
+ "color.g" => [@color[1], :char],
+ "color.b" => [@color[2], :char],
+ "color.a" => [@color[3], :char],
+
+ # image properties
+ "image.id" => [-1],
+ "image.tween_list" => [nil],
+ "border.l" => [0],
+ "border.r" => [0],
+ "border.t" => [0],
+ "border.b" => [0],
+ "fill.smooth" => [true],
+ "fill.pos_rel_x" => [0.0, :double],
+ "fill.pos_abs_x" => [0],
+ "fill.rel_x" => [1.0, :double],
+ "fill.abs_x" => [0],
+ "fill.pos_rel_y" => [0.0, :double],
+ "fill.pos_abs_y" => [0],
+ "fill.rel_y" => [1.0, :double],
+ "fill.abs_y" => [0],
+
+ # text properties
+ "color2.r" => [0, :char],
+ "color2.g" => [0, :char],
+ "color2.b" => [0, :char],
+ "color2.a" => [255, :char],
+ "color3.r" => [0, :char],
+ "color3.g" => [0, :char],
+ "color3.b" => [0, :char],
+ "color3.a" => [128, :char],
+ "text.text" => [""],
+ "text.text_class" => [""],
+ "text.font" => [""],
+ "text.size" => [0],
+ "text.fit_x" => [false],
+ "text.fit_y" => [false],
+ "text.min_x" => [0],
+ "text.min_y" => [0],
+ "text.align.x" => [0.0, :double],
+ "text.align.y" => [0.0, :double],
+ "text.id_source" => [-1],
+ "text.id_text_source" => [-1]}
+ end
+ end
+
+ class Tween
+ def initialize(image)
+ @id = image.id
+ end
+
+ def to_eet_name
+ "Edje_Part_Image_Id"
+ end
+ end
+
+ class Tweens < Array
+ def <<(im)
+ image = EDJE.image_dir.find { |e| e.filename == im }
+ if image.nil?
+ image = ImageDirectoryEntry.new(im)
+ EDJE.image_dir << image
+ end
+
+ super(Tween.new(image))
+ end
+ end
+
+ class ImageDescription < Description
+ attr_reader :image, :auto_rel, :tweens
+
+ def initialize(name = "default", value = 0.0)
+ super
+
+ @image = nil
+ @tweens = Tweens.new
+ @border = [0, 0, 0, 0]
+ @fill_smooth = true
+ @auto_rel = false
+ end
+
+ def image=(im)
+ return if !@image.nil? && im == @image.filename
+
+ @image = EDJE.image_dir.find { |e| e.filename == im }
+ if @image.nil?
+ @image = ImageDirectoryEntry.new(im)
+ EDJE.image_dir << @image
+ end
+
+ self.auto_rel = @auto_rel
+ end
+
+ def auto_rel=(b)
+ @auto_rel = b
+
+ if @auto_rel && !@image.nil?
+ off = @rel[0].offset
+
+ @rel[1].set_rel(0.0, 0.0)
+ @rel[1].set_offset(off[0] + @image.image.width - 1,
+ off[1] + @image.image.height - 1)
+ end
+ end
+
+ def set_border(l = 0, r = 0, t = 0, b = 0)
+ @border = [r, r, t, b]
+ end
+
+ def to_eet_properties
+ super.merge!(
+ {"image.id" => [@image.nil? ? -1 : @image.id],
+ "image.tween_list" => [@tweens],
+ "border.l" => [@border[0]],
+ "border.r" => [@border[1]],
+ "border.t" => [@border[2]],
+ "border.b" => [@border[3]],
+ "fill.smooth" => [@fill_smooth],
+ "fill.pos_rel_x" => [0.0, :double],
+ "fill.pos_abs_x" => [0],
+ "fill.rel_x" => [1.0, :double],
+ "fill.abs_x" => [0],
+ "fill.pos_rel_y" => [0.0, :double],
+ "fill.pos_abs_y" => [0],
+ "fill.rel_y" => [1.0, :double],
+ "fill.abs_y" => [0]})
+ end
+ end
+
+ class TextDescription < Description
+ attr_reader :font
+ attr_accessor :text, :font_size
+
+ def initialize(name = "default", value = 0.0)
+ super
+
+ @outline_color = [0, 0, 0, 255]
+ @shadow_color = [0, 0, 0, 128]
+ @text = ""
+ @text_class = ""
+ @font = ""
+ @font_size = 0
+ @fit = [false, false]
+ @text_min = [false, false]
+ @text_align = [0.5, 0.5]
+ @text_id_source = -1
+ @text_id_text_source = -1
+ end
+
+ def set_fit(x = false, y = false)
+ @fit = [x, y]
+ end
+
+ def set_text_min(x = false, y = false)
+ @text_min = [x, y]
+ end
+
+ def set_text_align(x = 0.5, y = 0.5)
+ @text_align = [x, y]
+ end
+
+ def font=(f)
+ md = f.to_str.match(/.*\.ttf/)
+ unless md.nil?
+ found = EDJE.font_dir.find { |font| font.filename == f }
+ if found.nil?
+ EDJE.font_dir << FontDirectoryEntry.new(f)
+ end
+ end
+
+ @font = f.dup
+ end
+
+ def outline_color=(c)
+ @outline_color = parse_hex_color(c)
+ end
+
+ def shadow_color=(c)
+ @shadow_color = parse_hex_color(c)
+ end
+
+ def to_eet_properties
+ super.merge!(
+ {"color2.r" => [@outline_color[0], :char],
+ "color2.g" => [@outline_color[1], :char],
+ "color2.b" => [@outline_color[2], :char],
+ "color2.a" => [@outline_color[3], :char],
+ "color3.r" => [@shadow_color[0], :char],
+ "color3.g" => [@shadow_color[1], :char],
+ "color3.b" => [@shadow_color[2], :char],
+ "color3.a" => [@shadow_color[3], :char],
+ "text.text" => [@text],
+ "text.text_class" => [@text_class],
+ "text.font" => [@font],
+ "text.size" => [@font_size],
+ "text.fit_x" => [@fit[0]],
+ "text.fit_y" => [@fit[1]],
+ "text.min_x" => [@text_min[0]],
+ "text.min_y" => [@text_min[1]],
+ "text.align.x" => [@text_align[0], :double],
+ "text.align.y" => [@text_align[1], :double],
+ "text.id_source" => [@text_id_source],
+ "text.id_text_source" => [@text_id_text_source]})
+ end
+ end
+end