From e26cc0d6cb6436d3edc970235b35980524717174 Mon Sep 17 00:00:00 2001 From: aoitaku Date: Sun, 26 Jun 2016 21:58:06 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=95=E3=83=AD=E3=83=BC=E3=83=AC=E3=82=A4?= =?UTF-8?q?=E3=82=A2=E3=82=A6=E3=83=88=E3=81=A7=E3=81=8D=E3=81=AA=E3=81=84?= =?UTF-8?q?=E4=B8=8D=E5=85=B7=E5=90=88=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/quincite/components/component.rb | 492 +++++++++++++-------------- lib/quincite/components/layouter.rb | 434 ++++++++++++----------- lib/quincite/core/color.rb | 122 +++---- lib/quincite/core/dsl.rb | 258 +++++++------- lib/quincite/core/style.rb | 6 +- 5 files changed, 672 insertions(+), 640 deletions(-) diff --git a/lib/quincite/components/component.rb b/lib/quincite/components/component.rb index 2664099..1d99700 100644 --- a/lib/quincite/components/component.rb +++ b/lib/quincite/components/component.rb @@ -1,247 +1,247 @@ -module Quincite - - module UI - - module Component - - extend Forwardable - - attr_accessor :id - attr_reader :style - - attr_reader :content_width, :content_height - - def_delegator :@style, :position - def_delegators :@style, :top, :left, :bottom, :right - def_delegators :@style, :padding_top, :padding_bottom - def_delegators :@style, :padding_left, :padding_right - def_delegators :@style, :bg_image, :bg_color - def_delegators :@style, :border_width, :border_color - def_delegator :@style, :justify_content - def_delegator :@style, :align_items - def_delegator :@style, :layout, :layout_style - - def init_component - @style = Style.new - end - - def style_include?(name) - @style.respond_to?("#{name}=") - end - - def style_set(name, args) - @style.__send__("#{name}=", args) - end - - def width - @width || content_width || 0 - end - - def height - @height || content_height || 0 - end - - def layout_width - return 0 if position == :absolute - width + margin_left + margin_right - end - - def layout_height - return 0 if position == :absolute - height + margin_top + margin_bottom - end - - def margin_top - return 0 if position == :absolute - @style.margin_top - end - - def margin_right - return 0 if position == :absolute - @style.margin_right - end - - def margin_bottom - return 0 if position == :absolute - @style.margin_bottom - end - - def margin_left - return 0 if position == :absolute - @style.margin_left - end - - def horizontal_margin - margin_left + margin_right - end - - def offset_left(parent) - [parent.padding_left, margin_left].max - end - - def offset_right(parent) - [parent.padding_right, margin_right].max - end - - def horizontal_offset(parent) - offset_left(parent) + offset_right(parent) - end - - def vertical_margin - margin_top + margin_bottom - end - - def offset_top(parent) - [parent.padding_top, margin_top].max - end - - def offset_bottom(parent) - [parent.padding_bottom, margin_bottom].max - end - - def vertical_offset(parent) - offset_top(parent) + offset_bottom(parent) - end - - def inner_width(parent) - if parent.respond_to?(:padding_left) && parent.respond_to?(:padding_right) - parent.width - horizontal_offset(parent) - else - parent.width - horizontal_margin - end - end - - def inner_height(parent) - if parent.respond_to?(:padding_top) && parent.respond_to?(:padding_bottom) - parent.height - vertical_offset(parent) - else - parent.height - vertical_margin - end - end - - def layout(ox=0, oy=0, parent=RootContainer) - resize(parent) - move(ox, oy, parent) - end - - def move(to_x, to_y, parent) - move_x(to_x, parent) - move_y(to_y, parent) - end - - def move_x(to_x, parent) - if position == :absolute - if left and Numeric === left - case left - when Fixnum - self.x = to_x + left - when Float - self.x = to_x + (parent.width - self.width) * left - end - elsif right and Numeric === right - case right - when Fixnum - self.x = to_x + parent.width - self.width - right - when Float - self.x = to_x + (parent.width - self.width) * (1 - right) - end - else - self.x = to_x - end - else - if left and Numeric === left - case left - when Fixnum - self.x = to_x + left - when Float - self.x = to_x + left * self.width - end - elsif right and Numeric === right - case right - when Fixnum - self.x = to_x - right - when Float - self.x = to_x - right * self.width - end - else - self.x = to_x - end - end - end - private :move_x - - def move_y(to_y, parent) - if position == :absolute - if top and Numeric === top - case top - when Fixnum - self.y = to_y + top - when Float - self.y = to_y + (parent.height - self.height) * top - end - elsif bottom and Numeric === bottom - case bottom - when Fixnum - self.y = to_y + parent.height - self.height - bottom - when Float - self.y = to_y + (parent.height - self.height) * (1 - bottom) - end - else - self.y = to_y - end - else - if top and Numeric === top - case top - when Fixnum - self.y = to_y + top - when Float - self.y = to_y + top * self.height - end - elsif bottom and Numeric === bottom - case bottom - when Fixnum - self.y = to_y - bottom - when Float - self.y = to_y - bottom * self.height - end - else - self.y = to_y - end - end - end - private :move_y - - def resize(parent) - case @style.width - when Integer - @width = @style.width - when Float - @width = parent.width * @style.width - when :full - @width = inner_width(parent) - else - @width = nil - end - case @style.height - when Integer - @height = @style.height - when Float - @height = parent.height * @style.height - when :full - @height = inner_height(parent) - else - @height = nil - end - end - - def break_after? - !!@style.break_after - end - - def visible? - !!@style.visible - end - - end - end +module Quincite + + module UI + + module Component + + extend Forwardable + + attr_accessor :id + attr_reader :style + + attr_reader :content_width, :content_height + + def_delegator :@style, :position + def_delegators :@style, :top, :left, :bottom, :right + def_delegators :@style, :padding_top, :padding_bottom + def_delegators :@style, :padding_left, :padding_right + def_delegators :@style, :bg_image, :bg_color + def_delegators :@style, :border_width, :border_color + def_delegator :@style, :justify_content + def_delegator :@style, :align_items + def_delegator :@style, :layout, :layout_style + + def init_component + @style = Style.new + end + + def style_include?(name) + @style.respond_to?("#{name}=") + end + + def style_set(name, args) + @style.__send__("#{name}=", args) + end + + def width + @width || content_width || 0 + end + + def height + @height || content_height || 0 + end + + def layout_width + return 0 if position == :absolute + width + margin_left + margin_right + end + + def layout_height + return 0 if position == :absolute + height + margin_top + margin_bottom + end + + def margin_top + return 0 if position == :absolute + @style.margin_top + end + + def margin_right + return 0 if position == :absolute + @style.margin_right + end + + def margin_bottom + return 0 if position == :absolute + @style.margin_bottom + end + + def margin_left + return 0 if position == :absolute + @style.margin_left + end + + def horizontal_margin + margin_left + margin_right + end + + def offset_left(parent) + [parent.padding_left, margin_left].max + end + + def offset_right(parent) + [parent.padding_right, margin_right].max + end + + def horizontal_offset(parent) + offset_left(parent) + offset_right(parent) + end + + def vertical_margin + margin_top + margin_bottom + end + + def offset_top(parent) + [parent.padding_top, margin_top].max + end + + def offset_bottom(parent) + [parent.padding_bottom, margin_bottom].max + end + + def vertical_offset(parent) + offset_top(parent) + offset_bottom(parent) + end + + def inner_width(parent) + if parent.respond_to?(:padding_left) && parent.respond_to?(:padding_right) + parent.width - horizontal_offset(parent) + else + parent.width - horizontal_margin + end + end + + def inner_height(parent) + if parent.respond_to?(:padding_top) && parent.respond_to?(:padding_bottom) + parent.height - vertical_offset(parent) + else + parent.height - vertical_margin + end + end + + def layout(ox=0, oy=0, parent=RootContainer) + resize(parent) + move(ox, oy, parent) + end + + def move(to_x, to_y, parent) + move_x(to_x, parent) + move_y(to_y, parent) + end + + def move_x(to_x, parent) + if position == :absolute + if left and Numeric === left + case left + when Fixnum + self.x = to_x + left + when Float + self.x = to_x + (parent.width - self.width) * left + end + elsif right and Numeric === right + case right + when Fixnum + self.x = to_x + parent.width - self.width - right + when Float + self.x = to_x + (parent.width - self.width) * (1 - right) + end + else + self.x = to_x + end + else + if left and Numeric === left + case left + when Fixnum + self.x = to_x + left + when Float + self.x = to_x + left * self.width + end + elsif right and Numeric === right + case right + when Fixnum + self.x = to_x - right + when Float + self.x = to_x - right * self.width + end + else + self.x = to_x + end + end + end + private :move_x + + def move_y(to_y, parent) + if position == :absolute + if top and Numeric === top + case top + when Fixnum + self.y = to_y + top + when Float + self.y = to_y + (parent.height - self.height) * top + end + elsif bottom and Numeric === bottom + case bottom + when Fixnum + self.y = to_y + parent.height - self.height - bottom + when Float + self.y = to_y + (parent.height - self.height) * (1 - bottom) + end + else + self.y = to_y + end + else + if top and Numeric === top + case top + when Fixnum + self.y = to_y + top + when Float + self.y = to_y + top * self.height + end + elsif bottom and Numeric === bottom + case bottom + when Fixnum + self.y = to_y - bottom + when Float + self.y = to_y - bottom * self.height + end + else + self.y = to_y + end + end + end + private :move_y + + def resize(parent) + case @style.width + when Integer + @width = @style.width + when Float + @width = parent.width * @style.width + when :full + @width = inner_width(parent) + else + @width = nil + end + case @style.height + when Integer + @height = @style.height + when Float + @height = parent.height * @style.height + when :full + @height = inner_height(parent) + else + @height = nil + end + end + + def break_after? + !!@style.break_after + end + + def visible? + !!@style.visible + end + + end + end end \ No newline at end of file diff --git a/lib/quincite/components/layouter.rb b/lib/quincite/components/layouter.rb index e10853b..6f25c1a 100644 --- a/lib/quincite/components/layouter.rb +++ b/lib/quincite/components/layouter.rb @@ -1,203 +1,233 @@ -module Quincite - - module UI - - module Layouter - - def resize(parent) - super - __send__(:"#{layout_style}_resize") - update_collision - self - end - - def move(ox=0, oy=0, parent) - super - __send__(:"#{layout_style}_move") - self - end - - def flow_resize - v_margin = padding_top - @content_width = @width || UI.max_width - @content_height = components.lazy.each {|component| - component.resize(self) - }.slice_before(&components_overflow?).inject(0) {|height, row| - component = row.max_by(&:layout_height) - next height if component.position == :absolute - v_space = [v_margin, component.margin_top].max + height - v_margin = component.margin_bottom - v_space + component.height - } + [v_margin, padding_bottom].max - end - private :flow_resize - - def flow_move - v_margin = padding_top - components.slice_before(&components_overflow?).inject(0) do |height, row| - component = row.max_by(&:layout_height) - max_component_height = component.height - v_space = [v_margin, component.margin_top].max + height - v_margin = component.margin_bottom - inner_width = row.inject(0, &row_injection) + [row.last.margin_right, padding_right].max - row.inject(0, &row_injection {|component, h_space| - x = self.x + h_space + case justify_content - when :space_between - if row.size > 1 and not row.last.break_after? - h_space += (self.width - inner_width) / (row.size - 1).to_f - end - 0 - when :center - (self.width - inner_width) / 2.0 - when :right - self.width - inner_width - else - 0 - end - y = self.y + v_space + case align_items - when :center - (max_component_height - component.height) / 2.0 - when :bottom - max_component_height - component.height - else - 0 - end - if component.position == :absolute - component.move(self.x, self.y, self) - else - component.move(x, y, self) - end - h_space - }) - v_space + max_component_height - end - end - private :flow_move - - def row_injection(&with) - h_margin = padding_left - -> width, component do - h_space = [h_margin, component.margin_left].max + width - h_space = with.call(component, h_space) if with - next width if component.position == :absolute - h_margin = component.margin_right - h_space + component.width - end - end - private :row_injection - - def vertical_box_resize - v_margin = padding_top - @content_height = components.inject(0) {|height, component| - component.resize(self) - next height if component.position == :absolute - v_space = [v_margin, component.margin_top].max + height - v_margin = component.margin_bottom - v_space + component.height - } + [v_margin, padding_bottom].max - component = components.max_by(&:layout_width) - if component - @content_width = component.width + - [component.margin_left, padding_left].max + - [component.margin_right, padding_right].max - end - end - private :vertical_box_resize - - def vertical_box_move - v_margin = padding_top - components.inject(0) do |height, component| - h_space = [padding_left, component.margin_left].max - v_space = [v_margin, component.margin_top].max + height - x = self.x + h_space + case justify_content - when :center - (component.inner_width(self) - component.width) / 2 - when :right - component.inner_width(self) - component.width - else - 0 - end - y = self.y + v_space + case align_items - when :space_between - if @height and components.size > 1 - v_space += (@height - @content_height) / (components.size - 1) - end - 0 - when :center - @height ? (@height - @content_height) / 2 : 0 - when :bottom - @height ? @height - @content_height : 0 - else - 0 - end - if component.position == :absolute - component.move(self.x, self.y, self) - else - component.move(x, y, self) - end - next height if component.position == :absolute - v_margin = component.margin_bottom - v_space + component.height - end - end - private :vertical_box_move - - def horizontal_box_resize - h_margin = padding_left - @content_width = components.inject(0) {|width, component| - component.resize(self) - next width if component.position == :absolute - h_space = [h_margin, component.margin_left].max + width - h_margin = component.margin_right - h_space + component.width - } + [h_margin, padding_right].max - component = components.max_by(&:layout_height) - if component - @content_height = component.height + - [component.margin_top, padding_top].max + - [component.margin_bottom, padding_bottom].max - end - end - private :horizontal_box_resize - - def horizontal_box_move - h_margin = padding_left - components.inject(0) do |width, component| - h_space = [h_margin, component.margin_left].max + width - v_space = [padding_top, component.margin_top].max - x = self.x + h_space + case justify_content - when :space_between - if @width and components.size > 1 - h_space += (@width - @content_width) / (components.size - 1) - end - 0 - when :center - @width ? (@width - @content_width) / 2 : 0 - when :right - @width ? @width - @content_width : 0 - else - 0 - end - y = self.y + v_space + case align_items - when :center - (component.inner_height(self) - component.height) / 2 - when :bottom - component.inner_height(self) - component.height - else - 0 - end - if component.position == :absolute - component.move(self.x, self.y, self) - else - component.move(x, y, self) - end - next width if component.position == :absolute - h_margin = component.margin_right - h_space + component.width - end - end - private :horizontal_box_move - - end - end +module Quincite + + module UI + + module Layouter + + def resize(parent) + super + __send__(:"#{layout_style}_resize") + update_collision + self + end + + def move(ox=0, oy=0, parent) + super + __send__(:"#{layout_style}_move") + self + end + + def flow_resize + v_margin = padding_top + @content_width = @width || UI.max_width + @content_height = components.lazy.each {|component| + component.resize(self) + }.slice_before(&components_overflow?).inject(0) {|height, row| + component = row.max_by(&:layout_height) + next height if component.position == :absolute + v_space = [v_margin, component.margin_top].max + height + v_margin = component.margin_bottom + v_space + component.height + } + [v_margin, padding_bottom].max + end + private :flow_resize + + def flow_move + v_margin = padding_top + components.slice_before(&components_overflow?).inject(0) do |height, row| + component = row.max_by(&:layout_height) + max_component_height = component.height + v_space = [v_margin, component.margin_top].max + height + v_margin = component.margin_bottom + inner_width = row.inject(0, &row_injection) + [row.last.margin_right, padding_right].max + row.inject(0, &row_injection {|component, h_space| + x = self.x + h_space + case justify_content + when :space_between + if row.size > 1 and not row.last.break_after? + h_space += (self.width - inner_width) / (row.size - 1).to_f + end + 0 + when :center + (self.width - inner_width) / 2.0 + when :right + self.width - inner_width + else + 0 + end + y = self.y + v_space + case align_items + when :center + (max_component_height - component.height) / 2.0 + when :bottom + max_component_height - component.height + else + 0 + end + if component.position == :absolute + component.move(self.x, self.y, self) + else + component.move(x, y, self) + end + h_space + }) + v_space + max_component_height + end + end + private :flow_move + + def row_injection(&with) + h_margin = padding_left + -> width, component do + h_space = [h_margin, component.margin_left].max + width + h_space = with.call(component, h_space) if with + next width if component.position == :absolute + h_margin = component.margin_right + h_space + component.width + end + end + private :row_injection + + def components_overflow? + h_margin = padding_top + width = 0 + max_width = @content_width + force_break = false + -> component do + next false if component.position == :absolute + h_space = [h_margin, component.margin_left].max + component.width + if force_break + force_break = component.break_after? + width = h_space + h_margin = padding_left + next true + else + force_break = component.break_after? + end + expected_width = width + component.layout_width + padding_left + padding_right + if width > 0 and expected_width > max_width + width = h_space + h_margin = padding_left + true + else + width += h_space + h_margin = component.margin_right + false + end + end + end + private :components_overflow? + + def vertical_box_resize + v_margin = padding_top + @content_height = components.inject(0) {|height, component| + component.resize(self) + next height if component.position == :absolute + v_space = [v_margin, component.margin_top].max + height + v_margin = component.margin_bottom + v_space + component.height + } + [v_margin, padding_bottom].max + component = components.max_by(&:layout_width) + if component + @content_width = component.width + + [component.margin_left, padding_left].max + + [component.margin_right, padding_right].max + end + end + private :vertical_box_resize + + def vertical_box_move + v_margin = padding_top + components.inject(0) do |height, component| + h_space = [padding_left, component.margin_left].max + v_space = [v_margin, component.margin_top].max + height + x = self.x + h_space + case justify_content + when :center + (component.inner_width(self) - component.width) / 2 + when :right + component.inner_width(self) - component.width + else + 0 + end + y = self.y + v_space + case align_items + when :space_between + if @height and components.size > 1 + v_space += (@height - @content_height) / (components.size - 1) + end + 0 + when :center + @height ? (@height - @content_height) / 2 : 0 + when :bottom + @height ? @height - @content_height : 0 + else + 0 + end + if component.position == :absolute + component.move(self.x, self.y, self) + else + component.move(x, y, self) + end + next height if component.position == :absolute + v_margin = component.margin_bottom + v_space + component.height + end + end + private :vertical_box_move + + def horizontal_box_resize + h_margin = padding_left + @content_width = components.inject(0) {|width, component| + component.resize(self) + next width if component.position == :absolute + h_space = [h_margin, component.margin_left].max + width + h_margin = component.margin_right + h_space + component.width + } + [h_margin, padding_right].max + component = components.max_by(&:layout_height) + if component + @content_height = component.height + + [component.margin_top, padding_top].max + + [component.margin_bottom, padding_bottom].max + end + end + private :horizontal_box_resize + + def horizontal_box_move + h_margin = padding_left + components.inject(0) do |width, component| + h_space = [h_margin, component.margin_left].max + width + v_space = [padding_top, component.margin_top].max + x = self.x + h_space + case justify_content + when :space_between + if @width and components.size > 1 + h_space += (@width - @content_width) / (components.size - 1) + end + 0 + when :center + @width ? (@width - @content_width) / 2 : 0 + when :right + @width ? @width - @content_width : 0 + else + 0 + end + y = self.y + v_space + case align_items + when :center + (component.inner_height(self) - component.height) / 2 + when :bottom + component.inner_height(self) - component.height + else + 0 + end + if component.position == :absolute + component.move(self.x, self.y, self) + else + component.move(x, y, self) + end + next width if component.position == :absolute + h_margin = component.margin_right + h_space + component.width + end + end + private :horizontal_box_move + + end + end end \ No newline at end of file diff --git a/lib/quincite/core/color.rb b/lib/quincite/core/color.rb index c0170b6..ebf3c3a 100644 --- a/lib/quincite/core/color.rb +++ b/lib/quincite/core/color.rb @@ -1,61 +1,61 @@ -module Quincite - - module UI - - class Color - - attr_accessor :red, :green, :blue, :alpha - - def initialize(rgb:, alpha: 255) - @red, @green, @blue = *rgb - @alpha = alpha - end - - def self.from_array(color) - case color.size - when 3 - self.new(rgb: color) - when 4 - self.new(rgb: color.take(3), alpha: color.last) - else - nil - end - end - - def self.from_hex(color) - sefl.new(rgb: [ - color >> 16 & 0xff, - color >> 8 & 0xff, - color & 0xff - ]) - end - - def self.from_hexstring(color) - sefl.new(rgb: [ - color[1..2].hex, - color[3..4].hex, - color[5..6].hex - ]) - end - - def self.[](*rgba) - self.from_array(rgba) - end - - end - - def Color(color) - case color - when Array - Color.from_array(color) - when Fixnum - Color.from_hex(color) - when /^#[0-9a-fA-F]{6}$/ - Color.from_hexstring(color) - else - nil - end - end - - end -end +module Quincite + + module UI + + class Color + + attr_accessor :red, :green, :blue, :alpha + + def initialize(rgb:, alpha: 255) + @red, @green, @blue = *rgb + @alpha = alpha + end + + def self.from_array(color) + case color.size + when 3 + self.new(rgb: color) + when 4 + self.new(rgb: color.take(3), alpha: color.last) + else + nil + end + end + + def self.from_hex(color) + self.new(rgb: [ + color >> 16 & 0xff, + color >> 8 & 0xff, + color & 0xff + ]) + end + + def self.from_hexstring(color) + sefl.new(rgb: [ + color[1..2].hex, + color[3..4].hex, + color[5..6].hex + ]) + end + + def self.[](*rgba) + self.from_array(rgba) + end + + end + + def self.Color(color) + case color + when Array + Color.from_array(color) + when Fixnum + Color.from_hex(color) + when /^#[0-9a-fA-F]{6}$/ + Color.from_hexstring(color) + else + nil + end + end + + end +end diff --git a/lib/quincite/core/dsl.rb b/lib/quincite/core/dsl.rb index 0f50744..39ddf12 100644 --- a/lib/quincite/core/dsl.rb +++ b/lib/quincite/core/dsl.rb @@ -1,129 +1,129 @@ -require_relative 'anonymous_proxy' - -module Quincite - - module UI - - extend AnonymousProxy - - anon_proxy :gateway do - - def method_missing(name, *args, &proc) - if proc - UI.resolve_method(name, *args, &proc) - else - UI.resolve_method(name, *args) - end - end - - def respond_to?(name) - UI.worker.acceptable?(name) - end - - end - - anon_proxy :worker, Array do - - def transfer(name, *args) - if block_given? - last.__send__(name, *args, &proc) - else - last.__send__(name, *args) - end - end - - def acceptable?(name) - last.respond_to?(name) - end - - def run_with_stack(o) - push o - yield - pop - end - - end - - @namespace = self - - def self.namespace=(namespace) - @namespace = namespace - end - - def self.namespace - @namespace - end - - def self.resolve_const(name) - build_component(name) - end - - def self.resolve_method(name, *args) - if name.match(/^[A-Z]/) - if block_given? - build_component(name, *args) { gateway.instance_eval(&proc) } - else - build_component(name, *args) - end - else - args = [*args, proc] if block_given? - component_style_set(name, *args) - end - end - - def self.new_component(name, *args) - namespace.const_get(name).new(*args) - end - - def self.build_component(name, *args) - if block_given? - component = worker.run_with_stack(new_component(name, *args), &proc) - else - component = new_component(name, *args) - end - if worker.empty? - component - else - worker.transfer(:add, component) - end - end - - def self.component_style_set(name, *args) - if (worker.acceptable?(:style_include?) and - worker.transfer(:style_include?, name)) - worker.transfer(:style_set, name, *args) - elsif worker.acceptable?(:"#{name}=") - worker.transfer(:"#{name}=", *args) - else - raise unless worker.acceptable?(name) - worker.transfer(name, *args) - end - end - - def self.build(container, &proc) - container = Class.new { include container } if container.class == Module - setup_build(proc) - worker.run_with_stack(container.new){ - gateway.instance_eval(&proc) - }.tap { cleanup_build(proc) } - end - - def self.setup_build(proc) proc.binding.eval <<-EOD end - class << self.class - alias __const_missing__ const_missing if defined? const_missing - def const_missing(name) Quincite::UI.resolve_const(name) end - end - EOD - - def self.cleanup_build(proc) proc.binding.eval <<-EOD end - class << self.class - remove_method :const_missing - if defined? __const_missing__ - alias const_missing __const_missing__ - remove_method :__const_missing__ - end - end - EOD - - end -end +require_relative 'anonymous_proxy' + +module Quincite + + module UI + + extend AnonymousProxy + + anon_proxy :gateway do + + def method_missing(name, *args, &proc) + if proc + UI.resolve_method(name, *args, &proc) + else + UI.resolve_method(name, *args) + end + end + + def respond_to?(name) + UI.worker.acceptable?(name) + end + + end + + anon_proxy :worker, Array do + + def transfer(name, *args) + if block_given? + last.__send__(name, *args, &proc) + else + last.__send__(name, *args) + end + end + + def acceptable?(name) + last.respond_to?(name) + end + + def run_with_stack(o) + push o + yield + pop + end + + end + + @namespace = self + + def self.namespace=(namespace) + @namespace = namespace + end + + def self.namespace + @namespace + end + + def self.resolve_const(name) + build_component(name) + end + + def self.resolve_method(name, *args) + if name.match(/^[A-Z]/) + if block_given? + build_component(name, *args) { gateway.instance_eval(&proc) } + else + build_component(name, *args) + end + else + args = [*args, proc] if block_given? + component_style_set(name, *args) + end + end + + def self.new_component(name, *args) + namespace.const_get(name).new(*args) + end + + def self.build_component(name, *args) + if block_given? + component = worker.run_with_stack(new_component(name, *args), &proc) + else + component = new_component(name, *args) + end + if worker.empty? + component + else + worker.transfer(:add, component) + end + end + + def self.component_style_set(name, *args) + if (worker.acceptable?(:style_include?) and + worker.transfer(:style_include?, name)) + worker.transfer(:style_set, name, *args) + elsif worker.acceptable?(:"#{name}=") + worker.transfer(:"#{name}=", *args) + else + raise unless worker.acceptable?(name) + worker.transfer(name, *args) + end + end + + def self.build(container, &proc) + container = Class.new { include container } if container.class == Module + setup_build(proc) + worker.run_with_stack(container.new){ + gateway.instance_eval(&proc) + }.tap { cleanup_build(proc) } + end + + def self.setup_build(proc) proc.binding.eval <<-EOD end + class << self.class + alias __const_missing__ const_missing if defined? const_missing + def const_missing(name) Quincite::UI.resolve_const(name) end + end + EOD + + def self.cleanup_build(proc) proc.binding.eval <<-EOD end + class << self.class + remove_method :const_missing + if defined? __const_missing__ + alias const_missing __const_missing__ + remove_method :__const_missing__ + end + end + EOD + + end +end diff --git a/lib/quincite/core/style.rb b/lib/quincite/core/style.rb index d3665d0..ecde14f 100644 --- a/lib/quincite/core/style.rb +++ b/lib/quincite/core/style.rb @@ -22,11 +22,13 @@ class Style def_delegator :@bg, :color=, :bg_color= def_delegator :@bg, :image, :bg_image def_delegator :@bg, :image=, :bg_image= + def_delegator :@bg, :bg= def_delegator :@border, :width, :border_width def_delegator :@border, :width=, :border_width= def_delegator :@border, :color, :border_color def_delegator :@border, :color=, :border_color= + def_delegator :@border, :border= def initialize @position = :relative @@ -136,7 +138,7 @@ def bg=(bg) case bg when Hash @image = bg[:image] - @color = Color(bg[:color]) || Color[255, 255, 255, 255] + @color = UI.Color(bg[:color]) || Color[255, 255, 255, 255] else @image = nil @color = nil @@ -158,7 +160,7 @@ def border=(border) case border when Hash @width = border[:width] || 1 - @color = Color(border[:color]) || Color[255, 255, 255, 255] + @color = UI.Color(border[:color]) || Color[255, 255, 255, 255] else @width = nil @color = nil