From 853470fca37fc12fd29081d92258bbe69f2933a4 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 23 Apr 2012 23:48:50 -0500 Subject: [PATCH 01/23] Added stroke defaults, callback spec --- lib/shoes/common/paint.rb | 1 + lib/shoes/common/style.rb | 1 + lib/shoes/element_methods.rb | 9 +++++++ lib/shoes/line.rb | 2 +- lib/shoes/oval.rb | 2 +- lib/shoes/shape.rb | 2 +- lib/swt_shoes/line.rb | 2 ++ lib/swt_shoes/oval.rb | 1 + spec/shoes/element_methods_spec.rb | 25 +++++++++++++++++- spec/shoes/line_spec.rb | 5 ++++ spec/shoes/oval_spec.rb | 5 ++++ .../shared_element_method_spec.rb | 5 ++++ spec/swt_shoes/line_spec.rb | 1 + spec/swt_shoes/shared_examples/style_spec.rb | 26 +++++++++++++++++++ spec/swt_shoes/spec_helper.rb | 3 +++ 15 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 spec/swt_shoes/shared_examples/style_spec.rb diff --git a/lib/shoes/common/paint.rb b/lib/shoes/common/paint.rb index 91ac5a2b..cbf2835d 100644 --- a/lib/shoes/common/paint.rb +++ b/lib/shoes/common/paint.rb @@ -1,6 +1,7 @@ module Shoes module Common module Paint + DEFAULTS = {:stroke => Shoes::COLORS[:black]} def stroke @style[:stroke] end diff --git a/lib/shoes/common/style.rb b/lib/shoes/common/style.rb index ec28cef4..861b6cc0 100644 --- a/lib/shoes/common/style.rb +++ b/lib/shoes/common/style.rb @@ -6,6 +6,7 @@ module Common # # @style module Style + PAINT_DEFAULTS = {:stroke => Shoes::COLORS[:black]} def style(new_styles = {}) @style.merge! new_styles end diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 06a85473..960dc650 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -111,6 +111,15 @@ def strokewidth(width) @style[:strokewidth] = width end + # Sets the current fill color + # + # Arguments + # + # color - a Shoes::Color + def fill(color) + @style[:fill] = color + end + # Adds style, or just returns current style if no argument # # Returns the updated style diff --git a/lib/shoes/line.rb b/lib/shoes/line.rb index b1926009..bc03bddd 100644 --- a/lib/shoes/line.rb +++ b/lib/shoes/line.rb @@ -14,7 +14,7 @@ def initialize(x1, y1, x2, y2, opts = {}) @width = (x1 - x2).abs @height = (y1 - y2).abs - @style = opts + @style = Shoes::Common::Paint::DEFAULTS.merge(opts) # GUI @gui_opts = @style.delete(:gui) diff --git a/lib/shoes/oval.rb b/lib/shoes/oval.rb index 143b35ed..958c9ddf 100644 --- a/lib/shoes/oval.rb +++ b/lib/shoes/oval.rb @@ -17,7 +17,7 @@ def initialize(*opts) when 3; @style[:left], @style[:top], @style[:radius] = opts else @style[:left], @style[:top], @style[:width], @style[:height] = opts end - @style = defaults.merge(@style) + @style = Shoes::Common::Paint::DEFAULTS.merge(defaults).merge(@style) @left = @style[:left] @top = @style[:top] @width = @style[:width] diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index 125e56c5..954aa782 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -20,7 +20,7 @@ class Shape # Implementation frameworks should pass in any required arguments # through the +opts+ hash. def initialize(opts = {}, blk = nil) - @style = opts + @style = Shoes::Common::Paint::DEFAULTS.merge(opts) @blk = blk diff --git a/lib/swt_shoes/line.rb b/lib/swt_shoes/line.rb index 80c495cc..4ac55482 100644 --- a/lib/swt_shoes/line.rb +++ b/lib/swt_shoes/line.rb @@ -1,6 +1,7 @@ module SwtShoes module Line attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback def gui_init # @gui_opts must be provided if this shape is responsible for @@ -11,6 +12,7 @@ def gui_init default_paint_callback = lambda do |event| gc = event.gc gc.set_antialias Swt::SWT::ON + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_line(@left, @top, right, bottom) end diff --git a/lib/swt_shoes/oval.rb b/lib/swt_shoes/oval.rb index fe0bcc9c..db47196b 100644 --- a/lib/swt_shoes/oval.rb +++ b/lib/swt_shoes/oval.rb @@ -13,6 +13,7 @@ def gui_init gc = event.gc gc.set_antialias Swt::SWT::ON gc.set_line_width self.style[:strokewidth] + gc.set_background(self.style[:fill].to_native) gc.draw_oval(@left, @top, @width, @height) end @gui_container.add_paint_listener(@gui_paint_callback) diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 0ec1c5e1..f21b327a 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -1,4 +1,5 @@ require_relative 'spec_helper' +require "shoes/color" require 'shoes/element_methods' require 'shoes/configuration' @@ -81,7 +82,6 @@ def initialize end describe "stroke" do - require "shoes/color" # Need the colors! let(:app) { ElementMethodsShoeLaces.new } let(:color) { Shoes::COLORS[:tomato] } @@ -126,6 +126,29 @@ def initialize end end + describe "fill" do + let(:app) { ElementMethodsShoeLaces.new } + let(:color) { Shoes::COLORS[:tomato] } + + specify "returns a color" do + app.fill(color).class.should eq(Shoes::Color) + end + + # This works differently on the app than on a normal element + specify "sets on receiver" do + app.fill color + app.style[:fill].should eq(color) + end + + specify "applies to subsequently created objects" do + app.fill color + Shoes::Oval.should_receive(:new).with do |*args| + style = args.pop + style[:fill].should eq(color) + end + app.oval(10, 10, 100, 100) + end + end #it "Should return 0 for left for button_one" do # @gui.elements['button_one'].left.should be 0 #end diff --git a/spec/shoes/line_spec.rb b/spec/shoes/line_spec.rb index 6cd430b3..5662038a 100644 --- a/spec/shoes/line_spec.rb +++ b/spec/shoes/line_spec.rb @@ -3,6 +3,11 @@ require 'white_shoes' describe Shoes::Line do + describe "basic" do + subject { Shoes::Line.new(20, 23, 300, 430) } + it_behaves_like "object with stroke" + end + shared_examples_for "basic line" do it { should be_kind_of(Shoes::Line) } its(:top) { should eq(15) } diff --git a/spec/shoes/oval_spec.rb b/spec/shoes/oval_spec.rb index 04c2dfae..7f22de33 100644 --- a/spec/shoes/oval_spec.rb +++ b/spec/shoes/oval_spec.rb @@ -3,6 +3,11 @@ require 'white_shoes' describe Shoes::Oval do + describe "basic" do + subject { Shoes::Oval.new(20, 30, 100, 200) } + it_behaves_like "object with stroke" + end + context "(eccentric)" do subject { Shoes::Oval.new(20, 30, 100, 200) } diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb index 399964e8..c7c9d986 100644 --- a/spec/shoes/shared_examples/shared_element_method_spec.rb +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -13,6 +13,11 @@ subject.stroke.should eq(color) subject.style[:stroke].should eq(color) end + + # Be sure the subject does *not* have the stroke set previously + specify "defaults to black" do + subject.stroke.should eq(Shoes::COLORS[:black]) + end end diff --git a/spec/swt_shoes/line_spec.rb b/spec/swt_shoes/line_spec.rb index e0a418bb..32125289 100644 --- a/spec/swt_shoes/line_spec.rb +++ b/spec/swt_shoes/line_spec.rb @@ -28,4 +28,5 @@ end it_behaves_like "paintable" + it_behaves_like "Swt object with stroke" end diff --git a/spec/swt_shoes/shared_examples/style_spec.rb b/spec/swt_shoes/shared_examples/style_spec.rb new file mode 100644 index 00000000..82d51f45 --- /dev/null +++ b/spec/swt_shoes/shared_examples/style_spec.rb @@ -0,0 +1,26 @@ +shared_examples_for "Swt object with stroke" do + describe "paint callback" do + let(:event) { double("event") } + let(:gc) { double("gc").as_null_object } + + before :each do + event.stub(:gc) { gc } + gui_container.should_receive(:add_paint_listener) + end + + specify "sets stroke color" do + gc.should_receive(:set_foreground).with(subject.stroke.to_native) + subject.gui_paint_callback.call(event) + end + + specify "sets antialias" do + gc.should_receive(:set_antialias).with(Swt::SWT::ON) + subject.gui_paint_callback.call(event) + end + + specify "sets strokewidth" do + gc.should_receive(:set_line_width).with(subject.style[:strokewidth]) + subject.gui_paint_callback.call(event) + end + end +end diff --git a/spec/swt_shoes/spec_helper.rb b/spec/swt_shoes/spec_helper.rb index 1e91dd31..b9431cab 100644 --- a/spec/swt_shoes/spec_helper.rb +++ b/spec/swt_shoes/spec_helper.rb @@ -1,2 +1,5 @@ require "swt_shoes" Shoes.configuration.framework = 'swt_shoes' + +shared_examples = File.join(File.dirname(__FILE__), 'shared_examples', '**/*.rb') +Dir[shared_examples].each { |f| require f } From 7f420d1429eccd6aab78f3f75b44337f5d52a9ae Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Tue, 24 Apr 2012 00:29:24 -0500 Subject: [PATCH 02/23] Added fill for oval --- lib/shoes/common/paint.rb | 14 +++++++++++- lib/shoes/common/style.rb | 1 - lib/swt_shoes/oval.rb | 5 ++++- spec/shoes/element_methods_spec.rb | 4 ++-- spec/shoes/oval_spec.rb | 1 + .../shared_element_method_spec.rb | 22 +++++++++++++++++-- spec/swt_shoes/oval_spec.rb | 13 +++++++++++ spec/swt_shoes/shared_examples/style_spec.rb | 17 ++++++++++++++ 8 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 spec/swt_shoes/oval_spec.rb diff --git a/lib/shoes/common/paint.rb b/lib/shoes/common/paint.rb index cbf2835d..68055fe6 100644 --- a/lib/shoes/common/paint.rb +++ b/lib/shoes/common/paint.rb @@ -1,7 +1,11 @@ module Shoes module Common module Paint - DEFAULTS = {:stroke => Shoes::COLORS[:black]} + DEFAULTS = { + :stroke => Shoes::COLORS[:black], + :fill => Shoes::COLORS[:black] + } + def stroke @style[:stroke] end @@ -9,6 +13,14 @@ def stroke def stroke=(color) @style[:stroke] = color end + + def fill + @style[:fill] + end + + def fill=(color) + @style[:fill] = color + end end end end diff --git a/lib/shoes/common/style.rb b/lib/shoes/common/style.rb index 861b6cc0..ec28cef4 100644 --- a/lib/shoes/common/style.rb +++ b/lib/shoes/common/style.rb @@ -6,7 +6,6 @@ module Common # # @style module Style - PAINT_DEFAULTS = {:stroke => Shoes::COLORS[:black]} def style(new_styles = {}) @style.merge! new_styles end diff --git a/lib/swt_shoes/oval.rb b/lib/swt_shoes/oval.rb index db47196b..6ab26fa3 100644 --- a/lib/swt_shoes/oval.rb +++ b/lib/swt_shoes/oval.rb @@ -1,6 +1,7 @@ module SwtShoes module Oval attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback # FIXME: This (mostly) duplicates SwtShoes::Line#gui_init def gui_init @@ -12,8 +13,10 @@ def gui_init @gui_paint_callback = lambda do |event| gc = event.gc gc.set_antialias Swt::SWT::ON + gc.set_background self.fill.to_native + gc.fill_oval(@left, @top, @width, @height) + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] - gc.set_background(self.style[:fill].to_native) gc.draw_oval(@left, @top, @width, @height) end @gui_container.add_paint_listener(@gui_paint_callback) diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index f21b327a..48c1c06d 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -83,7 +83,7 @@ def initialize describe "stroke" do let(:app) { ElementMethodsShoeLaces.new } - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do app.stroke(color).class.should eq(Shoes::Color) @@ -128,7 +128,7 @@ def initialize describe "fill" do let(:app) { ElementMethodsShoeLaces.new } - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do app.fill(color).class.should eq(Shoes::Color) diff --git a/spec/shoes/oval_spec.rb b/spec/shoes/oval_spec.rb index 7f22de33..3c728879 100644 --- a/spec/shoes/oval_spec.rb +++ b/spec/shoes/oval_spec.rb @@ -6,6 +6,7 @@ describe "basic" do subject { Shoes::Oval.new(20, 30, 100, 200) } it_behaves_like "object with stroke" + it_behaves_like "object with fill" end context "(eccentric)" do diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb index c7c9d986..983f6dfd 100644 --- a/spec/shoes/shared_examples/shared_element_method_spec.rb +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -1,7 +1,7 @@ require 'shoes/color' shared_examples_for "object with stroke" do - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do c = subject.stroke = color @@ -16,8 +16,26 @@ # Be sure the subject does *not* have the stroke set previously specify "defaults to black" do - subject.stroke.should eq(Shoes::COLORS[:black]) + subject.stroke.should eq(Shoes::COLORS.fetch :black) end end +shared_examples_for "object with fill" do + let(:color) { Shoes::COLORS.fetch :honeydew } + specify "returns a color" do + c = subject.fill = color + c.class.should eq(Shoes::Color) + end + + specify "sets on receiver" do + subject.fill = color + subject.fill.should eq(color) + subject.style[:fill].should eq(color) + end + + # Be sure the subject does *not* have the stroke set previously + specify "defaults to black" do + subject.fill.should eq(Shoes::COLORS.fetch :black) + end +end diff --git a/spec/swt_shoes/oval_spec.rb b/spec/swt_shoes/oval_spec.rb new file mode 100644 index 00000000..9b840ba6 --- /dev/null +++ b/spec/swt_shoes/oval_spec.rb @@ -0,0 +1,13 @@ +describe SwtShoes::Oval do + let(:gui_container) { double("gui container") } + let(:opts) { {:gui => {:container => gui_container}} } + + subject { + Shoes::Oval.new(10, 15, 100, opts) + } + + it_behaves_like "paintable" + it_behaves_like "Swt object with stroke" + it_behaves_like "Swt object with fill" +end + diff --git a/spec/swt_shoes/shared_examples/style_spec.rb b/spec/swt_shoes/shared_examples/style_spec.rb index 82d51f45..45624e78 100644 --- a/spec/swt_shoes/shared_examples/style_spec.rb +++ b/spec/swt_shoes/shared_examples/style_spec.rb @@ -24,3 +24,20 @@ end end end + +shared_examples_for "Swt object with fill" do + describe "paint callback" do + let(:event) { double("event") } + let(:gc) { double("gc").as_null_object } + + before :each do + event.stub(:gc) { gc } + gui_container.should_receive(:add_paint_listener) + end + + specify "sets fill color" do + gc.should_receive(:set_background).with(subject.fill.to_native) + subject.gui_paint_callback.call(event) + end + end +end From cc61fc9a15d8f50617e3f6cffc4a593d7778b630 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Tue, 24 Apr 2012 01:06:15 -0500 Subject: [PATCH 03/23] Added fill to shape --- lib/shoes/element_methods.rb | 4 ++-- lib/swt_shoes/shape.rb | 7 +++++-- spec/shoes/element_methods_spec.rb | 16 ++++++++++++---- spec/swt_shoes/shape_spec.rb | 25 +++++++++++++++++++------ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 960dc650..1da7fd5d 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -88,8 +88,8 @@ def oval(*opts) end # Creates a new Shoes::Shape object - def shape(style={}, &blk) - Shoes::Shape.new(style, blk) + def shape(shape_style={}, &blk) + Shoes::Shape.new(style.merge(shape_style), blk) end # Creates a new Shoes::Color object diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 0b315d36..47666795 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -8,8 +8,8 @@ module SwtShoes # @opts - options # module Shape - attr_reader :gui_container - attr_reader :gui_element + attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback # The initialization hook for SwtShoes. # @@ -45,7 +45,10 @@ def gui_init @gui_element = @gui_opts[:element] || Swt::Path.new(Shoes.display) @gui_paint_callback = lambda do |event| gc = event.gc + gc.set_background self.fill.to_native + gc.fill_path(@gui_element) gc.set_antialias Swt::SWT::ON + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_path(@gui_element) end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 48c1c06d..09980bf1 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -52,14 +52,22 @@ def initialize end describe "shape" do - it "produces a Shoes::Shape" do - shape = ElementMethodsShoeLaces.new.shape do + let(:app) { ElementMethodsShoeLaces.new } + subject { + app.shape { move_to 400, 300 line_to 400, 200 line_to 100, 100 line_to 400, 300 - end - shape.should be_an_instance_of(Shoes::Shape) + } + } + + it { should be_an_instance_of(Shoes::Shape) } + + it "receives style from app" do + green = Shoes::COLORS.fetch :green + app.style[:stroke] = green + subject.stroke.should eq(green) end end diff --git a/spec/swt_shoes/shape_spec.rb b/spec/swt_shoes/shape_spec.rb index e5080ab3..65a69c71 100644 --- a/spec/swt_shoes/shape_spec.rb +++ b/spec/swt_shoes/shape_spec.rb @@ -20,13 +20,9 @@ def initialize(opts = {}, blk = nil ) let(:args_with_element) { {container: gui_container, element: gui_element} } let(:args_without_element) { {container: gui_container} } - before :each do - gui_container.should_receive(:add_paint_listener) - end - shared_examples_for "Swt::Shape" do before :each do - gui_element.stub(:move_to) + gui_container.should_receive(:add_paint_listener) end it "uses Swt and not White Shoes" do @@ -43,7 +39,6 @@ def initialize(opts = {}, blk = nil ) subject { ShapeShoeLaces.new gui: args_with_element } it_behaves_like "Swt::Shape" - end context "with gui container only" do @@ -52,10 +47,28 @@ def initialize(opts = {}, blk = nil ) it_behaves_like "Swt::Shape" describe "gui_init" do + before :each do + gui_container.should_receive(:add_paint_listener) + end + it "should not set current point on gui element" do gui_element.should_not_receive(:move_to) subject end end end + + context "basic" do + subject { + Shoes::Shape.new(gui: args_without_element) { + move_to 150, 150 + line_to 300, 300 + line_to 0, 300 + line to 150, 350 + } + } + + it_behaves_like "Swt object with stroke" + it_behaves_like "Swt object with fill" + end end From a41cf320b5db97943b48816d3dabba94cc402eee Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 12:56:38 -0500 Subject: [PATCH 04/23] Refactored shoes specs --- lib/shoes/element_methods.rb | 12 +++++++----- spec/shoes/app_spec.rb | 6 +++--- spec/shoes/element_methods_spec.rb | 24 +++++++++++++++++------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index d3e891d7..7135dcbd 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -1,8 +1,10 @@ -#require 'animation' - -#require 'native' -#require 'button' -#require 'flow' +# FIXME: shoes/animation and shoes/sound require java. They shouldn't. +#require 'shoes/animation' +#require 'shoes/sound' +require 'shoes/button' +require 'shoes/color' +require 'shoes/flow' +require 'shoes/shape' module Shoes module ElementMethods diff --git a/spec/shoes/app_spec.rb b/spec/shoes/app_spec.rb index 02b9f402..05054d98 100644 --- a/spec/shoes/app_spec.rb +++ b/spec/shoes/app_spec.rb @@ -1,6 +1,6 @@ -require "spec_helper" - +require_relative './spec_helper' require 'white_shoes' +require 'shoes/app' describe Shoes::App do @@ -39,4 +39,4 @@ end -end \ No newline at end of file +end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index d920f194..21d089ba 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -1,4 +1,6 @@ -require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') +require_relative 'spec_helper' +require 'shoes/element_methods' +require 'shoes/configuration' describe "Basic Element Methods" do class ElementMethodsShoeLaces @@ -116,13 +118,21 @@ class ElementMethodsShoeLaces end describe "rgb" do - subject { ElementMethodsShoeLaces.new.rgb(100, 149, 237) } # cornflower + let(:red) { 100 } + let(:green) { 149 } + let(:blue) { 237 } + let(:alpha) { 133 } # cornflower + let(:app) { ElementMethodsShoeLaces.new } + + it "sends args to Shoes::Color" do + Shoes::Color.should_receive(:new).with(red, green, blue, alpha) + app.rgb(red, green, blue, alpha) + end - its(:class) { should eq(Shoes::Color) } - its(:red) { should eq(100) } - its(:green) { should eq(149) } - its(:blue) { should eq(237) } - its(:alpha) { should eq(Shoes::Color::OPAQUE) } + it "defaults to opaque" do + Shoes::Color.should_receive(:new).with(red, green, blue, Shoes::Color::OPAQUE) + app.rgb(red, green, blue) + end end From 958c3a22b39ed485021913c614c42ae339eac233 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 12:54:16 -0500 Subject: [PATCH 05/23] Added style method to app --- lib/shoes/app.rb | 8 +++++++- lib/shoes/element_methods.rb | 16 +++++++++++++++ spec/shoes/app_spec.rb | 11 ++++++++++ spec/shoes/element_methods_spec.rb | 20 +++++++++++++++++++ .../shared_element_method_spec.rb | 12 +++++++++++ spec/shoes/shared_examples/style_spec.rb | 9 +++++++++ spec/shoes/spec_helper.rb | 2 ++ 7 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 spec/shoes/shared_examples/shared_element_method_spec.rb create mode 100644 spec/shoes/shared_examples/style_spec.rb create mode 100644 spec/shoes/spec_helper.rb diff --git a/lib/shoes/app.rb b/lib/shoes/app.rb index d86053b0..45182dee 100644 --- a/lib/shoes/app.rb +++ b/lib/shoes/app.rb @@ -32,6 +32,8 @@ def initialize(opts={}, &blk) self.opts = opts + @style = {} + gui_init instance_eval &blk if blk @@ -40,6 +42,10 @@ def initialize(opts={}, &blk) end + def style(new_styles = {}) + @style.merge! new_styles + end + #import javax.swing.JPanel #import javax.swing.JFrame #import java.awt.Dimension @@ -134,4 +140,4 @@ def initialize(opts={}, &blk) # @current_panel = parent #end end -end \ No newline at end of file +end diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 7135dcbd..f2bd98af 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -7,6 +7,13 @@ require 'shoes/shape' module Shoes + # Methods for creating and manipulating Shoes elements + # + # Requirements + # + # Including classes must provide: + # + # @style - a hash of styles module ElementMethods #def stack(opts={}, &blk) @@ -102,5 +109,14 @@ def oval(*opts) def rgb(red, green, blue, alpha = Shoes::Color::OPAQUE) Shoes::Color.new(red, green, blue, alpha) end + + # Sets the current stroke color + # + # Arguments + # + # color - a Shoes::Color + def stroke(color) + @style[:stroke] = color + end end end diff --git a/spec/shoes/app_spec.rb b/spec/shoes/app_spec.rb index 05054d98..12faa475 100644 --- a/spec/shoes/app_spec.rb +++ b/spec/shoes/app_spec.rb @@ -36,7 +36,18 @@ app.title.should == "Shoes::App Spec" end + + it "initializes style hash" do + style = Shoes::App.new.style + style.class.should eq(Hash) + style.should be_empty + end end + describe "style" do + subject { Shoes::App.new } + it_behaves_like "object with style" + it_behaves_like "object with stroke" + end end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 21d089ba..65c5e0fa 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -135,6 +135,26 @@ class ElementMethodsShoeLaces end end + describe "stroke" do + require "shoes/color" # Need the colors! + let(:app) { + Object.new.tap do |app| + app.extend Shoes::ElementMethods + app.singleton_class.class_eval "attr_accessor :style" + app.style = {} + end + } + + subject { app } + + it_behaves_like "object with stroke" + + specify "applies to subsequently created objects" do + pending "oval" + app.stroke Shoes::COLORS[:tomato] + app.oval(10, 10, 100, 100)#.style[:stroke].should eq(Shoes::COLORS[:tomato]) + end + end #it "Should return 0 for left for button_one" do # @gui.elements['button_one'].left.should be 0 diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb new file mode 100644 index 00000000..0709f613 --- /dev/null +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -0,0 +1,12 @@ +shared_examples_for "object with stroke" do + specify "returns a color" do + subject.stroke(Shoes::COLORS[:tomato]).class.should eq(Shoes::Color) + end + + specify "sets on receiver" do + subject.stroke Shoes::COLORS[:tomato] + subject.style[:stroke].should eq(Shoes::COLORS[:tomato]) + end +end + + diff --git a/spec/shoes/shared_examples/style_spec.rb b/spec/shoes/shared_examples/style_spec.rb new file mode 100644 index 00000000..f9991a63 --- /dev/null +++ b/spec/shoes/shared_examples/style_spec.rb @@ -0,0 +1,9 @@ +shared_examples_for "object with style" do + it "merges new styles" do + old_style = subject.style + subject.style :left => 100 + subject.style :top => 50 + subject.style.should eq(old_style.merge(:left => 100, :top => 50)) + end +end + diff --git a/spec/shoes/spec_helper.rb b/spec/shoes/spec_helper.rb new file mode 100644 index 00000000..45acf781 --- /dev/null +++ b/spec/shoes/spec_helper.rb @@ -0,0 +1,2 @@ +shared_examples = File.join(File.dirname(__FILE__), 'shared_examples', '**/*.rb') +Dir[shared_examples].each { |f| require f } From 287c025608402e6743ce8472686ef56ae593cb4a Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 13:12:34 -0500 Subject: [PATCH 06/23] Added stroke spec for oval --- lib/shoes/element_methods.rb | 1 + spec/shoes/element_methods_spec.rb | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index f2bd98af..eb33779b 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -102,6 +102,7 @@ def oval(*opts) args[:left] -= args[:width] / 2 args[:top] -= args[:height] / 2 end + args[:stroke] ||= @style[:stroke] Shoes::Shape.new args end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 65c5e0fa..fca340f6 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -5,7 +5,11 @@ describe "Basic Element Methods" do class ElementMethodsShoeLaces attr_accessor :gui_container + attr_reader :style include Shoes::ElementMethods + def initialize + @style = {} + end end Shoes.configuration.framework = 'white_shoes' @@ -150,8 +154,11 @@ class ElementMethodsShoeLaces it_behaves_like "object with stroke" specify "applies to subsequently created objects" do - pending "oval" app.stroke Shoes::COLORS[:tomato] + Shoes::Shape.should_receive(:new).with do |*args| + style = args.pop + style[:stroke].should eq(Shoes::COLORS[:tomato]) + end app.oval(10, 10, 100, 100)#.style[:stroke].should eq(Shoes::COLORS[:tomato]) end end From bbd1e8a07a165a522de61508a1a3bb952d9d897b Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 13:48:02 -0500 Subject: [PATCH 07/23] Added style and paint modules --- lib/shoes/common/paint.rb | 13 +++++++++++++ lib/shoes/common/style.rb | 9 +++++++++ lib/shoes/shape.rb | 16 ++++++++++------ spec/shoes/app_spec.rb | 1 - spec/shoes/element_methods_spec.rb | 15 +++++++++++---- spec/shoes/shape_spec.rb | 7 +++++++ .../shared_element_method_spec.rb | 10 +++++++--- 7 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 lib/shoes/common/paint.rb create mode 100644 lib/shoes/common/style.rb create mode 100644 spec/shoes/shape_spec.rb diff --git a/lib/shoes/common/paint.rb b/lib/shoes/common/paint.rb new file mode 100644 index 00000000..91ac5a2b --- /dev/null +++ b/lib/shoes/common/paint.rb @@ -0,0 +1,13 @@ +module Shoes + module Common + module Paint + def stroke + @style[:stroke] + end + + def stroke=(color) + @style[:stroke] = color + end + end + end +end diff --git a/lib/shoes/common/style.rb b/lib/shoes/common/style.rb new file mode 100644 index 00000000..2356f980 --- /dev/null +++ b/lib/shoes/common/style.rb @@ -0,0 +1,9 @@ +module Shoes + module Common + module Style + def style(new_styles = {}) + @style.merge! new_styles + end + end + end +end diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index fc7182e9..6f9348ea 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -1,9 +1,13 @@ require 'facets/hash' require 'shoes/common_methods' +require 'shoes/common/paint' +require 'shoes/common/style' module Shoes class Shape include Shoes::CommonMethods + include Shoes::Common::Paint + include Shoes::Common::Style attr_reader :blk attr_reader :x, :y @@ -15,15 +19,15 @@ class Shape # # opts['x'] - the initial x-position for drawing # opts['y'] - the initial y-position for drawing - def initialize(opts={}, blk = nil) - @opts = opts + def initialize(style={}, blk = nil) + @style = style @blk = blk - @left = @opts[:left] || 0 - @top = @opts[:top] || 0 - @width = @opts[:width] || 0 - @height = @opts[:height] || 0 + @left = @style[:left] || 0 + @top = @style[:top] || 0 + @width = @style[:width] || 0 + @height = @style[:height] || 0 # Initialize current point to (left, top) @x, @y = @left, @top diff --git a/spec/shoes/app_spec.rb b/spec/shoes/app_spec.rb index 12faa475..48fe48bf 100644 --- a/spec/shoes/app_spec.rb +++ b/spec/shoes/app_spec.rb @@ -47,7 +47,6 @@ describe "style" do subject { Shoes::App.new } it_behaves_like "object with style" - it_behaves_like "object with stroke" end end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index fca340f6..acbeb754 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -148,16 +148,23 @@ def initialize app.style = {} end } + let(:color) { Shoes::COLORS[:tomato] } - subject { app } + specify "returns a color" do + app.stroke(color).class.should eq(Shoes::Color) + end - it_behaves_like "object with stroke" + # This works differently on the app than on a normal element + specify "sets on receiver" do + app.stroke color + app.style[:stroke].should eq(color) + end specify "applies to subsequently created objects" do - app.stroke Shoes::COLORS[:tomato] + app.stroke color Shoes::Shape.should_receive(:new).with do |*args| style = args.pop - style[:stroke].should eq(Shoes::COLORS[:tomato]) + style[:stroke].should eq(color) end app.oval(10, 10, 100, 100)#.style[:stroke].should eq(Shoes::COLORS[:tomato]) end diff --git a/spec/shoes/shape_spec.rb b/spec/shoes/shape_spec.rb new file mode 100644 index 00000000..4eed40aa --- /dev/null +++ b/spec/shoes/shape_spec.rb @@ -0,0 +1,7 @@ +require_relative 'spec_helper' +require 'shoes/shape' + +describe Shoes::Shape do + it_behaves_like "object with stroke" + it_behaves_like "object with style" +end diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb index 0709f613..1d615dc2 100644 --- a/spec/shoes/shared_examples/shared_element_method_spec.rb +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -1,11 +1,15 @@ shared_examples_for "object with stroke" do + let(:color) { Shoes::COLORS[:tomato] } + specify "returns a color" do - subject.stroke(Shoes::COLORS[:tomato]).class.should eq(Shoes::Color) + c = subject.stroke = color + c.class.should eq(Shoes::Color) end specify "sets on receiver" do - subject.stroke Shoes::COLORS[:tomato] - subject.style[:stroke].should eq(Shoes::COLORS[:tomato]) + subject.stroke = color + subject.stroke.should eq(color) + subject.style[:stroke].should eq(color) end end From 98e94cc17dab177f0199894b01d5e4ebf5101336 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 14:15:22 -0500 Subject: [PATCH 08/23] WIP: Adding style to SWT::SHAPE --- lib/shoes/shape.rb | 5 +++-- lib/swt_shoes/shape.rb | 8 ++++---- spec/swt_shoes/element_methods_spec.rb | 3 +++ spec/swt_shoes/shape_spec.rb | 12 +++++++++--- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index 6f9348ea..5549c9f6 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -19,8 +19,9 @@ class Shape # # opts['x'] - the initial x-position for drawing # opts['y'] - the initial y-position for drawing - def initialize(style={}, blk = nil) - @style = style + def initialize(opts={}, blk = nil) + @gui_opts = opts.delete(:gui) || {} + @style = opts @blk = blk diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index e00bcbd2..24abfaab 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -36,13 +36,13 @@ module Shape # first is the Swt event that will trigger the callback. The second is # this shape. def gui_init - @gui_container = @opts[:gui][:container] - if @opts[:gui][:element] - @gui_element = @opts[:gui][:element] + @gui_container = @gui_opts[:container] + if @gui_opts[:element] + @gui_element = @gui_opts[:element] @gui_element.move_to(@x, @y) end paint_callback = lambda do |e| - @opts[:gui][:paint_callback].call(e, self) + @gui_opts[:paint_callback].call(e, self) end @gui_container.add_paint_listener(paint_callback) end diff --git a/spec/swt_shoes/element_methods_spec.rb b/spec/swt_shoes/element_methods_spec.rb index c0d0fe1e..d83a4ede 100644 --- a/spec/swt_shoes/element_methods_spec.rb +++ b/spec/swt_shoes/element_methods_spec.rb @@ -7,6 +7,9 @@ class ElementMethodsShoeLaces attr_accessor :gui_container include Shoes::ElementMethods include SwtShoes::ElementMethods + def initialize + @style = {} + end end Shoes.configuration.framework = 'swt_shoes' diff --git a/spec/swt_shoes/shape_spec.rb b/spec/swt_shoes/shape_spec.rb index df7a5ea8..0f9e19c1 100644 --- a/spec/swt_shoes/shape_spec.rb +++ b/spec/swt_shoes/shape_spec.rb @@ -9,16 +9,21 @@ class ShapeShoeLaces attr_reader :blk attr_reader :width, :height def initialize(opts = {}, blk = nil ) - @opts = opts + @gui_opts = opts.delete(:gui) + @style = opts gui_init end end - let(:gui_container) { double('gui_container', add_paint_listener: "Paint Listener") } + let(:gui_container) { double('gui_container') } let(:gui_element) { double('gui_element') } let(:args_with_element) { {container: gui_container, element: gui_element} } let(:args_without_element) { {container: gui_container} } + before :each do + gui_container.should_receive(:add_paint_listener) + end + shared_examples_for "Swt::Shape" do before :each do gui_element.stub(:move_to) @@ -40,7 +45,7 @@ def initialize(opts = {}, blk = nil ) it_behaves_like "Swt::Shape" describe "gui_init" do - it "should set current point on gui element" do + it "sets current point and registers paint listener" do gui_element.should_receive(:move_to) subject end @@ -55,6 +60,7 @@ def initialize(opts = {}, blk = nil ) describe "gui_init" do it "should not set current point on gui element" do gui_element.should_not_receive(:move_to) + subject end end end From a19b00d4c952caceae467ea23f324371bc02ed46 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 21:52:01 -0500 Subject: [PATCH 09/23] Added SwtShoes native color, oval stroke --- lib/shoes/app.rb | 4 ---- lib/shoes/element_methods.rb | 7 +++++++ lib/swt_shoes.rb | 18 +++++++++--------- lib/swt_shoes/color.rb | 13 +++++++++++++ lib/swt_shoes/element_methods.rb | 4 +++- lib/swt_shoes/shape.rb | 4 ++-- spec/swt_shoes/color_spec.rb | 11 +++++++++++ 7 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 lib/swt_shoes/color.rb create mode 100644 spec/swt_shoes/color_spec.rb diff --git a/lib/shoes/app.rb b/lib/shoes/app.rb index 45182dee..47f81122 100644 --- a/lib/shoes/app.rb +++ b/lib/shoes/app.rb @@ -42,10 +42,6 @@ def initialize(opts={}, &blk) end - def style(new_styles = {}) - @style.merge! new_styles - end - #import javax.swing.JPanel #import javax.swing.JFrame #import java.awt.Dimension diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index eb33779b..cad3132a 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -119,5 +119,12 @@ def rgb(red, green, blue, alpha = Shoes::Color::OPAQUE) def stroke(color) @style[:stroke] = color end + + # Adds style, or just returns current style if no argument + # + # Returns the updated style + def style(new_styles = {}) + @style.merge! new_styles + end end end diff --git a/lib/swt_shoes.rb b/lib/swt_shoes.rb index 9f0deddf..c7f1b559 100644 --- a/lib/swt_shoes.rb +++ b/lib/swt_shoes.rb @@ -16,21 +16,21 @@ def window(*a, &b) require 'swt_shoes/flow' require 'swt_shoes/button' require 'swt_shoes/shape' +require 'swt_shoes/color' module SwtShoes module Shoes + include Log4jruby::LoggerForClass + def self.app(opts={}, &blk) + Shoes::App.new(opts, &blk) + logger.debug "Exiting Shoes.app" + end - include Log4jruby::LoggerForClass - - def self.app(opts={}, &blk) - Shoes::App.new(opts, &blk) - logger.debug "Exiting Shoes.app" + def self.display + Swt::Widgets::Display.getCurrent + end end - - - end - end diff --git a/lib/swt_shoes/color.rb b/lib/swt_shoes/color.rb new file mode 100644 index 00000000..33f4b1a4 --- /dev/null +++ b/lib/swt_shoes/color.rb @@ -0,0 +1,13 @@ +module SwtShoes + module Color + def to_native + Swt::Graphics::Color.new(Shoes.display, @red, @green, @blue) + end + end +end + +module Shoes + class Color + include SwtShoes::Color + end +end diff --git a/lib/swt_shoes/element_methods.rb b/lib/swt_shoes/element_methods.rb index ed977bc0..2c46f962 100644 --- a/lib/swt_shoes/element_methods.rb +++ b/lib/swt_shoes/element_methods.rb @@ -54,7 +54,7 @@ module ElementMethods def line(x1, y1, x2, y2, opts={}) opts[:gui] = { container: self.gui_container, - element: Swt::Path.new(Swt::Widgets::Display.get_current), + element: Swt::Path.new(Shoes.display), paint_callback: lambda do |event, shape| #return if hidden? gc = event.gc @@ -68,6 +68,7 @@ def line(x1, y1, x2, y2, opts={}) def oval(*opts) args = opts.last.class == Hash ? opts.pop : {} + args = style.merge(args) args[:gui] = { container: self.gui_container, paint_callback: lambda do |event, shape| @@ -75,6 +76,7 @@ def oval(*opts) gc = event.gc gc.set_antialias Swt::SWT::ON gc.set_line_width 1 + gc.setForeground(shape.style[:stroke].to_native) gc.draw_oval(shape.left, shape.top, shape.width, shape.height) end } diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 24abfaab..5a422253 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -41,10 +41,10 @@ def gui_init @gui_element = @gui_opts[:element] @gui_element.move_to(@x, @y) end - paint_callback = lambda do |e| + @gui_paint_callback = lambda do |e| @gui_opts[:paint_callback].call(e, self) end - @gui_container.add_paint_listener(paint_callback) + @gui_container.add_paint_listener(@gui_paint_callback) end def line_to(x, y) diff --git a/spec/swt_shoes/color_spec.rb b/spec/swt_shoes/color_spec.rb new file mode 100644 index 00000000..c121a6f0 --- /dev/null +++ b/spec/swt_shoes/color_spec.rb @@ -0,0 +1,11 @@ +require 'swt_shoes/color' +require 'shoes/color' + +describe SwtShoes::Color do + subject { Shoes::COLORS[:salmon].to_native } + + its(:class) { should eq(Java::OrgEclipseSwtGraphics::Color) } + its(:red) { should eq(250) } + its(:green) { should eq(128) } + its(:blue) { should eq(114) } +end From 3443b4c39e7d95aa6d9cf540a16ee5584e2143a2 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 22:34:18 -0500 Subject: [PATCH 10/23] Added strokewidth to oval and line for Swt --- lib/shoes/element_methods.rb | 9 +++++++-- lib/swt_shoes/element_methods.rb | 9 +++++---- spec/shoes/element_methods_spec.rb | 31 ++++++++++++++++++++++-------- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index cad3132a..0ed72341 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -70,10 +70,9 @@ def sound(soundfile, opts = {}, &blk) # Draws a line from (x1,y1) to (x2,y2) # TODO: Probably don't need to use the full-on Swt::Path for this def line(x1, y1, x2, y2, opts={}) - args = {} + args = opts args[:left], end_x = x1 < x2 ? [x1, x2] : [x2, x1] args[:top], end_y = y1 < y2 ? [y1, y2] : [y2, y1] - args[:gui] = opts[:gui] path = lambda { line_to(end_x, end_y) } Shoes::Shape.new(args, path) end @@ -103,6 +102,7 @@ def oval(*opts) args[:top] -= args[:height] / 2 end args[:stroke] ||= @style[:stroke] + args[:strokewidth] ||= @style[:strokewidth] Shoes::Shape.new args end @@ -120,6 +120,11 @@ def stroke(color) @style[:stroke] = color end + # Sets the stroke width, in pixels + def strokewidth(width) + @style[:strokewidth] = width + end + # Adds style, or just returns current style if no argument # # Returns the updated style diff --git a/lib/swt_shoes/element_methods.rb b/lib/swt_shoes/element_methods.rb index 2c46f962..143953e5 100644 --- a/lib/swt_shoes/element_methods.rb +++ b/lib/swt_shoes/element_methods.rb @@ -52,18 +52,19 @@ module ElementMethods #end # def line(x1, y1, x2, y2, opts={}) - opts[:gui] = { + args = style.merge(opts) + args[:gui] = { container: self.gui_container, element: Swt::Path.new(Shoes.display), paint_callback: lambda do |event, shape| #return if hidden? gc = event.gc gc.set_antialias Swt::SWT::ON - gc.set_line_width 1 + gc.set_line_width shape.style[:strokewidth] gc.draw_path(shape.gui_element) end } - super(x1, y1, x2, y2, opts) + super(x1, y1, x2, y2, args) end def oval(*opts) @@ -75,7 +76,7 @@ def oval(*opts) #return if hidden? gc = event.gc gc.set_antialias Swt::SWT::ON - gc.set_line_width 1 + gc.set_line_width shape.style[:strokewidth] gc.setForeground(shape.style[:stroke].to_native) gc.draw_oval(shape.left, shape.top, shape.width, shape.height) end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index acbeb754..6eb120dc 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -141,13 +141,7 @@ def initialize describe "stroke" do require "shoes/color" # Need the colors! - let(:app) { - Object.new.tap do |app| - app.extend Shoes::ElementMethods - app.singleton_class.class_eval "attr_accessor :style" - app.style = {} - end - } + let(:app) { ElementMethodsShoeLaces.new } let(:color) { Shoes::COLORS[:tomato] } specify "returns a color" do @@ -166,7 +160,28 @@ def initialize style = args.pop style[:stroke].should eq(color) end - app.oval(10, 10, 100, 100)#.style[:stroke].should eq(Shoes::COLORS[:tomato]) + app.oval(10, 10, 100, 100) + end + end + + describe "strokewidth" do + let(:app) { ElementMethodsShoeLaces.new } + specify "returns a number" do + app.strokewidth(4).should eq(4) + end + + specify "sets on receiver" do + app.strokewidth 4 + app.style[:strokewidth].should eq(4) + end + + specify "applies to subsequently created objects" do + app.strokewidth 6 + Shoes::Shape.should_receive(:new).with do |*args| + style = args.pop + style[:strokewidth].should eq(6) + end + app.oval(10, 10, 100, 100) end end From a4bd706fab0e2aba4ee65ebc5333b5c0d0271e6c Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 23:39:12 -0500 Subject: [PATCH 11/23] Added app defaults for stroke and strokewidth --- lib/shoes/app.rb | 4 +++- lib/shoes/element_methods.rb | 4 ++-- lib/swt_shoes/element_methods.rb | 3 +-- spec/shoes/app_spec.rb | 35 +++++++++++++++++++++++++++++++- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/lib/shoes/app.rb b/lib/shoes/app.rb index 47f81122..ba6e9e8f 100644 --- a/lib/shoes/app.rb +++ b/lib/shoes/app.rb @@ -1,4 +1,5 @@ require 'shoes/element_methods' +require 'shoes/color' require 'facets/hash' def window(*a, &b) @@ -15,6 +16,7 @@ def self.app(opts={}, &blk) class App DEFAULTS = { 'width' => 800, 'height' => 600, 'title' => "Shoooes!"} + DEFAULT_STYLE = { :stroke => Shoes::COLORS[:black], :strokewidth => 1 } include Shoes::ElementMethods @@ -32,7 +34,7 @@ def initialize(opts={}, &blk) self.opts = opts - @style = {} + @style = DEFAULT_STYLE gui_init diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 0ed72341..5401aff1 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -70,7 +70,7 @@ def sound(soundfile, opts = {}, &blk) # Draws a line from (x1,y1) to (x2,y2) # TODO: Probably don't need to use the full-on Swt::Path for this def line(x1, y1, x2, y2, opts={}) - args = opts + args = style.merge(opts) args[:left], end_x = x1 < x2 ? [x1, x2] : [x2, x1] args[:top], end_y = y1 < y2 ? [y1, y2] : [y2, y1] path = lambda { line_to(end_x, end_y) } @@ -94,7 +94,7 @@ def oval(*opts) when 3; args[:left], args[:top], args[:radius] = opts else args[:left], args[:top], args[:width], args[:height] = opts end - args = defaults.merge(args) + args = defaults.merge(style).merge(args) args[:width] = args[:radius] * 2 if args[:width].zero? args[:height] = args[:width] if args[:height].zero? if args[:center] diff --git a/lib/swt_shoes/element_methods.rb b/lib/swt_shoes/element_methods.rb index 143953e5..dec1aa4e 100644 --- a/lib/swt_shoes/element_methods.rb +++ b/lib/swt_shoes/element_methods.rb @@ -52,7 +52,7 @@ module ElementMethods #end # def line(x1, y1, x2, y2, opts={}) - args = style.merge(opts) + args = opts args[:gui] = { container: self.gui_container, element: Swt::Path.new(Shoes.display), @@ -69,7 +69,6 @@ def line(x1, y1, x2, y2, opts={}) def oval(*opts) args = opts.last.class == Hash ? opts.pop : {} - args = style.merge(args) args[:gui] = { container: self.gui_container, paint_callback: lambda do |event, shape| diff --git a/spec/shoes/app_spec.rb b/spec/shoes/app_spec.rb index 48fe48bf..d149b987 100644 --- a/spec/shoes/app_spec.rb +++ b/spec/shoes/app_spec.rb @@ -40,13 +40,46 @@ it "initializes style hash" do style = Shoes::App.new.style style.class.should eq(Hash) - style.should be_empty end end + # This behavior is different from Red Shoes. Red Shoes doesn't expose + # the style hash on Shoes::App. describe "style" do subject { Shoes::App.new } it_behaves_like "object with style" end + describe "strokewidth" do + it "defaults to 1" do + subject.style[:strokewidth].should eq(1) + end + + it "passes default to objects" do + subject.line(0, 100, 100, 0).style[:strokewidth].should eq(1) + end + + it "passes new values to objects" do + subject.strokewidth 10 + subject.line(0, 100, 100, 0).style[:strokewidth].should eq(10) + end + end + + describe "stroke" do + let(:black) { Shoes::COLORS[:black] } + let(:goldenrod) { Shoes::COLORS[:goldenrod] } + it "defaults to black" do + subject.style[:stroke].should eq(black) + end + + it "passes default to objects" do + subject.oval(100, 100, 100).style[:stroke].should eq(black) + end + + it "passes new value to objects" do + subject.stroke goldenrod + subject.oval(100, 100, 100).style[:stroke].should eq(goldenrod) + end + end + end From 9be6d7771aa55d067cc63a9d511b727be86e5291 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 16 Apr 2012 23:40:15 -0500 Subject: [PATCH 12/23] Made rake spec tasks include opts in RSPEC_OPTS --- Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Rakefile b/Rakefile index a704dc4b..5add12b9 100644 --- a/Rakefile +++ b/Rakefile @@ -28,6 +28,7 @@ end def jruby_rspec(files, args) swt = args.delete(:swt) rspec_opts = spec_opts_from_args(args) + rspec_opts << " #{ENV['RSPEC_OPTS']}" jruby_run(rspec(files, rspec_opts), swt) From e77b488a49564dce69cd0c73b192631588dcc0bb Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Sat, 21 Apr 2012 08:08:00 -0500 Subject: [PATCH 13/23] Added Shape functionality, Line, Oval - refactored Line and Oval into their own classes - shape does move_to and line_to, but the groundwork is there for it to do all the rest --- lib/shoes.rb | 5 + lib/shoes/common/style.rb | 5 + lib/shoes/element_methods.rb | 36 +++----- lib/shoes/line.rb | 24 +++++ lib/shoes/oval.rb | 37 ++++++++ lib/shoes/shape.rb | 52 ++++++----- lib/swt_shoes.rb | 2 + lib/swt_shoes/element_methods.rb | 25 +++-- lib/swt_shoes/line.rb | 28 ++++++ lib/swt_shoes/oval.rb | 28 ++++++ lib/swt_shoes/shape.rb | 28 +++--- lib/white_shoes.rb | 2 + lib/white_shoes/line.rb | 21 +++++ lib/white_shoes/oval.rb | 21 +++++ lib/white_shoes/shape.rb | 3 +- spec/shoes/element_methods_spec.rb | 91 ++++--------------- spec/shoes/line_spec.rb | 33 +++++++ spec/shoes/oval_spec.rb | 57 ++++++++++++ spec/shoes/shape_spec.rb | 25 ++++- .../shared_element_method_spec.rb | 2 + spec/swt_shoes/element_methods_spec.rb | 47 +++++----- spec/swt_shoes/line_spec.rb | 31 +++++++ spec/swt_shoes/shape_spec.rb | 6 -- 23 files changed, 429 insertions(+), 180 deletions(-) create mode 100644 lib/shoes/line.rb create mode 100644 lib/shoes/oval.rb create mode 100644 lib/swt_shoes/line.rb create mode 100644 lib/swt_shoes/oval.rb create mode 100644 lib/white_shoes/line.rb create mode 100644 lib/white_shoes/oval.rb create mode 100644 spec/shoes/line_spec.rb create mode 100644 spec/shoes/oval_spec.rb create mode 100644 spec/swt_shoes/line_spec.rb diff --git a/lib/shoes.rb b/lib/shoes.rb index 0de74cc8..e21e8447 100644 --- a/lib/shoes.rb +++ b/lib/shoes.rb @@ -9,6 +9,9 @@ module Shoes attr_accessor :logger + def self.logger + @logger + end @logger = Log4jruby::Logger.get('test', :tracing => true, :level => :debug) @logger.debug("Shoooes!") @@ -28,6 +31,8 @@ module Shoes #require 'shoes/edit_box' #require 'shoes/check' #require 'shoes/image' +require 'shoes/line' +require 'shoes/oval' require 'shoes/sound' require 'shoes/shape' require 'shoes/configuration' diff --git a/lib/shoes/common/style.rb b/lib/shoes/common/style.rb index 2356f980..ec28cef4 100644 --- a/lib/shoes/common/style.rb +++ b/lib/shoes/common/style.rb @@ -1,5 +1,10 @@ module Shoes module Common + # Style methods. + # + # Requirements + # + # @style module Style def style(new_styles = {}) @style.merge! new_styles diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 5401aff1..06a85473 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -4,6 +4,8 @@ require 'shoes/button' require 'shoes/color' require 'shoes/flow' +require 'shoes/line' +require 'shoes/oval' require 'shoes/shape' module Shoes @@ -68,13 +70,8 @@ def sound(soundfile, opts = {}, &blk) # # Draws a line from (x1,y1) to (x2,y2) - # TODO: Probably don't need to use the full-on Swt::Path for this - def line(x1, y1, x2, y2, opts={}) - args = style.merge(opts) - args[:left], end_x = x1 < x2 ? [x1, x2] : [x2, x1] - args[:top], end_y = y1 < y2 ? [y1, y2] : [y2, y1] - path = lambda { line_to(end_x, end_y) } - Shoes::Shape.new(args, path) + def line(x1, y1, x2, y2, opts = {}) + Shoes::Line.new(x1, y1, x2, y2, style.merge(opts)) end # Draws an oval at (left, top) with either @@ -86,24 +83,13 @@ def line(x1, y1, x2, y2, opts={}) # where styles is a hash with any or all of these keys: # left, top, width, height, radius, center def oval(*opts) - defaults = {left: 0, top: 0, width: 0, height: 0, radius: 0, center: false} - args = opts.last.class == Hash ? opts.pop : {} - case opts.length - when 0, 1 - when 2; args[:left], args[:top] = opts - when 3; args[:left], args[:top], args[:radius] = opts - else args[:left], args[:top], args[:width], args[:height] = opts - end - args = defaults.merge(style).merge(args) - args[:width] = args[:radius] * 2 if args[:width].zero? - args[:height] = args[:width] if args[:height].zero? - if args[:center] - args[:left] -= args[:width] / 2 - args[:top] -= args[:height] / 2 - end - args[:stroke] ||= @style[:stroke] - args[:strokewidth] ||= @style[:strokewidth] - Shoes::Shape.new args + oval_style = opts.last.class == Hash ? opts.pop : {} + Shoes::Oval.new(*opts, style.merge(oval_style)) + end + + # Creates a new Shoes::Shape object + def shape(style={}, &blk) + Shoes::Shape.new(style, blk) end # Creates a new Shoes::Color object diff --git a/lib/shoes/line.rb b/lib/shoes/line.rb new file mode 100644 index 00000000..b1926009 --- /dev/null +++ b/lib/shoes/line.rb @@ -0,0 +1,24 @@ +require 'shoes/common_methods' +require 'shoes/common/paint' +require 'shoes/common/style' + +module Shoes + class Line + include Shoes::CommonMethods + include Shoes::Common::Paint + include Shoes::Common::Style + + def initialize(x1, y1, x2, y2, opts = {}) + @left = x1 < x2 ? x1 : x2 + @top = y1 < y2 ? y1 : y2 + @width = (x1 - x2).abs + @height = (y1 - y2).abs + + @style = opts + + # GUI + @gui_opts = @style.delete(:gui) + gui_init + end + end +end diff --git a/lib/shoes/oval.rb b/lib/shoes/oval.rb new file mode 100644 index 00000000..143b35ed --- /dev/null +++ b/lib/shoes/oval.rb @@ -0,0 +1,37 @@ +require 'shoes/common_methods' +require 'shoes/common/paint' +require 'shoes/common/style' + +module Shoes + class Oval + include Shoes::CommonMethods + include Shoes::Common::Paint + include Shoes::Common::Style + + def initialize(*opts) + defaults = {:left => 0, :top => 0, :width => 0, :height => 0, :radius => 0, :center => false} + @style = opts.last.class == Hash ? opts.pop : {} + case opts.length + when 0, 1 + when 2; @style[:left], @style[:top] = opts + when 3; @style[:left], @style[:top], @style[:radius] = opts + else @style[:left], @style[:top], @style[:width], @style[:height] = opts + end + @style = defaults.merge(@style) + @left = @style[:left] + @top = @style[:top] + @width = @style[:width] + @height = @style[:height] + @width = @style[:radius] * 2 if @width.zero? + @height = @width if @height.zero? + if @style[:center] + @left -= @width / 2 if @width > 0 + @top -= @height / 2 if @height > 0 + end + + # GUI + @gui_opts = @style.delete(:gui) + gui_init + end + end +end diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index 5549c9f6..125e56c5 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -2,6 +2,7 @@ require 'shoes/common_methods' require 'shoes/common/paint' require 'shoes/common/style' +require 'shoes/line' module Shoes class Shape @@ -14,13 +15,11 @@ class Shape # Creates a new Shoes::Shape # + # This is a composite shape, which has one or more components. + # # Implementation frameworks should pass in any required arguments # through the +opts+ hash. - # - # opts['x'] - the initial x-position for drawing - # opts['y'] - the initial y-position for drawing - def initialize(opts={}, blk = nil) - @gui_opts = opts.delete(:gui) || {} + def initialize(opts = {}, blk = nil) @style = opts @blk = blk @@ -33,27 +32,38 @@ def initialize(opts={}, blk = nil) # Initialize current point to (left, top) @x, @y = @left, @top + # Component shapes + @components = [] + + # GUI + @gui_opts = @style.delete(:gui) gui_init instance_eval &@blk unless @blk.nil? end - # Update bounds and sizes - # TODO: Handle all of the edge cases - def update_bounds - if @x < @left - @width += @left - @x - @left = @x - elsif @x > right - @width += (@x - right) - end - - if @y < @top - @height += @top - @y - @top = @x - elsif @y > bottom - @height += @y - bottom - end + def left + @components.map(&:left).min + end + + def top + @components.map(&:top).min + end + + def right + @components.map { |c| c.left + c.width }.max + end + + def bottom + @components.map { |c| c.top + c.height }.max + end + + def width + (left - right).abs + end + + def height + (top - bottom).abs end end end diff --git a/lib/swt_shoes.rb b/lib/swt_shoes.rb index c7f1b559..de3a009d 100644 --- a/lib/swt_shoes.rb +++ b/lib/swt_shoes.rb @@ -15,6 +15,8 @@ def window(*a, &b) #require 'swt_shoes/window' require 'swt_shoes/flow' require 'swt_shoes/button' +require 'swt_shoes/line' +require 'swt_shoes/oval' require 'swt_shoes/shape' require 'swt_shoes/color' diff --git a/lib/swt_shoes/element_methods.rb b/lib/swt_shoes/element_methods.rb index dec1aa4e..34ca0498 100644 --- a/lib/swt_shoes/element_methods.rb +++ b/lib/swt_shoes/element_methods.rb @@ -51,20 +51,10 @@ module ElementMethods # cbox #end # - def line(x1, y1, x2, y2, opts={}) - args = opts - args[:gui] = { - container: self.gui_container, - element: Swt::Path.new(Shoes.display), - paint_callback: lambda do |event, shape| - #return if hidden? - gc = event.gc - gc.set_antialias Swt::SWT::ON - gc.set_line_width shape.style[:strokewidth] - gc.draw_path(shape.gui_element) - end - } - super(x1, y1, x2, y2, args) + def line(*opts) + args = opts.last.class == Hash ? opts.pop : {} + args[:gui] = {container: self.gui_container} + super(*opts, args) end def oval(*opts) @@ -82,6 +72,13 @@ def oval(*opts) } super(*opts, args) end + + # FIXME: same as #line + def shape(*opts) + args = opts.last.class == Hash ? opts.pop : {} + args[:gui] = {container: self.gui_container} + super(*opts, args) + end end end diff --git a/lib/swt_shoes/line.rb b/lib/swt_shoes/line.rb new file mode 100644 index 00000000..80c495cc --- /dev/null +++ b/lib/swt_shoes/line.rb @@ -0,0 +1,28 @@ +module SwtShoes + module Line + attr_reader :gui_container, :gui_element + + def gui_init + # @gui_opts must be provided if this shape is responsible for + # drawing itself. If this shape is part of another shape, then + # @gui_opts should be nil + if @gui_opts + @gui_container = @gui_opts[:container] + default_paint_callback = lambda do |event| + gc = event.gc + gc.set_antialias Swt::SWT::ON + gc.set_line_width self.style[:strokewidth] + gc.draw_line(@left, @top, right, bottom) + end + @gui_paint_callback = @gui_opts[:paint_callback] || default_paint_callback + @gui_container.add_paint_listener(@gui_paint_callback) + end + end + end +end + +module Shoes + class Line + include SwtShoes::Line + end +end diff --git a/lib/swt_shoes/oval.rb b/lib/swt_shoes/oval.rb new file mode 100644 index 00000000..fe0bcc9c --- /dev/null +++ b/lib/swt_shoes/oval.rb @@ -0,0 +1,28 @@ +module SwtShoes + module Oval + attr_reader :gui_container, :gui_element + + # FIXME: This (mostly) duplicates SwtShoes::Line#gui_init + def gui_init + # @gui_opts must be provided if this shape is responsible for + # drawing itself. If this shape is part of another shape, then + # @gui_opts should be nil + if @gui_opts + @gui_container = @gui_opts[:container] + @gui_paint_callback = lambda do |event| + gc = event.gc + gc.set_antialias Swt::SWT::ON + gc.set_line_width self.style[:strokewidth] + gc.draw_oval(@left, @top, @width, @height) + end + @gui_container.add_paint_listener(@gui_paint_callback) + end + end + end +end + +module Shoes + class Oval + include SwtShoes::Oval + end +end diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 5a422253..0b315d36 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -30,33 +30,37 @@ module Shape # end # } # - # This hook method is only interested in the `:gui` values. + # This hook method is only interested in the `:gui` values, which will + # be passed in the @gui_opts variable. # # Note in particular the `:paint_callback`. It has 2 parameters. The # first is the Swt event that will trigger the callback. The second is # this shape. def gui_init - @gui_container = @gui_opts[:container] - if @gui_opts[:element] - @gui_element = @gui_opts[:element] - @gui_element.move_to(@x, @y) + # @gui_opts must be provided if this shape is responsible for + # drawing itself. If this shape is part of another shape, then + # @gui_opts should be nil + if @gui_opts + @gui_container = @gui_opts[:container] + @gui_element = @gui_opts[:element] || Swt::Path.new(Shoes.display) + @gui_paint_callback = lambda do |event| + gc = event.gc + gc.set_antialias Swt::SWT::ON + gc.set_line_width self.style[:strokewidth] + gc.draw_path(@gui_element) + end + @gui_container.add_paint_listener(@gui_paint_callback) end - @gui_paint_callback = lambda do |e| - @gui_opts[:paint_callback].call(e, self) - end - @gui_container.add_paint_listener(@gui_paint_callback) end def line_to(x, y) - @x, @y = x, y + @components << ::Shoes::Line.new(@x, @y, x, y, @style) @gui_element.line_to(x, y) - update_bounds end def move_to(x, y) @x, @y = x, y @gui_element.move_to(x, y) - update_bounds end end end diff --git a/lib/white_shoes.rb b/lib/white_shoes.rb index 2d943dd0..8f829d3c 100644 --- a/lib/white_shoes.rb +++ b/lib/white_shoes.rb @@ -3,6 +3,8 @@ require 'white_shoes/app' require 'white_shoes/flow' require 'white_shoes/button' +require 'white_shoes/line' +require 'white_shoes/oval' require 'white_shoes/shape' require 'rubygems' diff --git a/lib/white_shoes/line.rb b/lib/white_shoes/line.rb new file mode 100644 index 00000000..5a0e5e10 --- /dev/null +++ b/lib/white_shoes/line.rb @@ -0,0 +1,21 @@ +require 'white_shoes/common_methods' + +module WhiteShoes + # Line methods + module Line + attr_accessor :gui_container + attr_accessor :gui_element + + def gui_init + self.gui_element = "A new gui Line" + end + end +end + +module Shoes + class Line + include WhiteShoes::Line + end +end + + diff --git a/lib/white_shoes/oval.rb b/lib/white_shoes/oval.rb new file mode 100644 index 00000000..877010c5 --- /dev/null +++ b/lib/white_shoes/oval.rb @@ -0,0 +1,21 @@ +require 'white_shoes/common_methods' + +module WhiteShoes + # Oval methods + module Oval + attr_accessor :gui_container + attr_accessor :gui_element + + def gui_init + self.gui_element = "A new gui Oval" + end + end +end + +module Shoes + class Oval + include WhiteShoes::Oval + end +end + + diff --git a/lib/white_shoes/shape.rb b/lib/white_shoes/shape.rb index b8368381..3ccfe252 100644 --- a/lib/white_shoes/shape.rb +++ b/lib/white_shoes/shape.rb @@ -18,11 +18,10 @@ def gui_init def move_to(x, y) @x, @y = x, y - update_bounds end def line_to(x, y) - move_to(x, y) + @components << Shoes::Line.new(@x, @y, x, y, @style) end end end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 6eb120dc..0ec1c5e1 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -38,86 +38,27 @@ def initialize end describe "line" do - shared_examples_for "basic line" do - it { should be_instance_of(Shoes::Shape) } - its(:top) { should eq(15) } - its(:left) { should eq(10) } - its(:width) { should eq(90) } - its(:height) { should eq(45) } - end - - context "created left-to-right, top-to-bottom" do - subject { ElementMethodsShoeLaces.new.line(10, 15, 100, 60) } - it_behaves_like "basic line" - end - - context "specified right-to-left, top-to-bottom" do - subject { ElementMethodsShoeLaces.new.line(100, 15, 10, 60) } - it_behaves_like "basic line" - end - - context "specified right-to-left, bottom-to-top" do - subject { ElementMethodsShoeLaces.new.line(100, 60, 10, 15) } - it_behaves_like "basic line" - end - - context "specified left-to-right, bottom-to-top" do - subject { ElementMethodsShoeLaces.new.line(10, 60, 100, 15) } - it_behaves_like "basic line" + it "makes a Shoes::Line" do + Shoes::Line.should_receive(:new) + ElementMethodsShoeLaces.new.line(10, 15, 20, 30) end end describe "oval" do - context "(eccentric)" do - subject { ElementMethodsShoeLaces.new.oval(20, 30, 100, 200) } - - it { should be_instance_of(Shoes::Shape) } - its (:top) { should eq(30) } - its (:left) { should eq(20) } - its (:width) { should eq(100) } - its (:height) { should eq(200) } - end - - shared_examples_for "circle" do - it { should be_instance_of(Shoes::Shape) } - its (:top) { should eq(30) } - its (:left) { should eq(20) } - its (:width) { should eq(100) } - its (:height) { should eq(100) } - end - - context "(circle) created with explicit arguments:" do - context "width and height" do - subject { ElementMethodsShoeLaces.new.oval(20, 30, 100, 100) } - it_behaves_like "circle" - end - - context "radius" do - subject { ElementMethodsShoeLaces.new.oval(20, 30, 50) } - it_behaves_like "circle" - end + it "produces a Shoes::Oval" do + ElementMethodsShoeLaces.new.oval(10, 50, 250).should be_an_instance_of(Shoes::Oval) end + end - context "(circle) created with style hash:" do - context "left, top, height, width" do - subject { ElementMethodsShoeLaces.new.oval(left: 20, top: 30, width: 100, height: 100) } - it_behaves_like "circle" - end - - context "left, top, height, width, center: false" do - subject { ElementMethodsShoeLaces.new.oval(left: 20, top: 30, width: 100, height: 100, center: false) } - it_behaves_like "circle" - end - - context "left, top, radius" do - subject { ElementMethodsShoeLaces.new.oval(left: 20, top: 30, radius: 50) } - it_behaves_like "circle" - end - - context "left, top, width, height, center: true" do - subject { ElementMethodsShoeLaces.new.oval(left: 70, top: 80, width: 100, height: 100, center: true) } - it_behaves_like "circle" + describe "shape" do + it "produces a Shoes::Shape" do + shape = ElementMethodsShoeLaces.new.shape do + move_to 400, 300 + line_to 400, 200 + line_to 100, 100 + line_to 400, 300 end + shape.should be_an_instance_of(Shoes::Shape) end end @@ -156,7 +97,7 @@ def initialize specify "applies to subsequently created objects" do app.stroke color - Shoes::Shape.should_receive(:new).with do |*args| + Shoes::Oval.should_receive(:new).with do |*args| style = args.pop style[:stroke].should eq(color) end @@ -177,7 +118,7 @@ def initialize specify "applies to subsequently created objects" do app.strokewidth 6 - Shoes::Shape.should_receive(:new).with do |*args| + Shoes::Oval.should_receive(:new).with do |*args| style = args.pop style[:strokewidth].should eq(6) end diff --git a/spec/shoes/line_spec.rb b/spec/shoes/line_spec.rb new file mode 100644 index 00000000..6cd430b3 --- /dev/null +++ b/spec/shoes/line_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +require 'shoes/line' +require 'white_shoes' + +describe Shoes::Line do + shared_examples_for "basic line" do + it { should be_kind_of(Shoes::Line) } + its(:top) { should eq(15) } + its(:left) { should eq(10) } + its(:width) { should eq(90) } + its(:height) { should eq(45) } + end + + context "created left-to-right, top-to-bottom" do + subject { Shoes::Line.new(10, 15, 100, 60) } + it_behaves_like "basic line" + end + + context "specified right-to-left, top-to-bottom" do + subject { Shoes::Line.new(100, 15, 10, 60) } + it_behaves_like "basic line" + end + + context "specified right-to-left, bottom-to-top" do + subject { Shoes::Line.new(100, 60, 10, 15) } + it_behaves_like "basic line" + end + + context "specified left-to-right, bottom-to-top" do + subject { Shoes::Line.new(10, 60, 100, 15) } + it_behaves_like "basic line" + end +end diff --git a/spec/shoes/oval_spec.rb b/spec/shoes/oval_spec.rb new file mode 100644 index 00000000..04c2dfae --- /dev/null +++ b/spec/shoes/oval_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' +require 'shoes/oval' +require 'white_shoes' + +describe Shoes::Oval do + context "(eccentric)" do + subject { Shoes::Oval.new(20, 30, 100, 200) } + + it { should be_instance_of(Shoes::Oval) } + its (:top) { should eq(30) } + its (:left) { should eq(20) } + its (:width) { should eq(100) } + its (:height) { should eq(200) } + end + + shared_examples_for "circle" do + it { should be_instance_of(Shoes::Oval) } + its (:top) { should eq(30) } + its (:left) { should eq(20) } + its (:width) { should eq(100) } + its (:height) { should eq(100) } + end + + context "(circle) created with explicit arguments:" do + context "width and height" do + subject { Shoes::Oval.new(20, 30, 100, 100) } + it_behaves_like "circle" + end + + context "radius" do + subject { Shoes::Oval.new(20, 30, 50) } + it_behaves_like "circle" + end + end + + context "(circle) created with style hash:" do + context "left, top, height, width" do + subject { Shoes::Oval.new(left: 20, top: 30, width: 100, height: 100) } + it_behaves_like "circle" + end + + context "left, top, height, width, center: false" do + subject { Shoes::Oval.new(left: 20, top: 30, width: 100, height: 100, center: false) } + it_behaves_like "circle" + end + + context "left, top, radius" do + subject { Shoes::Oval.new(left: 20, top: 30, radius: 50) } + it_behaves_like "circle" + end + + context "left, top, width, height, center: true" do + subject { Shoes::Oval.new(left: 70, top: 80, width: 100, height: 100, center: true) } + it_behaves_like "circle" + end + end +end diff --git a/spec/shoes/shape_spec.rb b/spec/shoes/shape_spec.rb index 4eed40aa..f5940b78 100644 --- a/spec/shoes/shape_spec.rb +++ b/spec/shoes/shape_spec.rb @@ -1,7 +1,30 @@ -require_relative 'spec_helper' +require 'spec_helper' require 'shoes/shape' +require 'white_shoes' describe Shoes::Shape do it_behaves_like "object with stroke" it_behaves_like "object with style" + + describe "octagon" do + let(:draw) { + lambda { + xs = [200, 300, 370, 370, 300, 200, 130, 130] + ys = [100, 100, 170, 270, 340, 340, 270, 170] + move_to xs.first, ys.first + xs.zip(ys).each do |x, y| + line_to(x, y) + end + line_to xs.first, ys.first + } + } + subject { Shoes::Shape.new Hash.new, draw } + + its(:left) { should eq(130) } + its(:top) { should eq(100) } + its(:right) { should eq(370) } + its(:bottom) { should eq(340) } + its(:width) { should eq(240) } + its(:height) { should eq(240) } + end end diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb index 1d615dc2..399964e8 100644 --- a/spec/shoes/shared_examples/shared_element_method_spec.rb +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -1,3 +1,5 @@ +require 'shoes/color' + shared_examples_for "object with stroke" do let(:color) { Shoes::COLORS[:tomato] } diff --git a/spec/swt_shoes/element_methods_spec.rb b/spec/swt_shoes/element_methods_spec.rb index d83a4ede..006e65d8 100644 --- a/spec/swt_shoes/element_methods_spec.rb +++ b/spec/swt_shoes/element_methods_spec.rb @@ -15,6 +15,12 @@ def initialize Shoes.configuration.framework = 'swt_shoes' let(:gui_container) { double('gui_container') } + let(:app) { + ElementMethodsShoeLaces.new.tap { |a| + a.gui_container = gui_container + } + } + shared_examples_for "paintable" do it "registers for painting" do @@ -26,40 +32,33 @@ def initialize end describe "line" do - # The line object - subject { - s = ElementMethodsShoeLaces.new - s.gui_container = gui_container - s.line(10, 15, 100, 60) - } - - context "same as WhiteShoes" do - before :each do - gui_container.stub(:add_paint_listener) - end - it { should be_instance_of(Shoes::Shape) } - its(:top) { should eq(15) } - its(:left) { should eq(10) } - its(:width) { should eq(90) } - its(:height) { should eq(45) } + specify "creates a Shoes::Line" do + gui_container.should_receive(:add_paint_listener) + app.line(1, 2, 101, 201).should be_an_instance_of(Shoes::Line) end + end + describe "oval" do + # The oval object + subject { app.oval(30, 20, 100, 200) } context "Swt-specific" do end it_behaves_like "paintable" end - describe "oval" do - # The oval object + describe "shape" do subject { - s = ElementMethodsShoeLaces.new - s.gui_container = gui_container - s.oval(30, 20, 100, 200) + app.shape do + move_to 100, 200 + line_to 300, 400 + end } - context "Swt-specific" do - end - it_behaves_like "paintable" + specify "create a Shoes::Shape" do + gui_container.should_receive(:add_paint_listener) + subject.should be_an_instance_of(Shoes::Shape) + end end + end diff --git a/spec/swt_shoes/line_spec.rb b/spec/swt_shoes/line_spec.rb new file mode 100644 index 00000000..e0a418bb --- /dev/null +++ b/spec/swt_shoes/line_spec.rb @@ -0,0 +1,31 @@ +describe SwtShoes::Line do + let(:gui_container) { double("gui container") } + let(:opts) { {:gui => {:container => gui_container}} } + + subject { + Shoes::Line.new(10, 15, 100, 60, opts) + } + + context "same as WhiteShoes" do + before :each do + gui_container.should_receive(:add_paint_listener) + end + it { should be_instance_of(Shoes::Line) } + its(:top) { should eq(15) } + its(:left) { should eq(10) } + its(:width) { should eq(90) } + its(:height) { should eq(45) } + end + + context "Swt-specific" do + let(:paint_callback) { double("paint callback") } + let(:opts) { {:gui => {:container => gui_container, :paint_callback => paint_callback}} } + + it "uses passed-in paint callback if present" do + gui_container.should_receive(:add_paint_listener).with(paint_callback) + subject + end + end + + it_behaves_like "paintable" +end diff --git a/spec/swt_shoes/shape_spec.rb b/spec/swt_shoes/shape_spec.rb index 0f9e19c1..e5080ab3 100644 --- a/spec/swt_shoes/shape_spec.rb +++ b/spec/swt_shoes/shape_spec.rb @@ -44,12 +44,6 @@ def initialize(opts = {}, blk = nil ) it_behaves_like "Swt::Shape" - describe "gui_init" do - it "sets current point and registers paint listener" do - gui_element.should_receive(:move_to) - subject - end - end end context "with gui container only" do From 102aa9588efb6363801b12d308923df21324e742 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 23 Apr 2012 23:48:50 -0500 Subject: [PATCH 14/23] Added stroke defaults, callback spec --- lib/shoes/common/paint.rb | 1 + lib/shoes/common/style.rb | 1 + lib/shoes/element_methods.rb | 9 +++++++ lib/shoes/line.rb | 2 +- lib/shoes/oval.rb | 2 +- lib/shoes/shape.rb | 2 +- lib/swt_shoes/line.rb | 2 ++ lib/swt_shoes/oval.rb | 1 + spec/shoes/element_methods_spec.rb | 25 +++++++++++++++++- spec/shoes/line_spec.rb | 5 ++++ spec/shoes/oval_spec.rb | 5 ++++ .../shared_element_method_spec.rb | 5 ++++ spec/swt_shoes/line_spec.rb | 1 + spec/swt_shoes/shared_examples/style_spec.rb | 26 +++++++++++++++++++ spec/swt_shoes/spec_helper.rb | 3 +++ 15 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 spec/swt_shoes/shared_examples/style_spec.rb diff --git a/lib/shoes/common/paint.rb b/lib/shoes/common/paint.rb index 91ac5a2b..cbf2835d 100644 --- a/lib/shoes/common/paint.rb +++ b/lib/shoes/common/paint.rb @@ -1,6 +1,7 @@ module Shoes module Common module Paint + DEFAULTS = {:stroke => Shoes::COLORS[:black]} def stroke @style[:stroke] end diff --git a/lib/shoes/common/style.rb b/lib/shoes/common/style.rb index ec28cef4..861b6cc0 100644 --- a/lib/shoes/common/style.rb +++ b/lib/shoes/common/style.rb @@ -6,6 +6,7 @@ module Common # # @style module Style + PAINT_DEFAULTS = {:stroke => Shoes::COLORS[:black]} def style(new_styles = {}) @style.merge! new_styles end diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 06a85473..960dc650 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -111,6 +111,15 @@ def strokewidth(width) @style[:strokewidth] = width end + # Sets the current fill color + # + # Arguments + # + # color - a Shoes::Color + def fill(color) + @style[:fill] = color + end + # Adds style, or just returns current style if no argument # # Returns the updated style diff --git a/lib/shoes/line.rb b/lib/shoes/line.rb index b1926009..bc03bddd 100644 --- a/lib/shoes/line.rb +++ b/lib/shoes/line.rb @@ -14,7 +14,7 @@ def initialize(x1, y1, x2, y2, opts = {}) @width = (x1 - x2).abs @height = (y1 - y2).abs - @style = opts + @style = Shoes::Common::Paint::DEFAULTS.merge(opts) # GUI @gui_opts = @style.delete(:gui) diff --git a/lib/shoes/oval.rb b/lib/shoes/oval.rb index 143b35ed..958c9ddf 100644 --- a/lib/shoes/oval.rb +++ b/lib/shoes/oval.rb @@ -17,7 +17,7 @@ def initialize(*opts) when 3; @style[:left], @style[:top], @style[:radius] = opts else @style[:left], @style[:top], @style[:width], @style[:height] = opts end - @style = defaults.merge(@style) + @style = Shoes::Common::Paint::DEFAULTS.merge(defaults).merge(@style) @left = @style[:left] @top = @style[:top] @width = @style[:width] diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index 125e56c5..954aa782 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -20,7 +20,7 @@ class Shape # Implementation frameworks should pass in any required arguments # through the +opts+ hash. def initialize(opts = {}, blk = nil) - @style = opts + @style = Shoes::Common::Paint::DEFAULTS.merge(opts) @blk = blk diff --git a/lib/swt_shoes/line.rb b/lib/swt_shoes/line.rb index 80c495cc..4ac55482 100644 --- a/lib/swt_shoes/line.rb +++ b/lib/swt_shoes/line.rb @@ -1,6 +1,7 @@ module SwtShoes module Line attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback def gui_init # @gui_opts must be provided if this shape is responsible for @@ -11,6 +12,7 @@ def gui_init default_paint_callback = lambda do |event| gc = event.gc gc.set_antialias Swt::SWT::ON + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_line(@left, @top, right, bottom) end diff --git a/lib/swt_shoes/oval.rb b/lib/swt_shoes/oval.rb index fe0bcc9c..db47196b 100644 --- a/lib/swt_shoes/oval.rb +++ b/lib/swt_shoes/oval.rb @@ -13,6 +13,7 @@ def gui_init gc = event.gc gc.set_antialias Swt::SWT::ON gc.set_line_width self.style[:strokewidth] + gc.set_background(self.style[:fill].to_native) gc.draw_oval(@left, @top, @width, @height) end @gui_container.add_paint_listener(@gui_paint_callback) diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 0ec1c5e1..f21b327a 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -1,4 +1,5 @@ require_relative 'spec_helper' +require "shoes/color" require 'shoes/element_methods' require 'shoes/configuration' @@ -81,7 +82,6 @@ def initialize end describe "stroke" do - require "shoes/color" # Need the colors! let(:app) { ElementMethodsShoeLaces.new } let(:color) { Shoes::COLORS[:tomato] } @@ -126,6 +126,29 @@ def initialize end end + describe "fill" do + let(:app) { ElementMethodsShoeLaces.new } + let(:color) { Shoes::COLORS[:tomato] } + + specify "returns a color" do + app.fill(color).class.should eq(Shoes::Color) + end + + # This works differently on the app than on a normal element + specify "sets on receiver" do + app.fill color + app.style[:fill].should eq(color) + end + + specify "applies to subsequently created objects" do + app.fill color + Shoes::Oval.should_receive(:new).with do |*args| + style = args.pop + style[:fill].should eq(color) + end + app.oval(10, 10, 100, 100) + end + end #it "Should return 0 for left for button_one" do # @gui.elements['button_one'].left.should be 0 #end diff --git a/spec/shoes/line_spec.rb b/spec/shoes/line_spec.rb index 6cd430b3..5662038a 100644 --- a/spec/shoes/line_spec.rb +++ b/spec/shoes/line_spec.rb @@ -3,6 +3,11 @@ require 'white_shoes' describe Shoes::Line do + describe "basic" do + subject { Shoes::Line.new(20, 23, 300, 430) } + it_behaves_like "object with stroke" + end + shared_examples_for "basic line" do it { should be_kind_of(Shoes::Line) } its(:top) { should eq(15) } diff --git a/spec/shoes/oval_spec.rb b/spec/shoes/oval_spec.rb index 04c2dfae..7f22de33 100644 --- a/spec/shoes/oval_spec.rb +++ b/spec/shoes/oval_spec.rb @@ -3,6 +3,11 @@ require 'white_shoes' describe Shoes::Oval do + describe "basic" do + subject { Shoes::Oval.new(20, 30, 100, 200) } + it_behaves_like "object with stroke" + end + context "(eccentric)" do subject { Shoes::Oval.new(20, 30, 100, 200) } diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb index 399964e8..c7c9d986 100644 --- a/spec/shoes/shared_examples/shared_element_method_spec.rb +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -13,6 +13,11 @@ subject.stroke.should eq(color) subject.style[:stroke].should eq(color) end + + # Be sure the subject does *not* have the stroke set previously + specify "defaults to black" do + subject.stroke.should eq(Shoes::COLORS[:black]) + end end diff --git a/spec/swt_shoes/line_spec.rb b/spec/swt_shoes/line_spec.rb index e0a418bb..32125289 100644 --- a/spec/swt_shoes/line_spec.rb +++ b/spec/swt_shoes/line_spec.rb @@ -28,4 +28,5 @@ end it_behaves_like "paintable" + it_behaves_like "Swt object with stroke" end diff --git a/spec/swt_shoes/shared_examples/style_spec.rb b/spec/swt_shoes/shared_examples/style_spec.rb new file mode 100644 index 00000000..82d51f45 --- /dev/null +++ b/spec/swt_shoes/shared_examples/style_spec.rb @@ -0,0 +1,26 @@ +shared_examples_for "Swt object with stroke" do + describe "paint callback" do + let(:event) { double("event") } + let(:gc) { double("gc").as_null_object } + + before :each do + event.stub(:gc) { gc } + gui_container.should_receive(:add_paint_listener) + end + + specify "sets stroke color" do + gc.should_receive(:set_foreground).with(subject.stroke.to_native) + subject.gui_paint_callback.call(event) + end + + specify "sets antialias" do + gc.should_receive(:set_antialias).with(Swt::SWT::ON) + subject.gui_paint_callback.call(event) + end + + specify "sets strokewidth" do + gc.should_receive(:set_line_width).with(subject.style[:strokewidth]) + subject.gui_paint_callback.call(event) + end + end +end diff --git a/spec/swt_shoes/spec_helper.rb b/spec/swt_shoes/spec_helper.rb index 1e91dd31..b9431cab 100644 --- a/spec/swt_shoes/spec_helper.rb +++ b/spec/swt_shoes/spec_helper.rb @@ -1,2 +1,5 @@ require "swt_shoes" Shoes.configuration.framework = 'swt_shoes' + +shared_examples = File.join(File.dirname(__FILE__), 'shared_examples', '**/*.rb') +Dir[shared_examples].each { |f| require f } From bee6a918e2743b51c31a8f5b77b3efa24086847d Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Tue, 24 Apr 2012 00:29:24 -0500 Subject: [PATCH 15/23] Added fill for oval --- lib/shoes/common/paint.rb | 14 +++++++++++- lib/shoes/common/style.rb | 1 - lib/swt_shoes/oval.rb | 5 ++++- spec/shoes/element_methods_spec.rb | 4 ++-- spec/shoes/oval_spec.rb | 1 + .../shared_element_method_spec.rb | 22 +++++++++++++++++-- spec/swt_shoes/oval_spec.rb | 13 +++++++++++ spec/swt_shoes/shared_examples/style_spec.rb | 17 ++++++++++++++ 8 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 spec/swt_shoes/oval_spec.rb diff --git a/lib/shoes/common/paint.rb b/lib/shoes/common/paint.rb index cbf2835d..68055fe6 100644 --- a/lib/shoes/common/paint.rb +++ b/lib/shoes/common/paint.rb @@ -1,7 +1,11 @@ module Shoes module Common module Paint - DEFAULTS = {:stroke => Shoes::COLORS[:black]} + DEFAULTS = { + :stroke => Shoes::COLORS[:black], + :fill => Shoes::COLORS[:black] + } + def stroke @style[:stroke] end @@ -9,6 +13,14 @@ def stroke def stroke=(color) @style[:stroke] = color end + + def fill + @style[:fill] + end + + def fill=(color) + @style[:fill] = color + end end end end diff --git a/lib/shoes/common/style.rb b/lib/shoes/common/style.rb index 861b6cc0..ec28cef4 100644 --- a/lib/shoes/common/style.rb +++ b/lib/shoes/common/style.rb @@ -6,7 +6,6 @@ module Common # # @style module Style - PAINT_DEFAULTS = {:stroke => Shoes::COLORS[:black]} def style(new_styles = {}) @style.merge! new_styles end diff --git a/lib/swt_shoes/oval.rb b/lib/swt_shoes/oval.rb index db47196b..6ab26fa3 100644 --- a/lib/swt_shoes/oval.rb +++ b/lib/swt_shoes/oval.rb @@ -1,6 +1,7 @@ module SwtShoes module Oval attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback # FIXME: This (mostly) duplicates SwtShoes::Line#gui_init def gui_init @@ -12,8 +13,10 @@ def gui_init @gui_paint_callback = lambda do |event| gc = event.gc gc.set_antialias Swt::SWT::ON + gc.set_background self.fill.to_native + gc.fill_oval(@left, @top, @width, @height) + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] - gc.set_background(self.style[:fill].to_native) gc.draw_oval(@left, @top, @width, @height) end @gui_container.add_paint_listener(@gui_paint_callback) diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index f21b327a..48c1c06d 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -83,7 +83,7 @@ def initialize describe "stroke" do let(:app) { ElementMethodsShoeLaces.new } - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do app.stroke(color).class.should eq(Shoes::Color) @@ -128,7 +128,7 @@ def initialize describe "fill" do let(:app) { ElementMethodsShoeLaces.new } - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do app.fill(color).class.should eq(Shoes::Color) diff --git a/spec/shoes/oval_spec.rb b/spec/shoes/oval_spec.rb index 7f22de33..3c728879 100644 --- a/spec/shoes/oval_spec.rb +++ b/spec/shoes/oval_spec.rb @@ -6,6 +6,7 @@ describe "basic" do subject { Shoes::Oval.new(20, 30, 100, 200) } it_behaves_like "object with stroke" + it_behaves_like "object with fill" end context "(eccentric)" do diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb index c7c9d986..983f6dfd 100644 --- a/spec/shoes/shared_examples/shared_element_method_spec.rb +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -1,7 +1,7 @@ require 'shoes/color' shared_examples_for "object with stroke" do - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do c = subject.stroke = color @@ -16,8 +16,26 @@ # Be sure the subject does *not* have the stroke set previously specify "defaults to black" do - subject.stroke.should eq(Shoes::COLORS[:black]) + subject.stroke.should eq(Shoes::COLORS.fetch :black) end end +shared_examples_for "object with fill" do + let(:color) { Shoes::COLORS.fetch :honeydew } + specify "returns a color" do + c = subject.fill = color + c.class.should eq(Shoes::Color) + end + + specify "sets on receiver" do + subject.fill = color + subject.fill.should eq(color) + subject.style[:fill].should eq(color) + end + + # Be sure the subject does *not* have the stroke set previously + specify "defaults to black" do + subject.fill.should eq(Shoes::COLORS.fetch :black) + end +end diff --git a/spec/swt_shoes/oval_spec.rb b/spec/swt_shoes/oval_spec.rb new file mode 100644 index 00000000..9b840ba6 --- /dev/null +++ b/spec/swt_shoes/oval_spec.rb @@ -0,0 +1,13 @@ +describe SwtShoes::Oval do + let(:gui_container) { double("gui container") } + let(:opts) { {:gui => {:container => gui_container}} } + + subject { + Shoes::Oval.new(10, 15, 100, opts) + } + + it_behaves_like "paintable" + it_behaves_like "Swt object with stroke" + it_behaves_like "Swt object with fill" +end + diff --git a/spec/swt_shoes/shared_examples/style_spec.rb b/spec/swt_shoes/shared_examples/style_spec.rb index 82d51f45..45624e78 100644 --- a/spec/swt_shoes/shared_examples/style_spec.rb +++ b/spec/swt_shoes/shared_examples/style_spec.rb @@ -24,3 +24,20 @@ end end end + +shared_examples_for "Swt object with fill" do + describe "paint callback" do + let(:event) { double("event") } + let(:gc) { double("gc").as_null_object } + + before :each do + event.stub(:gc) { gc } + gui_container.should_receive(:add_paint_listener) + end + + specify "sets fill color" do + gc.should_receive(:set_background).with(subject.fill.to_native) + subject.gui_paint_callback.call(event) + end + end +end From 51811718e880bc4abbe821514c896910f36684e6 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Tue, 24 Apr 2012 01:06:15 -0500 Subject: [PATCH 16/23] Added fill to shape --- lib/shoes/element_methods.rb | 4 ++-- lib/swt_shoes/shape.rb | 7 +++++-- spec/shoes/element_methods_spec.rb | 16 ++++++++++++---- spec/swt_shoes/shape_spec.rb | 25 +++++++++++++++++++------ 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 960dc650..1da7fd5d 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -88,8 +88,8 @@ def oval(*opts) end # Creates a new Shoes::Shape object - def shape(style={}, &blk) - Shoes::Shape.new(style, blk) + def shape(shape_style={}, &blk) + Shoes::Shape.new(style.merge(shape_style), blk) end # Creates a new Shoes::Color object diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 0b315d36..47666795 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -8,8 +8,8 @@ module SwtShoes # @opts - options # module Shape - attr_reader :gui_container - attr_reader :gui_element + attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback # The initialization hook for SwtShoes. # @@ -45,7 +45,10 @@ def gui_init @gui_element = @gui_opts[:element] || Swt::Path.new(Shoes.display) @gui_paint_callback = lambda do |event| gc = event.gc + gc.set_background self.fill.to_native + gc.fill_path(@gui_element) gc.set_antialias Swt::SWT::ON + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_path(@gui_element) end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 48c1c06d..09980bf1 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -52,14 +52,22 @@ def initialize end describe "shape" do - it "produces a Shoes::Shape" do - shape = ElementMethodsShoeLaces.new.shape do + let(:app) { ElementMethodsShoeLaces.new } + subject { + app.shape { move_to 400, 300 line_to 400, 200 line_to 100, 100 line_to 400, 300 - end - shape.should be_an_instance_of(Shoes::Shape) + } + } + + it { should be_an_instance_of(Shoes::Shape) } + + it "receives style from app" do + green = Shoes::COLORS.fetch :green + app.style[:stroke] = green + subject.stroke.should eq(green) end end diff --git a/spec/swt_shoes/shape_spec.rb b/spec/swt_shoes/shape_spec.rb index e5080ab3..65a69c71 100644 --- a/spec/swt_shoes/shape_spec.rb +++ b/spec/swt_shoes/shape_spec.rb @@ -20,13 +20,9 @@ def initialize(opts = {}, blk = nil ) let(:args_with_element) { {container: gui_container, element: gui_element} } let(:args_without_element) { {container: gui_container} } - before :each do - gui_container.should_receive(:add_paint_listener) - end - shared_examples_for "Swt::Shape" do before :each do - gui_element.stub(:move_to) + gui_container.should_receive(:add_paint_listener) end it "uses Swt and not White Shoes" do @@ -43,7 +39,6 @@ def initialize(opts = {}, blk = nil ) subject { ShapeShoeLaces.new gui: args_with_element } it_behaves_like "Swt::Shape" - end context "with gui container only" do @@ -52,10 +47,28 @@ def initialize(opts = {}, blk = nil ) it_behaves_like "Swt::Shape" describe "gui_init" do + before :each do + gui_container.should_receive(:add_paint_listener) + end + it "should not set current point on gui element" do gui_element.should_not_receive(:move_to) subject end end end + + context "basic" do + subject { + Shoes::Shape.new(gui: args_without_element) { + move_to 150, 150 + line_to 300, 300 + line_to 0, 300 + line to 150, 350 + } + } + + it_behaves_like "Swt object with stroke" + it_behaves_like "Swt object with fill" + end end From c2389b240c8fd5a6657687e1ed304e139b267f06 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Wed, 25 Apr 2012 16:12:38 -0500 Subject: [PATCH 17/23] Use Swt.display --- lib/swt_shoes.rb | 5 +---- lib/swt_shoes/color.rb | 2 +- lib/swt_shoes/shape.rb | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/swt_shoes.rb b/lib/swt_shoes.rb index de3a009d..32ca1a4e 100644 --- a/lib/swt_shoes.rb +++ b/lib/swt_shoes.rb @@ -10,6 +10,7 @@ def window(*a, &b) end require 'swt_shoes/element_methods' +require 'swt_shoes/animation' require 'swt_shoes/app' require 'swt_shoes/layout' #require 'swt_shoes/window' @@ -28,10 +29,6 @@ def self.app(opts={}, &blk) Shoes::App.new(opts, &blk) logger.debug "Exiting Shoes.app" end - - def self.display - Swt::Widgets::Display.getCurrent - end end end diff --git a/lib/swt_shoes/color.rb b/lib/swt_shoes/color.rb index 33f4b1a4..8fa707b1 100644 --- a/lib/swt_shoes/color.rb +++ b/lib/swt_shoes/color.rb @@ -1,7 +1,7 @@ module SwtShoes module Color def to_native - Swt::Graphics::Color.new(Shoes.display, @red, @green, @blue) + Swt::Graphics::Color.new(Swt.display, @red, @green, @blue) end end end diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 47666795..67e27e0e 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -42,7 +42,7 @@ def gui_init # @gui_opts should be nil if @gui_opts @gui_container = @gui_opts[:container] - @gui_element = @gui_opts[:element] || Swt::Path.new(Shoes.display) + @gui_element = @gui_opts[:element] || Swt::Path.new(Swt.display) @gui_paint_callback = lambda do |event| gc = event.gc gc.set_background self.fill.to_native From f0873942afde1f14524532374d98a216beccbdd4 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Wed, 25 Apr 2012 16:30:18 -0500 Subject: [PATCH 18/23] Animation --- lib/shoes.rb | 2 +- lib/shoes/animation.rb | 29 ++------------ lib/shoes/element_methods.rb | 2 +- lib/shoes/timer_base.rb | 24 +++++++++++- lib/swt_shoes/animation.rb | 49 ++++++++++++++++-------- lib/swt_shoes/element_methods.rb | 15 ++------ lib/white_shoes.rb | 1 + lib/white_shoes/animation.rb | 20 ++++++++++ spec/shoes/animation_spec.rb | 53 ++++++++++++++++++++++++++ spec/shoes/element_methods_spec.rb | 9 +++++ spec/swt_shoes/animation_spec.rb | 40 +++++++++++++++++++ spec/swt_shoes/element_methods_spec.rb | 1 - 12 files changed, 187 insertions(+), 58 deletions(-) create mode 100644 lib/white_shoes/animation.rb create mode 100644 spec/shoes/animation_spec.rb create mode 100644 spec/swt_shoes/animation_spec.rb diff --git a/lib/shoes.rb b/lib/shoes.rb index e21e8447..28871854 100644 --- a/lib/shoes.rb +++ b/lib/shoes.rb @@ -20,7 +20,7 @@ def self.logger require 'shoes/app' #require 'shoes/native' #require 'shoes/element_methods' -#require 'shoes/animation' +require 'shoes/animation' #require 'shoes/runnable_block' #require 'shoes/timer_base' #require 'shoes/layout' diff --git a/lib/shoes/animation.rb b/lib/shoes/animation.rb index 741b6450..4934770b 100644 --- a/lib/shoes/animation.rb +++ b/lib/shoes/animation.rb @@ -3,32 +3,9 @@ module Shoes class Animation < TimerBase - - import javax.swing.Timer - - attr_reader :jtimer - - def initialize this, fps, &blk - ms_per_frame = 1000 / fps - - if block_given? - @runnable = RunnableBlock.new(this, blk) - @jtimer = Timer.new(ms_per_frame, @runnable ) - - #@runnable.init - @jtimer.start - end + def initialize gui_container, fps, &blk + @current_frame = 0 + super gui_container, fps, &blk end - - def stop - #@runnable.stop - @jtimer.stop - end - - def start - #@runnable.start - @jtimer.start - end - end end diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 1da7fd5d..89c8ddab 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -35,7 +35,7 @@ def button(text, opts={}, &blk) end def animate(fps = 10, &blk) - anim = Shoes::Animation.new(self, fps, &blk) + animation = Shoes::Animation.new(gui_container, fps, &blk) end # similar controls as Shoes::Video (#video) diff --git a/lib/shoes/timer_base.rb b/lib/shoes/timer_base.rb index 4b6aac9c..3e9a0900 100644 --- a/lib/shoes/timer_base.rb +++ b/lib/shoes/timer_base.rb @@ -1,5 +1,25 @@ module Shoes class TimerBase - # To change this template use File | Settings | File Templates. + def initialize gui_container, fps, &blk + @gui_container, @fps, @blk = gui_container, fps, blk + @stopped = false + gui_init + end + + def start + @stopped = false + end + + def stop + @stopped = true + end + + def stopped? + @stopped + end + + def toggle + @stopped = !@stopped + end end -end \ No newline at end of file +end diff --git a/lib/swt_shoes/animation.rb b/lib/swt_shoes/animation.rb index c3c1bb94..25f01f0c 100644 --- a/lib/swt_shoes/animation.rb +++ b/lib/swt_shoes/animation.rb @@ -1,26 +1,45 @@ require 'shoes/timer_base' require 'shoes/runnable_block' -module Shoes - class Animation < TimerBase - - def initialize fps, &blk - ms_per_frame = 1000 / fps - - if block_given? - @runnable = RunnableBlock.new(ms_per_frame, blk) - - @runnable.init +module SwtShoes + module Animation + def gui_init + # Wrap the animation block so we can count frames. + # Note that the task re-calls itself on each run. + task = Proc.new do + @blk.call(@current_frame) + @current_frame += 1 + @gui_container.redraw + Swt.display.timer_exec 1000 / @fps, task end + Swt.display.timer_exec 1000 / @fps, task end - def stop - @runnable.stop + def run end + #def initialize fps, &blk + #ms_per_frame = 1000 / fps - def start - @runnable.start - end + #if block_given? + #@runnable = RunnableBlock.new(ms_per_frame, blk) + + #@runnable.init + #end + #end + #def stop + #@runnable.stop + #end + + #def start + #@runnable.start + #end + + end +end + +module Shoes + class Animation + include SwtShoes::Animation end end diff --git a/lib/swt_shoes/element_methods.rb b/lib/swt_shoes/element_methods.rb index 34ca0498..acaeb8b6 100644 --- a/lib/swt_shoes/element_methods.rb +++ b/lib/swt_shoes/element_methods.rb @@ -57,23 +57,14 @@ def line(*opts) super(*opts, args) end + # FIXME: same as #line, #shape def oval(*opts) args = opts.last.class == Hash ? opts.pop : {} - args[:gui] = { - container: self.gui_container, - paint_callback: lambda do |event, shape| - #return if hidden? - gc = event.gc - gc.set_antialias Swt::SWT::ON - gc.set_line_width shape.style[:strokewidth] - gc.setForeground(shape.style[:stroke].to_native) - gc.draw_oval(shape.left, shape.top, shape.width, shape.height) - end - } + args[:gui] = {container: self.gui_container} super(*opts, args) end - # FIXME: same as #line + # FIXME: same as #line, #oval def shape(*opts) args = opts.last.class == Hash ? opts.pop : {} args[:gui] = {container: self.gui_container} diff --git a/lib/white_shoes.rb b/lib/white_shoes.rb index 8f829d3c..4252a265 100644 --- a/lib/white_shoes.rb +++ b/lib/white_shoes.rb @@ -1,5 +1,6 @@ #require 'white_shoes/base' +require 'white_shoes/animation' require 'white_shoes/app' require 'white_shoes/flow' require 'white_shoes/button' diff --git a/lib/white_shoes/animation.rb b/lib/white_shoes/animation.rb new file mode 100644 index 00000000..402b69ef --- /dev/null +++ b/lib/white_shoes/animation.rb @@ -0,0 +1,20 @@ +module WhiteShoes + module Animation + def gui_init + # Simulate an animation thread (note: this never stops) + Thread.new do + loop do + @blk.call(@current_frame) + @current_frame += 1 + sleep(1/@fps) + end + end.start + end + end +end + +module Shoes + class Animation + include WhiteShoes::Animation + end +end diff --git a/spec/shoes/animation_spec.rb b/spec/shoes/animation_spec.rb new file mode 100644 index 00000000..2a6c2db8 --- /dev/null +++ b/spec/shoes/animation_spec.rb @@ -0,0 +1,53 @@ +require 'shoes/animation' + +describe Shoes::Animation do + let(:gui_container) { double("gui container") } + subject { Shoes::Animation.new(gui_container, 30) } + + it "defaults to started" do + subject.should_not be_stopped + end + + context "started" do + it "is not stopped" do + subject.should_not be_stopped + end + + it "stops" do + subject.stop + subject.should be_stopped + end + + it "toggles to stopped" do + subject.toggle + subject.should be_stopped + end + end + + context "stopped" do + before :each do + subject.stop + end + + it "is stopped" do + subject.should be_stopped + end + + it "starts" do + subject.start + subject.should_not be_stopped + end + + it "toggles to off" do + subject.toggle + subject.should_not be_stopped + end + end + + it "counts frames" do + counter = 0 + animation = Shoes::Animation.new(gui_container, 24) { |frame| counter += frame } + sleep(0.1) + counter.should be > 0 + end +end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 09980bf1..930ef63d 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -157,6 +157,15 @@ def initialize app.oval(10, 10, 100, 100) end end + + describe "animate" do + let(:app) { ElementMethodsShoeLaces.new } + + it "creates a Shoes::Animation" do + animation = app.animate(24) {} + animation.should be_an_instance_of(Shoes::Animation) + end + end #it "Should return 0 for left for button_one" do # @gui.elements['button_one'].left.should be 0 #end diff --git a/spec/swt_shoes/animation_spec.rb b/spec/swt_shoes/animation_spec.rb new file mode 100644 index 00000000..d193b94d --- /dev/null +++ b/spec/swt_shoes/animation_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' +require 'swt_shoes/spec_helper' + +describe SwtShoes::Animation do + class AnimationShoeLaces + include SwtShoes::Animation + def initialize(fps = 24, &blk) + @fps = fps + @blk = blk + @current_frame = 0 + gui_init + end + end + + let(:block) { Proc.new {} } + let(:display) { Swt.display } + let(:gui_container) { double(:gui_container) } + subject { AnimationShoeLaces.new &block } + + it "injects into Shoes::Animation" do + Shoes::Animation.ancestors.should include(SwtShoes::Animation) + end + + it "triggers an Swt timer" do + display.should_receive :timer_exec + subject + end + + describe "frames" do + it "counts frames" do + pending "this feature works in an app, but not in this spec. Need some creativity." + # Using a real Shoes::Animation here + animation = Shoes::Animation.new gui_container, 30 do + "no-op" + end + sleep(1) + animation.instance_variable_get(:@current_frame).should be > 1 + end + end +end diff --git a/spec/swt_shoes/element_methods_spec.rb b/spec/swt_shoes/element_methods_spec.rb index 006e65d8..e6ae4839 100644 --- a/spec/swt_shoes/element_methods_spec.rb +++ b/spec/swt_shoes/element_methods_spec.rb @@ -60,5 +60,4 @@ def initialize subject.should be_an_instance_of(Shoes::Shape) end end - end From 3c51c37d74ff88e224f45e9f979d0ed508e50d2a Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Sat, 28 Apr 2012 15:03:51 -0500 Subject: [PATCH 19/23] WIP: Move for oval, line, button --- lib/shoes/button.rb | 11 +++-- lib/shoes/common_methods.rb | 6 +++ lib/shoes/shape.rb | 42 +++++++++++++------ lib/swt_shoes/button.rb | 10 +++++ lib/swt_shoes/shape.rb | 8 ++++ spec/shoes/button_spec.rb | 12 ++++-- spec/shoes/line_spec.rb | 1 + spec/shoes/oval_spec.rb | 1 + spec/shoes/shape_spec.rb | 3 ++ .../shared_examples/common_methods_spec.rb | 7 ++++ 10 files changed, 81 insertions(+), 20 deletions(-) create mode 100644 spec/shoes/shared_examples/common_methods_spec.rb diff --git a/lib/shoes/button.rb b/lib/shoes/button.rb index 06e30cf5..b310ff36 100644 --- a/lib/shoes/button.rb +++ b/lib/shoes/button.rb @@ -1,17 +1,20 @@ +require 'shoes/common_methods' + module Shoes class Button + include Shoes::CommonMethods attr_accessor :gui_container, :click_event_lambda attr_accessor :gui_element - attr_accessor :text, :width, :height + attr_accessor :text def initialize(gui_container, text = 'Button', opts={}, click_event_lambda = nil) self.gui_container = gui_container self.click_event_lambda = click_event_lambda self.text = text - self.height = opts[:height] - self.width = opts[:width] - + @height = opts[:height] + @width = opts[:width] + gui_button_init end diff --git a/lib/shoes/common_methods.rb b/lib/shoes/common_methods.rb index 28c9b9b0..09358e27 100644 --- a/lib/shoes/common_methods.rb +++ b/lib/shoes/common_methods.rb @@ -78,6 +78,12 @@ def toggle end + # Moves an element to a specific pixel position. The element is still in the slot, + # but will no longer be stacked or flowed with the other stuff in the slot. + def move(left, top) + @left, @top = left, top + end + # displace(left: a number, top: a number) » self # Displacing an element moves it. But without changing the layout around it. def displace(left, top) diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index 954aa782..d65d22fa 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -24,14 +24,6 @@ def initialize(opts = {}, blk = nil) @blk = blk - @left = @style[:left] || 0 - @top = @style[:top] || 0 - @width = @style[:width] || 0 - @height = @style[:height] || 0 - - # Initialize current point to (left, top) - @x, @y = @left, @top - # Component shapes @components = [] @@ -43,19 +35,19 @@ def initialize(opts = {}, blk = nil) end def left - @components.map(&:left).min + @left || @components.map(&:left).min || 0 end def top - @components.map(&:top).min + @top || @components.map(&:top).min || 0 end def right - @components.map { |c| c.left + c.width }.max + @right || @components.map { |c| c.left + c.width }.max || left end def bottom - @components.map { |c| c.top + c.height }.max + @bottom || @components.map { |c| c.top + c.height }.max || top end def width @@ -65,5 +57,31 @@ def width def height (top - bottom).abs end + + # Moves the shape + # + # Moves each component so bounds calculations still work. + def move(left, top) + relative_left, relative_top = offset(left, top) + @components.each do |c| + c_left = c.left + c_top = c.top + c.move(c_left + relative_left, c_top + relative_top) + end + @left, @top, @right, @bottom = left, top, nil, nil + end + + # Gives the relative offset from the current position + # + # Returns [left, top] values that should be added to the current + # position in order to move to the new coordinate. + def offset(left, top) + relative_left = (left - self.left).abs + relative_top = (top - self.top).abs + relative_left = -relative_left if left < self.left + relative_top = -relative_top if top < self.top + [relative_left, relative_top] + end + end end diff --git a/lib/swt_shoes/button.rb b/lib/swt_shoes/button.rb index 4c4bb51d..d9f0f1f8 100644 --- a/lib/swt_shoes/button.rb +++ b/lib/swt_shoes/button.rb @@ -12,6 +12,16 @@ def gui_button_init button.pack end + def move(left, top) + super + self.gui_element.setLocation(left, top) + # FIXME: this button must be removed from it's slot's gui element, so the slot can + # re-flow properly. Currently, if you call layout() on the slot, it moves the button + # back into its original position. If you don't call layout(), the other contents + # don't reflow. + # self.gui_container.layout + end + end end diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 67e27e0e..3ef1bb80 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -45,6 +45,7 @@ def gui_init @gui_element = @gui_opts[:element] || Swt::Path.new(Swt.display) @gui_paint_callback = lambda do |event| gc = event.gc + gc.setTransform(@transform) if @transform gc.set_background self.fill.to_native gc.fill_path(@gui_element) gc.set_antialias Swt::SWT::ON @@ -65,6 +66,13 @@ def move_to(x, y) @x, @y = x, y @gui_element.move_to(x, y) end + + def move(left, top) + super + @transform.dispose if @transform + @transform = Swt::Transform.new(Swt.Display) + @transform.translate(*offset(left, top)) + end end end diff --git a/spec/shoes/button_spec.rb b/spec/shoes/button_spec.rb index 7b4b2c5c..5abbf7bd 100644 --- a/spec/shoes/button_spec.rb +++ b/spec/shoes/button_spec.rb @@ -6,16 +6,20 @@ describe Shoes::Button do - #it_should_behave_like "A Common Element" + let(:input_block) { lambda {} } + let(:input_opts) { {:width => 131, :height => 137, :margin => 143} } + subject { Shoes::Button.new("gui_container", "text", input_opts, input_block) } + + it_behaves_like "movable object" describe "initialize" do it "should set accessors" do - input_block = lambda {} - input_opts = {:width => 131, :height => 137, :margin => 143} - button = Shoes::Button.new("gui_container", "text", input_opts, input_block) + button = subject button.gui_container.should == "gui_container" button.click_event_lambda.should == input_block button.text.should == "text" + button.width.should == 131 + button.height.should == 137 end end end diff --git a/spec/shoes/line_spec.rb b/spec/shoes/line_spec.rb index 5662038a..8e398d3a 100644 --- a/spec/shoes/line_spec.rb +++ b/spec/shoes/line_spec.rb @@ -6,6 +6,7 @@ describe "basic" do subject { Shoes::Line.new(20, 23, 300, 430) } it_behaves_like "object with stroke" + it_behaves_like "movable object" end shared_examples_for "basic line" do diff --git a/spec/shoes/oval_spec.rb b/spec/shoes/oval_spec.rb index 3c728879..fe166a74 100644 --- a/spec/shoes/oval_spec.rb +++ b/spec/shoes/oval_spec.rb @@ -7,6 +7,7 @@ subject { Shoes::Oval.new(20, 30, 100, 200) } it_behaves_like "object with stroke" it_behaves_like "object with fill" + it_behaves_like "movable object" end context "(eccentric)" do diff --git a/spec/shoes/shape_spec.rb b/spec/shoes/shape_spec.rb index f5940b78..0d632d3f 100644 --- a/spec/shoes/shape_spec.rb +++ b/spec/shoes/shape_spec.rb @@ -5,6 +5,7 @@ describe Shoes::Shape do it_behaves_like "object with stroke" it_behaves_like "object with style" + it_behaves_like "movable object" describe "octagon" do let(:draw) { @@ -26,5 +27,7 @@ its(:bottom) { should eq(340) } its(:width) { should eq(240) } its(:height) { should eq(240) } + + it_behaves_like "movable object" end end diff --git a/spec/shoes/shared_examples/common_methods_spec.rb b/spec/shoes/shared_examples/common_methods_spec.rb new file mode 100644 index 00000000..ce783f80 --- /dev/null +++ b/spec/shoes/shared_examples/common_methods_spec.rb @@ -0,0 +1,7 @@ +shared_examples_for "movable object" do + it "moves" do + subject.move(300, 200) + subject.left.should eq(300) + subject.top.should eq(200) + end +end From fa7b432b98e6976cd6a6b96b76fbc328259475ac Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Thu, 10 May 2012 12:19:14 -0500 Subject: [PATCH 20/23] WIP: Adding move --- lib/shoes/app.rb | 5 ++ lib/shoes/button.rb | 1 + lib/shoes/element_methods.rb | 6 +++ lib/shoes/flow.rb | 3 +- lib/shoes/shape.rb | 1 + lib/swt_shoes/animation.rb | 2 +- lib/swt_shoes/app.rb | 1 + lib/swt_shoes/button.rb | 50 ++++++++++++++++--- lib/swt_shoes/shape.rb | 26 +++++++--- .../shared_examples/common_methods_spec.rb | 2 + spec/swt_shoes/button_spec.rb | 4 +- .../shared_examples/common_methods_spec.rb | 7 +++ 12 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 spec/swt_shoes/shared_examples/common_methods_spec.rb diff --git a/lib/shoes/app.rb b/lib/shoes/app.rb index ba6e9e8f..9ec11120 100644 --- a/lib/shoes/app.rb +++ b/lib/shoes/app.rb @@ -34,11 +34,16 @@ def initialize(opts={}, &blk) self.opts = opts + @app = self @style = DEFAULT_STYLE + puts "in app constructor, @app = #{@app}" + puts "in app constructor, @style = #{@style}" gui_init instance_eval &blk if blk + puts "in app constructor, @app = #{@app}" + puts "in app constructor, @style = #{@style}" gui_open diff --git a/lib/shoes/button.rb b/lib/shoes/button.rb index b310ff36..ea6afb0d 100644 --- a/lib/shoes/button.rb +++ b/lib/shoes/button.rb @@ -12,6 +12,7 @@ def initialize(gui_container, text = 'Button', opts={}, click_event_lambda = nil self.gui_container = gui_container self.click_event_lambda = click_event_lambda self.text = text + @app = opts[:app] @height = opts[:height] @width = opts[:width] diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 89c8ddab..a447426b 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -24,17 +24,23 @@ module ElementMethods #end def flow(opts = {}, &blk) + opts.merge! :app => @app swt_flow = Shoes::Flow.new(self, self.gui_container, opts, blk) + puts "flow gui_container: #{swt_flow.gui_container.inspect}" + puts "flow gui_container.layout: #{swt_flow.gui_container.layout.inspect}" + puts "app(?) gui_container: #{self.gui_container.inspect}" end def button(text, opts={}, &blk) + opts.merge! :app => @app button = Shoes::Button.new(self.gui_container, text, opts, blk) #@elements[button.to_s] = button #button end def animate(fps = 10, &blk) + opts.merge! :app => @app animation = Shoes::Animation.new(gui_container, fps, &blk) end diff --git a/lib/shoes/flow.rb b/lib/shoes/flow.rb index e28cabb3..c693963a 100644 --- a/lib/shoes/flow.rb +++ b/lib/shoes/flow.rb @@ -18,6 +18,7 @@ def initialize(parent_container, parent_gui_container, opts={}, blk = nil) self.width = opts['width'] self.height = opts['height'] self.margin = opts['margin'] + @app = opts['app'] self.blk = blk @@ -29,4 +30,4 @@ def initialize(parent_container, parent_gui_container, opts={}, blk = nil) end end -end \ No newline at end of file +end diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index d65d22fa..7af30fb3 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -20,6 +20,7 @@ class Shape # Implementation frameworks should pass in any required arguments # through the +opts+ hash. def initialize(opts = {}, blk = nil) + self.extend(SwtShoes::Shape) @style = Shoes::Common::Paint::DEFAULTS.merge(opts) @blk = blk diff --git a/lib/swt_shoes/animation.rb b/lib/swt_shoes/animation.rb index 25f01f0c..d427c0ea 100644 --- a/lib/swt_shoes/animation.rb +++ b/lib/swt_shoes/animation.rb @@ -9,7 +9,7 @@ def gui_init task = Proc.new do @blk.call(@current_frame) @current_frame += 1 - @gui_container.redraw + @app.gui_container.redraw unless @app.gui_container.disposed Swt.display.timer_exec 1000 / @fps, task end Swt.display.timer_exec 1000 / @fps, task diff --git a/lib/swt_shoes/app.rb b/lib/swt_shoes/app.rb index a843e607..02651422 100644 --- a/lib/swt_shoes/app.rb +++ b/lib/swt_shoes/app.rb @@ -20,6 +20,7 @@ def gui_init container.setText(self.title) container.addListener(Swt::SWT::Close, main_window_on_close) + puts "app gui_container (in app): #{self.gui_container.inspect}" end diff --git a/lib/swt_shoes/button.rb b/lib/swt_shoes/button.rb index d9f0f1f8..b9451061 100644 --- a/lib/swt_shoes/button.rb +++ b/lib/swt_shoes/button.rb @@ -13,15 +13,49 @@ def gui_button_init end def move(left, top) - super - self.gui_element.setLocation(left, top) - # FIXME: this button must be removed from it's slot's gui element, so the slot can - # re-flow properly. Currently, if you call layout() on the slot, it moves the button - # back into its original position. If you don't call layout(), the other contents - # don't reflow. - # self.gui_container.layout - end + super(left, top) + unless gui_element.is_disposed + puts "gui_element: #{gui_element.inspect}" + puts "parent: #{gui_container.inspect}" + + # This element is part of a layout, we need to pop it into its own + # composite layer before moving it, so the rest of of the elements in + # the layout can reflow. + if gui_container.get_layout + + # FIXME: we need a new gui_element for this button, that belongs to a + # different composite, with a different layout, so that it can be + # positioned. This is to pop it out of a RowLayout. But--once it's out, + # it should belong to the "whole canvas", and at that point, we don't + # need to recreate the gui element to move it. + old_gui_container = gui_container + puts "old gui_container: #{gui_container.inspect}" + puts "app gui_container: #{@app.gui_container.inspect}" + self.gui_container = Swt::Widgets::Composite.new(@app.gui_container, Swt::SWT::NONE) + puts "new gui_container: #{gui_container.inspect}" + puts "gui containers have same parent: #{self.gui_container.parent == old_gui_container.parent}" + # first attempt disposed and recreated gui_element... + gui_element.dispose + puts "disposed gui_element" + self.gui_container.set_layout nil + gui_element = Swt::Widgets::Button.new(gui_container, Swt::SWT::PUSH).tap do |button| + button.set_text(self.text) + button.add_selection_listener(self.click_event_lambda) if click_event_lambda + button.pack + end + gui_container.set_bounds(0, 0, @app.gui_container.size.x, @app.gui_container.size.y) + puts "new gui_container's children:\n #{gui_container.children.map(&:inspect).join("\n ")}" + puts "new gui_container's bounds: #{gui_container.bounds}" + puts "old gui_container's children:\n #{old_gui_container.children.map(&:inspect).join("\n ")}" + puts "app gui_container's children:\n #{@app.gui_container.children.map(&:inspect).join("\n ")}" + + old_gui_container.layout + end + gui_element.set_location left, top + gui_element.redraw + end + end end end diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 3ef1bb80..c0c53373 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -43,15 +43,19 @@ def gui_init if @gui_opts @gui_container = @gui_opts[:container] @gui_element = @gui_opts[:element] || Swt::Path.new(Swt.display) + @transform = Swt::Transform.new(Swt.display) + @transform.translate(-130, -100) @gui_paint_callback = lambda do |event| gc = event.gc - gc.setTransform(@transform) if @transform + gc.setTransform(@transform) + puts "Transform: #{@transform.inspect}" gc.set_background self.fill.to_native gc.fill_path(@gui_element) gc.set_antialias Swt::SWT::ON gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_path(@gui_element) + @transform.dispose end @gui_container.add_paint_listener(@gui_paint_callback) end @@ -68,16 +72,22 @@ def move_to(x, y) end def move(left, top) + print "Moving from (#{self.left}, #{self.top}) to " + offset_left, offset_top = offset(left, top) super + print "(#{self.left}, #{self.top}) " + puts "offset: (#{offset_left}, #{offset_top})" + puts "transform: #{@transform}" @transform.dispose if @transform - @transform = Swt::Transform.new(Swt.Display) - @transform.translate(*offset(left, top)) + @transform = Swt::Transform.new(Swt.display) + @transform.translate(offset_left, offset_top) + puts "transform: #{@transform.inspect}" end end end -module Shoes - class Shape - include SwtShoes::Shape - end -end +#module Shoes + #class Shape + #include SwtShoes::Shape + #end +#end diff --git a/spec/shoes/shared_examples/common_methods_spec.rb b/spec/shoes/shared_examples/common_methods_spec.rb index ce783f80..7e89f09d 100644 --- a/spec/shoes/shared_examples/common_methods_spec.rb +++ b/spec/shoes/shared_examples/common_methods_spec.rb @@ -3,5 +3,7 @@ subject.move(300, 200) subject.left.should eq(300) subject.top.should eq(200) + raise end end + diff --git a/spec/swt_shoes/button_spec.rb b/spec/swt_shoes/button_spec.rb index 7c0923a0..2e4f7249 100644 --- a/spec/swt_shoes/button_spec.rb +++ b/spec/swt_shoes/button_spec.rb @@ -7,7 +7,7 @@ describe SwtShoes::Button do #it_should_behave_like "A Common Element" - + it_behaves_like "movable object with disposable gui element" class ButtonShoeLaces include SwtShoes::Button @@ -72,4 +72,4 @@ class ButtonShoeLaces # end #end -end \ No newline at end of file +end diff --git a/spec/swt_shoes/shared_examples/common_methods_spec.rb b/spec/swt_shoes/shared_examples/common_methods_spec.rb new file mode 100644 index 00000000..ce9f86b3 --- /dev/null +++ b/spec/swt_shoes/shared_examples/common_methods_spec.rb @@ -0,0 +1,7 @@ +shared_examples_for "movable object with disposable gui element" do + it "disposes its gui element" do + gui_element.should_receive(:dispose) + subject.move(300, 200) + raise + end +end From 57cba1f642fee1e62ef3ffbd39f15534f5d7dea7 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Thu, 10 May 2012 16:59:07 -0500 Subject: [PATCH 21/23] Merge animate --- Gemfile | 2 +- Gemfile.lock | 34 +- README.rdoc | 8 - Rakefile | 616 +++--------------- lib/shoes.rb | 2 +- lib/shoes/animation.rb | 29 +- lib/shoes/common/paint.rb | 13 + lib/shoes/element_methods.rb | 15 +- lib/shoes/line.rb | 2 +- lib/shoes/oval.rb | 2 +- lib/shoes/shape.rb | 2 +- lib/shoes/timer_base.rb | 24 +- lib/swt_shoes.rb | 5 +- lib/swt_shoes/animation.rb | 49 +- lib/swt_shoes/color.rb | 2 +- lib/swt_shoes/element_methods.rb | 15 +- lib/swt_shoes/line.rb | 2 + lib/swt_shoes/oval.rb | 4 + lib/swt_shoes/shape.rb | 9 +- lib/white_shoes.rb | 1 + lib/white_shoes/animation.rb | 20 + spec/shoes/animation_spec.rb | 53 ++ spec/shoes/element_methods_spec.rb | 52 +- spec/shoes/line_spec.rb | 5 + spec/shoes/oval_spec.rb | 6 + .../shared_element_method_spec.rb | 25 +- spec/swt_shoes/animation_spec.rb | 40 ++ spec/swt_shoes/element_methods_spec.rb | 1 - spec/swt_shoes/line_spec.rb | 1 + spec/swt_shoes/oval_spec.rb | 13 + spec/swt_shoes/shape_spec.rb | 25 +- spec/swt_shoes/shared_examples/style_spec.rb | 43 ++ spec/swt_shoes/spec_helper.rb | 3 + 33 files changed, 475 insertions(+), 648 deletions(-) create mode 100644 lib/white_shoes/animation.rb create mode 100644 spec/shoes/animation_spec.rb create mode 100644 spec/swt_shoes/animation_spec.rb create mode 100644 spec/swt_shoes/oval_spec.rb create mode 100644 spec/swt_shoes/shared_examples/style_spec.rb diff --git a/Gemfile b/Gemfile index eabe9811..2a839904 100644 --- a/Gemfile +++ b/Gemfile @@ -33,7 +33,7 @@ group :test do end gem "gherkin" gem "cucumber" - gem "rspec", "~> 2.0" + gem "rspec" gem "rake" #gem "shoes-cucumber" end diff --git a/Gemfile.lock b/Gemfile.lock index 6750f754..9cfadd69 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,40 +3,40 @@ GEM specs: builder (3.0.0) columnize (0.3.6) - cucumber (1.1.0) + cucumber (1.1.4) builder (>= 2.1.2) diff-lcs (>= 1.1.2) - gherkin (~> 2.5.0) + gherkin (~> 2.7.1) json (>= 1.4.6) term-ansicolor (>= 1.0.6) diff-lcs (1.1.3) - facets (2.9.2) + facets (2.9.3) ffi (1.0.11) ffi (1.0.11-java) - gherkin (2.5.1) + gherkin (2.7.6) json (>= 1.4.6) - gherkin (2.5.1-java) + gherkin (2.7.6-java) json (>= 1.4.6) guard (1.0.0) ffi (>= 0.5.0) thor (~> 0.14.6) guard-rspec (0.6.0) guard (>= 0.10.0) - json (1.6.1) - json (1.6.1-java) + json (1.6.5) + json (1.6.5-java) linecache (0.46) rbx-require-relative (> 0.0.4) log4jruby (0.4.0) - rake (0.9.2) + rake (0.9.2.2) rbx-require-relative (0.0.5) - rspec (2.6.0) - rspec-core (~> 2.6.0) - rspec-expectations (~> 2.6.0) - rspec-mocks (~> 2.6.0) - rspec-core (2.6.4) - rspec-expectations (2.6.0) + rspec (2.8.0) + rspec-core (~> 2.8.0) + rspec-expectations (~> 2.8.0) + rspec-mocks (~> 2.8.0) + rspec-core (2.8.0) + rspec-expectations (2.8.0) diff-lcs (~> 1.1.2) - rspec-mocks (2.6.0) + rspec-mocks (2.8.0) ruby-debug (0.10.4) columnize (>= 0.1) ruby-debug-base (~> 0.10.4.0) @@ -44,7 +44,7 @@ GEM linecache (>= 0.3) ruby-debug-base (0.10.4-java) swt (0.12) - term-ansicolor (1.0.6) + term-ansicolor (1.0.7) thor (0.14.6) PLATFORMS @@ -59,6 +59,6 @@ DEPENDENCIES guard-rspec log4jruby rake - rspec (~> 2.0) + rspec ruby-debug swt diff --git a/README.rdoc b/README.rdoc index a66f1953..de158be7 100644 --- a/README.rdoc +++ b/README.rdoc @@ -2,14 +2,6 @@ A JRuby implementation of shoes -== Getting Started - - rvm install jruby - gem install bundler - bundle install - ./swing-shoooes testing/blank-window.rb - ./swt-shoooes testing/blank-window.rb - ==TODO: Shoes Element Skeletons: diff --git a/Rakefile b/Rakefile index cddd983a..5add12b9 100644 --- a/Rakefile +++ b/Rakefile @@ -1,532 +1,23 @@ require 'rubygems' require 'rake' -#<<<<<<< HEAD -#require 'rake/clean' -## require_relative 'platform/skel' -#require 'fileutils' -#require 'find' -#require 'yaml' -#include FileUtils -# -#APP = YAML.load_file(File.join(ENV['APP'] || ".", "app.yaml")) -#APPNAME = APP['name'] -#RELEASE_ID, RELEASE_NAME = APP['version'], APP['release'] -#NAME = APP['shortname'] || APP['name'].downcase.gsub(/\W+/, '') -#SONAME = 'shoes' -# -## Like puts, but only if we've --trace'd -#def vputs(str) -# puts str if Rake.application.options.trace -#end -# -#begin -#require 'cucumber' -#require 'cucumber/rake/task' -# -#Cucumber::Rake::Task.new(:features) do |t| -# t.cucumber_opts = "--format pretty" -#end -# -#rescue LoadError -# vputs("Cukes is not loaded -- please `bundle install`") -#end -# -#begin -# -#require 'rspec/core/rake_task' -#RSpec::Core::RakeTask.new(:spec) do |t| -# t.rspec_opts = ["--color"] -#end -# -#rescue LoadError -# vputs("RSpec is not loaded -- please `bundle install`") -#end -# -#begin -# -#require 'bundler' -#Bundler::GemHelper.install_tasks -# -#rescue LoadError -# vputs("Bundler is not loaded -- please `gem install bundler && bundle install`") -#end -# -#GIT = ENV['GIT'] || "git" -#REVISION = (`#{GIT} rev-list HEAD`.split.length + 1).to_s -#VERS = ENV['VERSION'] || "0.r#{REVISION}" -#PKG = "#{NAME}-#{VERS}" -#APPARGS = APP['run'] -#FLAGS = %w[DEBUG] -# -#BIN = "*.{bundle,jar,o,so,obj,pdb,pch,res,lib,def,exp,exe,ilk}" -#CLEAN.include ["{bin,shoes}/#{BIN}", "req/**/#{BIN}", "dist", "*.app"] -# -#RUBY_SO = Config::CONFIG['RUBY_SO_NAME'] -#RUBY_V = Config::CONFIG['ruby_version'] -#RUBY_PROGRAM_VERSION = Config::CONFIG['RUBY_PROGRAM_VERSION'] -#SHOES_RUBY_ARCH = Config::CONFIG['arch'] -# -#if ENV['APP'] -# %w[dmg icons].each do |subk| -# APP[subk].keys.each do |name| -# APP[subk][name] = File.join(ENV['APP'], APP[subk][name]) -# end -# end -#end -# -#if File.exists? ".git/refs/tags/#{RELEASE_ID}/#{RELEASE_NAME}" -# abort "** Rename this release (and add to lib/shoes.rb) #{RELEASE_NAME} has already been tagged." -#end -# -## Same effect as sourcing a shell script before running rake. It's necessary to -## set these values before the make/{platform}/env.rb files are loaded. -#def osx_bootstrap_env -# ENV['DYLD_LIBRARY_PATH'] = '/usr/local/Cellar/cairo/1.10.2/lib:/usr/local/Cellar/cairo/1.10.2/include/cairo' -# ENV['LD_LIBRARY_PATH'] = '/usr/local/Cellar/cairo/1.10.2/lib:/usr/local/Cellar/cairo/1.10.2/include/cairo' -# ENV['CAIRO_CFLAGS'] = '-I/usr/local/Cellar/cairo/1.10.2/include/cairo' -# ENV['SHOES_DEPS_PATH'] = '/usr/local' -#end -# -# -# -#case RUBY_PLATFORM -#when /mingw/ -# require File.expand_path('rakefile_mingw') -# Builder = MakeMinGW -# NAMESPACE = :win32 -#when /darwin/ -# osx_bootstrap_env -# require File.expand_path('make/darwin/env') -# require_relative "make/darwin/homebrew" -# -# task :stub do -# ENV['MACOSX_DEPLOYMENT_TARGET'] = '10.4' -# sh "gcc -O -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc -framework Cocoa -o stub platform/mac/stub.m -I." -# end -# NAMESPACE = :osx -#when /linux/ -# require File.expand_path('rakefile_linux') -# Builder = MakeLinux -# NAMESPACE = :linux -#else -# puts "Sorry, your platform [#{RUBY_PLATFORM}] is not supported..." -#end -# -## -------------------------- -## common platform tasks -# -#desc "Same as `rake build'" -#task :default => [:build] -# -#desc "Does a full compile, with installer" -#task :package => [:build, :installer] -# -#task :build_os => [:build_skel, "dist/#{NAME}"] -# -#task "shoes/version.h" do |t| -# File.open(t.name, 'w') do |f| -# f << %{#define SHOES_RELEASE_ID #{RELEASE_ID}\n#define SHOES_RELEASE_NAME "#{RELEASE_NAME}"\n#define SHOES_REVISION #{REVISION}\n#define SHOES_BUILD_DATE #{Time.now.strftime("%Y%m%d")}\n#define SHOES_PLATFORM "#{SHOES_RUBY_ARCH}"\n} -# end -#end -# -#task "dist/VERSION.txt" do |t| -# File.open(t.name, 'w') do |f| -# f << %{shoes #{RELEASE_NAME.downcase} (0.r#{REVISION}) [#{SHOES_RUBY_ARCH} Ruby#{RUBY_PROGRAM_VERSION}]} -# %w[DEBUG].each { |x| f << " +#{x.downcase}" if ENV[x] } -# f << "\n" -# end -#end -# -## shoes is small, if any include changes, go ahead and build from scratch. -#SRC.zip(OBJ).each do |c, o| -# file o => [c] + Dir["shoes/*.h"] -#end -# -## ------ -## skel -# -#def skel_replace(line) -# line.gsub! /\s+%DEFAULTS%/ do -# if APPARGS -# args = APPARGS.split(/\s+/) -# %{ -# char *default_argv[] = {argv[0], #{args.inspect[1..-2]}}; -# argv = default_argv; -# argc = #{args.length + 1}; -# } -# end -# end -# line -#end -# -## preprocess .skel -#task :build_skel do |t| -# Dir["bin/*.skel"].each do |src| -# name = src.gsub(/\.skel$/, '.c') -# File.open(src) do |skel| -# File.open(name, 'w') do |c| -# skel.each_line do |line| -# c << skel_replace(line) -# end -# end -# end -# end -#end -# -## -------------------------- -## tasks depending on Builder = MakeLinux|MakeDarwin|MakeMinGW -# -#desc "Does a full compile, for the OS you're running on" -#task :build => ["#{NAMESPACE}:build"] -# -## first refactor ; build calls platform namespaced build; -## for now, each of those calls the old build method. -#task :old_build => [:build_os, "dist/VERSION.txt"] do -# Builder.common_build -# Builder.copy_deps_to_dist -# Builder.copy_files_to_dist -# Builder.setup_system_resources -#end -# -#directory 'dist' -# -#task "dist/#{NAME}" => ["dist/lib#{SONAME}.#{DLEXT}", "bin/main.o"] + ADD_DLL + ["#{NAMESPACE}:make_app"] -# -#task "dist/lib#{SONAME}.#{DLEXT}" => ['shoes/version.h', 'dist'] + OBJ + ["#{NAMESPACE}:make_so"] -# -#def cc(t) -# sh "#{CC} -I. -c -o #{t.name} #{LINUX_CFLAGS} #{t.source}" -#end -# -#rule ".o" => ".m" do |t| -# cc t -#end -# -#rule ".o" => ".c" do |t| -# cc t -#end -# -#task :installer => ["#{NAMESPACE}:installer"] -# -#def rewrite before, after, reg = /\#\{(\w+)\}/, reg2 = '\1' -# File.open(after, 'w') do |a| -# File.open(before) do |b| -# b.each do |line| -# a << line.gsub(reg) do -# if reg2.include? '\1' -# reg2.gsub(%r!\\1!, Object.const_get($1)) -# else -# reg2 -# end -# end -# end -# end -# end -#end -# -#def copy_files glob, dir -# FileList[glob].each { |f| cp_r f, dir } -#end -# -#namespace :osx do -# namespace :deps do -# task :install => "homebrew:install" -# namespace :homebrew do -# desc "Install OS X dependencies using Homebrew" -# task :install => [:customize, :install_libs, :uncustomize] -# -# task :install_libs do -# brew = Homebrew.new -# brew.universal if ENV['SHOES_OSX_ARCH'] == "universal" -# brew.install_packages -# end -# -# task :customize do -# brew = Homebrew.new -# brew.universal if ENV['SHOES_OSX_ARCH'] == "universal" -# brew.add_custom_remote -# brew.add_custom_formulas -# end -# -# task :uncustomize do -# brew = Homebrew.new -# brew.universal if ENV['SHOES_OSX_ARCH'] == "universal" -# brew.remove_custom_formulas -# brew.remove_custom_remote -# end -# end -# end -# -# task :build => ["build_tasks:pre_build", :build_skel, "dist/#{NAME}", "dist/VERSION.txt", "build_tasks:build"] -# -# namespace :build_tasks do -# -# task :build => [:common_build, :copy_deps_to_dist, :change_install_names, :copy_files_to_dist, :setup_system_resources, :verify] -# -# # Make sure the installed ruby is capable of this build -# task :check_ruby_arch do -# build_arch, ruby_arch = [OSX_ARCH, Config::CONFIG['ARCH_FLAG']].map {|s| s.split.reject {|w| w.include?("arch")}} -# if build_arch.length > 1 and build_arch.sort != ruby_arch.sort -# abort("To build universal shoes, you must first install a universal ruby") -# end -# end -# -# task :pre_build => :check_ruby_arch -# -# def copy_ext_osx xdir, libdir -# Dir.chdir(xdir) do -# `ruby extconf.rb; make` -# end -# copy_files "#{xdir}/*.bundle", libdir -# end -# -# task :common_build do -# mkdir_p "dist/ruby" -# cp_r "#{EXT_RUBY}/lib/ruby/#{RUBY_V}", "dist/ruby/lib" -# unless ENV['STANDARD'] -# %w[soap wsdl xsd].each do |libn| -# rm_rf "dist/ruby/lib/#{libn}" -# end -# end -# %w[req/ftsearch/lib/* req/rake/lib/*].each do |rdir| -# FileList[rdir].each { |rlib| cp_r rlib, "dist/ruby/lib" } -# end -# %w[req/binject/ext/binject_c req/ftsearch/ext/ftsearchrt req/bloopsaphone/ext/bloops req/chipmunk/ext/chipmunk]. -# each { |xdir| copy_ext_osx xdir, "dist/ruby/lib/#{SHOES_RUBY_ARCH}" } -# -# gdir = "dist/ruby/gems/#{RUBY_V}" -# {'hpricot' => 'lib', 'json' => 'lib/json/ext', 'sqlite3' => 'lib'}.each do |gemn, xdir| -# spec = eval(File.read("req/#{gemn}/gemspec")) -# mkdir_p "#{gdir}/specifications" -# mkdir_p "#{gdir}/gems/#{spec.full_name}/lib" -# FileList["req/#{gemn}/lib/*"].each { |rlib| cp_r rlib, "#{gdir}/gems/#{spec.full_name}/lib" } -# mkdir_p "#{gdir}/gems/#{spec.full_name}/#{xdir}" -# FileList["req/#{gemn}/ext/*"].each { |elib| copy_ext_osx elib, "#{gdir}/gems/#{spec.full_name}/#{xdir}" } -# cp "req/#{gemn}/gemspec", "#{gdir}/specifications/#{spec.full_name}.gemspec" -# end -# end -# -# def dylibs_to_change lib -# `otool -L #{lib}`.split("\n").inject([]) do |dylibs, line| -# if line =~ /^\S/ or line =~ /System|@executable_path|libobjc/ -# dylibs -# else -# dylibs << line.gsub(/\s\(compatibility.*$/, '').strip -# end -# end -# end -# -# task :change_install_names do -# cd "dist" do -# ["#{NAME}-bin", "pango-querymodules", *Dir['*.dylib'], *Dir['pango/modules/*.so']].each do |f| -# sh "install_name_tool -id @executable_path/#{File.basename f} #{f}" -# dylibs = dylibs_to_change(f) -# dylibs.each do |dylib| -# sh "install_name_tool -change #{dylib} @executable_path/#{File.basename dylib} #{f}" -# end -# end -# end -# end -# -# task :copy_pango_modules_to_dist do -# modules_file = `brew --prefix`.chomp << '/etc/pango/pango.modules' -# modules_path = File.open(modules_file) {|f| f.grep(/^# ModulesPath = (.*)$/){$1}.first} -# mkdir_p 'dist/pango' -# cp_r modules_path, 'dist/pango' -# cp `which pango-querymodules`.chomp, 'dist/' -# end -# -# task :copy_deps_to_dist => :copy_pango_modules_to_dist do -# # Generate a list of dependencies straight from the generated files. -# # Start with dependencies of shoes-bin and pango-querymodules, and then -# # add the dependencies of those dependencies. -# dylibs = dylibs_to_change("dist/#{NAME}-bin") -# dylibs.concat dylibs_to_change("dist/pango-querymodules") -# dupes = [] -# dylibs.each do |dylib| -# dylibs_to_change(dylib).each do |d| -# if dylibs.map {|lib| File.basename(lib)}.include?(File.basename(d)) -# dupes << d -# else -# dylibs << d -# end -# end -# end -# dylibs.each {|libn| cp "#{libn}", "dist/"} -# end -# -# task :copy_files_to_dist do -# if ENV['APP'] -# if APP['clone'] -# sh APP['clone'].gsub(/^git /, "#{GIT} --git-dir=#{ENV['APP']}/.git ") -# else -# cp_r ENV['APP'], "dist/app" -# end -# if APP['ignore'] -# APP['ignore'].each do |nn| -# rm_rf "dist/app/#{nn}" -# end -# end -# end -# -# cp_r "fonts", "dist/fonts" -# cp_r "lib", "dist/lib" -# cp_r "samples", "dist/samples" -# cp_r "static", "dist/static" -# cp "README.md", "dist/README.txt" -# cp "CHANGELOG", "dist/CHANGELOG.txt" -# cp "COPYING", "dist/COPYING.txt" -# end -# -# task :setup_system_resources do -# rm_rf "#{APPNAME}.app" -# mkdir "#{APPNAME}.app" -# mkdir "#{APPNAME}.app/Contents" -# cp_r "dist", "#{APPNAME}.app/Contents/MacOS" -# mkdir "#{APPNAME}.app/Contents/Resources" -# mkdir "#{APPNAME}.app/Contents/Resources/English.lproj" -# sh "ditto \"#{APP['icons']['osx']}\" \"#{APPNAME}.app/App.icns\"" -# sh "ditto \"#{APP['icons']['osx']}\" \"#{APPNAME}.app/Contents/Resources/App.icns\"" -# rewrite "platform/mac/Info.plist", "#{APPNAME}.app/Contents/Info.plist" -# cp "platform/mac/version.plist", "#{APPNAME}.app/Contents/" -# rewrite "platform/mac/pangorc", "#{APPNAME}.app/Contents/MacOS/pangorc" -# cp "platform/mac/command-manual.rb", "#{APPNAME}.app/Contents/MacOS/" -# rewrite "platform/mac/shoes-launch", "#{APPNAME}.app/Contents/MacOS/#{NAME}-launch" -# chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}-launch" -# chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}-bin" -# rewrite "platform/mac/shoes", "#{APPNAME}.app/Contents/MacOS/#{NAME}" -# chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}" -# chmod_R 0755, "#{APPNAME}.app/Contents/MacOS/pango-querymodules" -# # cp InfoPlist.strings YourApp.app/Contents/Resources/English.lproj/ -# `echo -n 'APPL????' > "#{APPNAME}.app/Contents/PkgInfo"` -# end -# end -# -# desc "Verify the build products" -# task :verify => ['verify:sanity', 'verify:lib_paths'] -# -# namespace :verify do -# def report_error message -# STDERR.puts "BUILD ERROR: " + message -# end -# -# task :sanity do -# report_error "No #{APPNAME}.app file found" unless File.exist? "#{APPNAME}.app" -# [NAME, "#{NAME}-launch", "#{NAME}-bin"].each do |f| -# report_error "No #{f} file found" unless File.exist? "#{APPNAME}.app/Contents/MacOS/#{f}" -# end -# end -# -# task :lib_paths do -# cd "#{APPNAME}.app/Contents/MacOS" do -# errors = [] -# ["#{NAME}-bin", "pango-querymodules", *Dir['*.dylib'], *Dir['pango/modules/*.so']].each do |f| -# dylibs = dylibs_to_change(f) -# dylibs.each do |dylib| -# errors << "Suspect library path on #{f}:\n #{dylib}\n (check with `otool -L #{File.expand_path f}`)" -# end -# end -# errors.each {|e| report_error e} -# end -# end -# end -# -# task :make_app do -# # Builder.make_app "dist/#{NAME}" -# bin = "dist/#{NAME}-bin" -# rm_f "dist/#{NAME}" -# rm_f bin -# sh "#{CC} -Ldist -o #{bin} bin/main.o #{LINUX_LIBS} -lshoes #{OSX_ARCH}" -# end -# -# task :make_so do -# name = "dist/lib#{SONAME}.#{DLEXT}" -# ldflags = LINUX_LDFLAGS.sub! /INSTALL_NAME/, "-install_name @executable_path/lib#{SONAME}.#{DLEXT}" -# sh "#{CC} -o #{name} #{OBJ.join(' ')} #{LINUX_LDFLAGS} #{LINUX_LIBS}" -# %w[libpostproc.dylib libavformat.dylib libavcodec.dylib libavutil.dylib libruby.dylib].each do |libn| -# sh "install_name_tool -change /tmp/dep/lib/#{libn} ./deps/lib/#{libn} #{name}" -# end -# end -# -# task :installer do -# dmg_ds, dmg_jpg = "platform/mac/dmg_ds_store", "static/shoes-dmg.jpg" -# if APP['dmg'] -# dmg_ds, dmg_jpg = APP['dmg']['ds_store'], APP['dmg']['background'] -# end -# -# mkdir_p "pkg" -# rm_rf "dmg" -# mkdir_p "dmg" -# cp_r "#{APPNAME}.app", "dmg" -# unless ENV['APP'] -# mv "dmg/#{APPNAME}.app/Contents/MacOS/samples", "dmg/samples" -# end -# ln_s "/Applications", "dmg/Applications" -# sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/pango-querymodules" -# sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}" -# sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}-bin" -# sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}-launch" -# sh "DYLD_LIBRARY_PATH= platform/mac/pkg-dmg --target pkg/#{PKG}.dmg --source dmg --volname '#{APPNAME}' --copy #{dmg_ds}:/.DS_Store --mkdir /.background --copy #{dmg_jpg}:/.background" # --format UDRW" -# rm_rf "dmg" -# end -#end -# -#namespace :win32 do -# task :build => [:old_build] -# -# task :make_app do -# Builder.make_app "dist/#{NAME}" -# end -# -# task :make_so do -# Builder.make_so "dist/lib#{SONAME}.#{DLEXT}" -# end -# -# task :installer do -# Builder.make_installer -# end -#end -# -#namespace :linux do -# task :build => [:old_build] -# -# task :make_app do -# Builder.make_app "dist/#{NAME}" -# end -# -# task :make_so do -# Builder.make_so "dist/lib#{SONAME}.#{DLEXT}" -# end -# -# task :installer do -# Builder.make_installer -# end -#end -# -#======= -# -#begin -# require 'jeweler' -# Jeweler::Tasks.new do |gem| -# gem.name = "shoes" -# gem.summary = %Q{JRuby implementation of shoes} -# gem.description = %Q{JRuby implementation of shoes} -# gem.email = "stwerner@vt.edu" -# gem.homepage = "http://github.com/scottw/shoes" -# gem.authors = ["Scott Werner"] -# gem.add_development_dependency "rspec", ">= 1.2.9" -# gem.files.include('lib/**/*.rb') -# # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings -# end -# Jeweler::GemcutterTasks.new -#rescue LoadError -# puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler" -#end +require 'rspec' +require 'facets/hash' -require 'rspec/core/rake_task' -RSpec::Core::RakeTask.new(:spec) do |spec| - #spec.libs << 'lib' << 'spec' - spec.pattern = 'spec/**/*_spec.rb' +require 'jruby' +JRuby.runtime.instance_config.runRubyInProcess = false + +# thanks Dan Lucraft! +def jruby_run(cmd, swt = false) + opts = "-J-XstartOnFirstThread" if swt && Config::CONFIG["host_os"] =~ /darwin/ + + # see https://github.com/jruby/jruby/wiki/FAQs + # "How can I increase the heap/memory size when launching a sub-JRuby?" + sh( "jruby --debug --1.9 #{opts} -S #{cmd}" ) +end + +def rspec(files, options = "") + rspec_opts = "#{options} #{files}" + "./bin/rspec --tty #{rspec_opts}" end # run rspec in separate Jruby JVM @@ -548,18 +39,67 @@ def jruby_rspec(files, args) #return { :examples => examples_failures[1], :failures => examples_failures[2] } end -#task :spec => :check_dependencies +def spec_opts_from_args(args) + opts = args[:module] ? "-e ::#{args[:module]}" : "" +end task :default => :spec -# -#require 'rake/rdoctask' -#Rake::RDocTask.new do |rdoc| -# version = File.exist?('VERSION') ? File.read('VERSION') : "" -# -# rdoc.rdoc_dir = 'rdoc' -# rdoc.title = "shoes #{version}" -# rdoc.rdoc_files.include('README*') -# rdoc.rdoc_files.include('lib/**/*.rb') -#end -#>>>>>>> brown/master +desc "Run All Specs" +task :spec, [:module] => "spec:all" do + +end + +namespace :spec do + + + + desc "Run All Specs / All Modules" + task :default => ["spec:all"] + + desc "Run Specs on Shoes + All Frameworks + Limit the examples to specific :modules : + Animation + App + Button + Flow + + ie. $ rake spec:all[Flow] + " + task "all", [:module] do |t, args| + Rake::Task["spec:shoes"].invoke(args[:module]) + Rake::Task["spec:swing"].invoke(args[:module]) + Rake::Task["spec:swt"].invoke(args[:module]) + Rake::Task["spec:white"].invoke(args[:module]) + end + + desc "Specs for WhiteShoes Framework + Limit the examples to specific :modules : see spec:all " + task "white", [:module] do |t, args| + argh = args.to_hash + jruby_rspec("spec/white_shoes/*_spec.rb", argh) + end + + desc "Specs for Swing Framework + Limit the examples to specific :modules : see spec:all " + task "swing", [:module] do |t, args| + argh = args.to_hash + jruby_rspec("spec/swing_shoes/*_spec.rb", argh) + end + + desc "Specs for SWT Framework + Limit the examples to specific :modules : " + task "swt", [:module] do |t, args| + argh = args.to_hash + argh[:swt] = true + jruby_rspec("spec/swt_shoes/*_spec.rb", argh) + end + + desc "Specs for base Shoes libraries + Limit the examples to specific :modules : " + task "shoes", [:module] do |t, args| + argh = args.to_hash + jruby_rspec("spec/shoes/*_spec.rb", argh) + end + +end diff --git a/lib/shoes.rb b/lib/shoes.rb index e21e8447..28871854 100644 --- a/lib/shoes.rb +++ b/lib/shoes.rb @@ -20,7 +20,7 @@ def self.logger require 'shoes/app' #require 'shoes/native' #require 'shoes/element_methods' -#require 'shoes/animation' +require 'shoes/animation' #require 'shoes/runnable_block' #require 'shoes/timer_base' #require 'shoes/layout' diff --git a/lib/shoes/animation.rb b/lib/shoes/animation.rb index 741b6450..4934770b 100644 --- a/lib/shoes/animation.rb +++ b/lib/shoes/animation.rb @@ -3,32 +3,9 @@ module Shoes class Animation < TimerBase - - import javax.swing.Timer - - attr_reader :jtimer - - def initialize this, fps, &blk - ms_per_frame = 1000 / fps - - if block_given? - @runnable = RunnableBlock.new(this, blk) - @jtimer = Timer.new(ms_per_frame, @runnable ) - - #@runnable.init - @jtimer.start - end + def initialize gui_container, fps, &blk + @current_frame = 0 + super gui_container, fps, &blk end - - def stop - #@runnable.stop - @jtimer.stop - end - - def start - #@runnable.start - @jtimer.start - end - end end diff --git a/lib/shoes/common/paint.rb b/lib/shoes/common/paint.rb index 91ac5a2b..68055fe6 100644 --- a/lib/shoes/common/paint.rb +++ b/lib/shoes/common/paint.rb @@ -1,6 +1,11 @@ module Shoes module Common module Paint + DEFAULTS = { + :stroke => Shoes::COLORS[:black], + :fill => Shoes::COLORS[:black] + } + def stroke @style[:stroke] end @@ -8,6 +13,14 @@ def stroke def stroke=(color) @style[:stroke] = color end + + def fill + @style[:fill] + end + + def fill=(color) + @style[:fill] = color + end end end end diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 06a85473..89c8ddab 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -35,7 +35,7 @@ def button(text, opts={}, &blk) end def animate(fps = 10, &blk) - anim = Shoes::Animation.new(self, fps, &blk) + animation = Shoes::Animation.new(gui_container, fps, &blk) end # similar controls as Shoes::Video (#video) @@ -88,8 +88,8 @@ def oval(*opts) end # Creates a new Shoes::Shape object - def shape(style={}, &blk) - Shoes::Shape.new(style, blk) + def shape(shape_style={}, &blk) + Shoes::Shape.new(style.merge(shape_style), blk) end # Creates a new Shoes::Color object @@ -111,6 +111,15 @@ def strokewidth(width) @style[:strokewidth] = width end + # Sets the current fill color + # + # Arguments + # + # color - a Shoes::Color + def fill(color) + @style[:fill] = color + end + # Adds style, or just returns current style if no argument # # Returns the updated style diff --git a/lib/shoes/line.rb b/lib/shoes/line.rb index b1926009..bc03bddd 100644 --- a/lib/shoes/line.rb +++ b/lib/shoes/line.rb @@ -14,7 +14,7 @@ def initialize(x1, y1, x2, y2, opts = {}) @width = (x1 - x2).abs @height = (y1 - y2).abs - @style = opts + @style = Shoes::Common::Paint::DEFAULTS.merge(opts) # GUI @gui_opts = @style.delete(:gui) diff --git a/lib/shoes/oval.rb b/lib/shoes/oval.rb index 143b35ed..958c9ddf 100644 --- a/lib/shoes/oval.rb +++ b/lib/shoes/oval.rb @@ -17,7 +17,7 @@ def initialize(*opts) when 3; @style[:left], @style[:top], @style[:radius] = opts else @style[:left], @style[:top], @style[:width], @style[:height] = opts end - @style = defaults.merge(@style) + @style = Shoes::Common::Paint::DEFAULTS.merge(defaults).merge(@style) @left = @style[:left] @top = @style[:top] @width = @style[:width] diff --git a/lib/shoes/shape.rb b/lib/shoes/shape.rb index 125e56c5..954aa782 100644 --- a/lib/shoes/shape.rb +++ b/lib/shoes/shape.rb @@ -20,7 +20,7 @@ class Shape # Implementation frameworks should pass in any required arguments # through the +opts+ hash. def initialize(opts = {}, blk = nil) - @style = opts + @style = Shoes::Common::Paint::DEFAULTS.merge(opts) @blk = blk diff --git a/lib/shoes/timer_base.rb b/lib/shoes/timer_base.rb index 4b6aac9c..3e9a0900 100644 --- a/lib/shoes/timer_base.rb +++ b/lib/shoes/timer_base.rb @@ -1,5 +1,25 @@ module Shoes class TimerBase - # To change this template use File | Settings | File Templates. + def initialize gui_container, fps, &blk + @gui_container, @fps, @blk = gui_container, fps, blk + @stopped = false + gui_init + end + + def start + @stopped = false + end + + def stop + @stopped = true + end + + def stopped? + @stopped + end + + def toggle + @stopped = !@stopped + end end -end \ No newline at end of file +end diff --git a/lib/swt_shoes.rb b/lib/swt_shoes.rb index de3a009d..32ca1a4e 100644 --- a/lib/swt_shoes.rb +++ b/lib/swt_shoes.rb @@ -10,6 +10,7 @@ def window(*a, &b) end require 'swt_shoes/element_methods' +require 'swt_shoes/animation' require 'swt_shoes/app' require 'swt_shoes/layout' #require 'swt_shoes/window' @@ -28,10 +29,6 @@ def self.app(opts={}, &blk) Shoes::App.new(opts, &blk) logger.debug "Exiting Shoes.app" end - - def self.display - Swt::Widgets::Display.getCurrent - end end end diff --git a/lib/swt_shoes/animation.rb b/lib/swt_shoes/animation.rb index c3c1bb94..25f01f0c 100644 --- a/lib/swt_shoes/animation.rb +++ b/lib/swt_shoes/animation.rb @@ -1,26 +1,45 @@ require 'shoes/timer_base' require 'shoes/runnable_block' -module Shoes - class Animation < TimerBase - - def initialize fps, &blk - ms_per_frame = 1000 / fps - - if block_given? - @runnable = RunnableBlock.new(ms_per_frame, blk) - - @runnable.init +module SwtShoes + module Animation + def gui_init + # Wrap the animation block so we can count frames. + # Note that the task re-calls itself on each run. + task = Proc.new do + @blk.call(@current_frame) + @current_frame += 1 + @gui_container.redraw + Swt.display.timer_exec 1000 / @fps, task end + Swt.display.timer_exec 1000 / @fps, task end - def stop - @runnable.stop + def run end + #def initialize fps, &blk + #ms_per_frame = 1000 / fps - def start - @runnable.start - end + #if block_given? + #@runnable = RunnableBlock.new(ms_per_frame, blk) + + #@runnable.init + #end + #end + #def stop + #@runnable.stop + #end + + #def start + #@runnable.start + #end + + end +end + +module Shoes + class Animation + include SwtShoes::Animation end end diff --git a/lib/swt_shoes/color.rb b/lib/swt_shoes/color.rb index 33f4b1a4..8fa707b1 100644 --- a/lib/swt_shoes/color.rb +++ b/lib/swt_shoes/color.rb @@ -1,7 +1,7 @@ module SwtShoes module Color def to_native - Swt::Graphics::Color.new(Shoes.display, @red, @green, @blue) + Swt::Graphics::Color.new(Swt.display, @red, @green, @blue) end end end diff --git a/lib/swt_shoes/element_methods.rb b/lib/swt_shoes/element_methods.rb index 34ca0498..acaeb8b6 100644 --- a/lib/swt_shoes/element_methods.rb +++ b/lib/swt_shoes/element_methods.rb @@ -57,23 +57,14 @@ def line(*opts) super(*opts, args) end + # FIXME: same as #line, #shape def oval(*opts) args = opts.last.class == Hash ? opts.pop : {} - args[:gui] = { - container: self.gui_container, - paint_callback: lambda do |event, shape| - #return if hidden? - gc = event.gc - gc.set_antialias Swt::SWT::ON - gc.set_line_width shape.style[:strokewidth] - gc.setForeground(shape.style[:stroke].to_native) - gc.draw_oval(shape.left, shape.top, shape.width, shape.height) - end - } + args[:gui] = {container: self.gui_container} super(*opts, args) end - # FIXME: same as #line + # FIXME: same as #line, #oval def shape(*opts) args = opts.last.class == Hash ? opts.pop : {} args[:gui] = {container: self.gui_container} diff --git a/lib/swt_shoes/line.rb b/lib/swt_shoes/line.rb index 80c495cc..4ac55482 100644 --- a/lib/swt_shoes/line.rb +++ b/lib/swt_shoes/line.rb @@ -1,6 +1,7 @@ module SwtShoes module Line attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback def gui_init # @gui_opts must be provided if this shape is responsible for @@ -11,6 +12,7 @@ def gui_init default_paint_callback = lambda do |event| gc = event.gc gc.set_antialias Swt::SWT::ON + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_line(@left, @top, right, bottom) end diff --git a/lib/swt_shoes/oval.rb b/lib/swt_shoes/oval.rb index fe0bcc9c..6ab26fa3 100644 --- a/lib/swt_shoes/oval.rb +++ b/lib/swt_shoes/oval.rb @@ -1,6 +1,7 @@ module SwtShoes module Oval attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback # FIXME: This (mostly) duplicates SwtShoes::Line#gui_init def gui_init @@ -12,6 +13,9 @@ def gui_init @gui_paint_callback = lambda do |event| gc = event.gc gc.set_antialias Swt::SWT::ON + gc.set_background self.fill.to_native + gc.fill_oval(@left, @top, @width, @height) + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_oval(@left, @top, @width, @height) end diff --git a/lib/swt_shoes/shape.rb b/lib/swt_shoes/shape.rb index 0b315d36..67e27e0e 100644 --- a/lib/swt_shoes/shape.rb +++ b/lib/swt_shoes/shape.rb @@ -8,8 +8,8 @@ module SwtShoes # @opts - options # module Shape - attr_reader :gui_container - attr_reader :gui_element + attr_reader :gui_container, :gui_element + attr_reader :gui_paint_callback # The initialization hook for SwtShoes. # @@ -42,10 +42,13 @@ def gui_init # @gui_opts should be nil if @gui_opts @gui_container = @gui_opts[:container] - @gui_element = @gui_opts[:element] || Swt::Path.new(Shoes.display) + @gui_element = @gui_opts[:element] || Swt::Path.new(Swt.display) @gui_paint_callback = lambda do |event| gc = event.gc + gc.set_background self.fill.to_native + gc.fill_path(@gui_element) gc.set_antialias Swt::SWT::ON + gc.set_foreground self.stroke.to_native gc.set_line_width self.style[:strokewidth] gc.draw_path(@gui_element) end diff --git a/lib/white_shoes.rb b/lib/white_shoes.rb index 8f829d3c..4252a265 100644 --- a/lib/white_shoes.rb +++ b/lib/white_shoes.rb @@ -1,5 +1,6 @@ #require 'white_shoes/base' +require 'white_shoes/animation' require 'white_shoes/app' require 'white_shoes/flow' require 'white_shoes/button' diff --git a/lib/white_shoes/animation.rb b/lib/white_shoes/animation.rb new file mode 100644 index 00000000..402b69ef --- /dev/null +++ b/lib/white_shoes/animation.rb @@ -0,0 +1,20 @@ +module WhiteShoes + module Animation + def gui_init + # Simulate an animation thread (note: this never stops) + Thread.new do + loop do + @blk.call(@current_frame) + @current_frame += 1 + sleep(1/@fps) + end + end.start + end + end +end + +module Shoes + class Animation + include WhiteShoes::Animation + end +end diff --git a/spec/shoes/animation_spec.rb b/spec/shoes/animation_spec.rb new file mode 100644 index 00000000..2a6c2db8 --- /dev/null +++ b/spec/shoes/animation_spec.rb @@ -0,0 +1,53 @@ +require 'shoes/animation' + +describe Shoes::Animation do + let(:gui_container) { double("gui container") } + subject { Shoes::Animation.new(gui_container, 30) } + + it "defaults to started" do + subject.should_not be_stopped + end + + context "started" do + it "is not stopped" do + subject.should_not be_stopped + end + + it "stops" do + subject.stop + subject.should be_stopped + end + + it "toggles to stopped" do + subject.toggle + subject.should be_stopped + end + end + + context "stopped" do + before :each do + subject.stop + end + + it "is stopped" do + subject.should be_stopped + end + + it "starts" do + subject.start + subject.should_not be_stopped + end + + it "toggles to off" do + subject.toggle + subject.should_not be_stopped + end + end + + it "counts frames" do + counter = 0 + animation = Shoes::Animation.new(gui_container, 24) { |frame| counter += frame } + sleep(0.1) + counter.should be > 0 + end +end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 0ec1c5e1..930ef63d 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -1,4 +1,5 @@ require_relative 'spec_helper' +require "shoes/color" require 'shoes/element_methods' require 'shoes/configuration' @@ -51,14 +52,22 @@ def initialize end describe "shape" do - it "produces a Shoes::Shape" do - shape = ElementMethodsShoeLaces.new.shape do + let(:app) { ElementMethodsShoeLaces.new } + subject { + app.shape { move_to 400, 300 line_to 400, 200 line_to 100, 100 line_to 400, 300 - end - shape.should be_an_instance_of(Shoes::Shape) + } + } + + it { should be_an_instance_of(Shoes::Shape) } + + it "receives style from app" do + green = Shoes::COLORS.fetch :green + app.style[:stroke] = green + subject.stroke.should eq(green) end end @@ -81,9 +90,8 @@ def initialize end describe "stroke" do - require "shoes/color" # Need the colors! let(:app) { ElementMethodsShoeLaces.new } - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do app.stroke(color).class.should eq(Shoes::Color) @@ -126,6 +134,38 @@ def initialize end end + describe "fill" do + let(:app) { ElementMethodsShoeLaces.new } + let(:color) { Shoes::COLORS.fetch :tomato } + + specify "returns a color" do + app.fill(color).class.should eq(Shoes::Color) + end + + # This works differently on the app than on a normal element + specify "sets on receiver" do + app.fill color + app.style[:fill].should eq(color) + end + + specify "applies to subsequently created objects" do + app.fill color + Shoes::Oval.should_receive(:new).with do |*args| + style = args.pop + style[:fill].should eq(color) + end + app.oval(10, 10, 100, 100) + end + end + + describe "animate" do + let(:app) { ElementMethodsShoeLaces.new } + + it "creates a Shoes::Animation" do + animation = app.animate(24) {} + animation.should be_an_instance_of(Shoes::Animation) + end + end #it "Should return 0 for left for button_one" do # @gui.elements['button_one'].left.should be 0 #end diff --git a/spec/shoes/line_spec.rb b/spec/shoes/line_spec.rb index 6cd430b3..5662038a 100644 --- a/spec/shoes/line_spec.rb +++ b/spec/shoes/line_spec.rb @@ -3,6 +3,11 @@ require 'white_shoes' describe Shoes::Line do + describe "basic" do + subject { Shoes::Line.new(20, 23, 300, 430) } + it_behaves_like "object with stroke" + end + shared_examples_for "basic line" do it { should be_kind_of(Shoes::Line) } its(:top) { should eq(15) } diff --git a/spec/shoes/oval_spec.rb b/spec/shoes/oval_spec.rb index 04c2dfae..3c728879 100644 --- a/spec/shoes/oval_spec.rb +++ b/spec/shoes/oval_spec.rb @@ -3,6 +3,12 @@ require 'white_shoes' describe Shoes::Oval do + describe "basic" do + subject { Shoes::Oval.new(20, 30, 100, 200) } + it_behaves_like "object with stroke" + it_behaves_like "object with fill" + end + context "(eccentric)" do subject { Shoes::Oval.new(20, 30, 100, 200) } diff --git a/spec/shoes/shared_examples/shared_element_method_spec.rb b/spec/shoes/shared_examples/shared_element_method_spec.rb index 399964e8..983f6dfd 100644 --- a/spec/shoes/shared_examples/shared_element_method_spec.rb +++ b/spec/shoes/shared_examples/shared_element_method_spec.rb @@ -1,7 +1,7 @@ require 'shoes/color' shared_examples_for "object with stroke" do - let(:color) { Shoes::COLORS[:tomato] } + let(:color) { Shoes::COLORS.fetch :tomato } specify "returns a color" do c = subject.stroke = color @@ -13,6 +13,29 @@ subject.stroke.should eq(color) subject.style[:stroke].should eq(color) end + + # Be sure the subject does *not* have the stroke set previously + specify "defaults to black" do + subject.stroke.should eq(Shoes::COLORS.fetch :black) + end end +shared_examples_for "object with fill" do + let(:color) { Shoes::COLORS.fetch :honeydew } + + specify "returns a color" do + c = subject.fill = color + c.class.should eq(Shoes::Color) + end + specify "sets on receiver" do + subject.fill = color + subject.fill.should eq(color) + subject.style[:fill].should eq(color) + end + + # Be sure the subject does *not* have the stroke set previously + specify "defaults to black" do + subject.fill.should eq(Shoes::COLORS.fetch :black) + end +end diff --git a/spec/swt_shoes/animation_spec.rb b/spec/swt_shoes/animation_spec.rb new file mode 100644 index 00000000..d193b94d --- /dev/null +++ b/spec/swt_shoes/animation_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' +require 'swt_shoes/spec_helper' + +describe SwtShoes::Animation do + class AnimationShoeLaces + include SwtShoes::Animation + def initialize(fps = 24, &blk) + @fps = fps + @blk = blk + @current_frame = 0 + gui_init + end + end + + let(:block) { Proc.new {} } + let(:display) { Swt.display } + let(:gui_container) { double(:gui_container) } + subject { AnimationShoeLaces.new &block } + + it "injects into Shoes::Animation" do + Shoes::Animation.ancestors.should include(SwtShoes::Animation) + end + + it "triggers an Swt timer" do + display.should_receive :timer_exec + subject + end + + describe "frames" do + it "counts frames" do + pending "this feature works in an app, but not in this spec. Need some creativity." + # Using a real Shoes::Animation here + animation = Shoes::Animation.new gui_container, 30 do + "no-op" + end + sleep(1) + animation.instance_variable_get(:@current_frame).should be > 1 + end + end +end diff --git a/spec/swt_shoes/element_methods_spec.rb b/spec/swt_shoes/element_methods_spec.rb index 006e65d8..e6ae4839 100644 --- a/spec/swt_shoes/element_methods_spec.rb +++ b/spec/swt_shoes/element_methods_spec.rb @@ -60,5 +60,4 @@ def initialize subject.should be_an_instance_of(Shoes::Shape) end end - end diff --git a/spec/swt_shoes/line_spec.rb b/spec/swt_shoes/line_spec.rb index e0a418bb..32125289 100644 --- a/spec/swt_shoes/line_spec.rb +++ b/spec/swt_shoes/line_spec.rb @@ -28,4 +28,5 @@ end it_behaves_like "paintable" + it_behaves_like "Swt object with stroke" end diff --git a/spec/swt_shoes/oval_spec.rb b/spec/swt_shoes/oval_spec.rb new file mode 100644 index 00000000..9b840ba6 --- /dev/null +++ b/spec/swt_shoes/oval_spec.rb @@ -0,0 +1,13 @@ +describe SwtShoes::Oval do + let(:gui_container) { double("gui container") } + let(:opts) { {:gui => {:container => gui_container}} } + + subject { + Shoes::Oval.new(10, 15, 100, opts) + } + + it_behaves_like "paintable" + it_behaves_like "Swt object with stroke" + it_behaves_like "Swt object with fill" +end + diff --git a/spec/swt_shoes/shape_spec.rb b/spec/swt_shoes/shape_spec.rb index e5080ab3..65a69c71 100644 --- a/spec/swt_shoes/shape_spec.rb +++ b/spec/swt_shoes/shape_spec.rb @@ -20,13 +20,9 @@ def initialize(opts = {}, blk = nil ) let(:args_with_element) { {container: gui_container, element: gui_element} } let(:args_without_element) { {container: gui_container} } - before :each do - gui_container.should_receive(:add_paint_listener) - end - shared_examples_for "Swt::Shape" do before :each do - gui_element.stub(:move_to) + gui_container.should_receive(:add_paint_listener) end it "uses Swt and not White Shoes" do @@ -43,7 +39,6 @@ def initialize(opts = {}, blk = nil ) subject { ShapeShoeLaces.new gui: args_with_element } it_behaves_like "Swt::Shape" - end context "with gui container only" do @@ -52,10 +47,28 @@ def initialize(opts = {}, blk = nil ) it_behaves_like "Swt::Shape" describe "gui_init" do + before :each do + gui_container.should_receive(:add_paint_listener) + end + it "should not set current point on gui element" do gui_element.should_not_receive(:move_to) subject end end end + + context "basic" do + subject { + Shoes::Shape.new(gui: args_without_element) { + move_to 150, 150 + line_to 300, 300 + line_to 0, 300 + line to 150, 350 + } + } + + it_behaves_like "Swt object with stroke" + it_behaves_like "Swt object with fill" + end end diff --git a/spec/swt_shoes/shared_examples/style_spec.rb b/spec/swt_shoes/shared_examples/style_spec.rb new file mode 100644 index 00000000..45624e78 --- /dev/null +++ b/spec/swt_shoes/shared_examples/style_spec.rb @@ -0,0 +1,43 @@ +shared_examples_for "Swt object with stroke" do + describe "paint callback" do + let(:event) { double("event") } + let(:gc) { double("gc").as_null_object } + + before :each do + event.stub(:gc) { gc } + gui_container.should_receive(:add_paint_listener) + end + + specify "sets stroke color" do + gc.should_receive(:set_foreground).with(subject.stroke.to_native) + subject.gui_paint_callback.call(event) + end + + specify "sets antialias" do + gc.should_receive(:set_antialias).with(Swt::SWT::ON) + subject.gui_paint_callback.call(event) + end + + specify "sets strokewidth" do + gc.should_receive(:set_line_width).with(subject.style[:strokewidth]) + subject.gui_paint_callback.call(event) + end + end +end + +shared_examples_for "Swt object with fill" do + describe "paint callback" do + let(:event) { double("event") } + let(:gc) { double("gc").as_null_object } + + before :each do + event.stub(:gc) { gc } + gui_container.should_receive(:add_paint_listener) + end + + specify "sets fill color" do + gc.should_receive(:set_background).with(subject.fill.to_native) + subject.gui_paint_callback.call(event) + end + end +end diff --git a/spec/swt_shoes/spec_helper.rb b/spec/swt_shoes/spec_helper.rb index 1e91dd31..b9431cab 100644 --- a/spec/swt_shoes/spec_helper.rb +++ b/spec/swt_shoes/spec_helper.rb @@ -1,2 +1,5 @@ require "swt_shoes" Shoes.configuration.framework = 'swt_shoes' + +shared_examples = File.join(File.dirname(__FILE__), 'shared_examples', '**/*.rb') +Dir[shared_examples].each { |f| require f } From 7583d81cdfa2f8183860ac568980a6818ed6196d Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Fri, 11 May 2012 08:47:50 -0500 Subject: [PATCH 22/23] Add hash arg to Shoes::Animate --- lib/shoes/animation.rb | 22 ++++++++++++++++++++-- lib/shoes/element_methods.rb | 23 +++++++++++++++++++++-- lib/shoes/timer_base.rb | 5 +++-- lib/swt_shoes/animation.rb | 4 ++-- lib/white_shoes/animation.rb | 2 +- spec/shoes/element_methods_spec.rb | 25 ++++++++++++++++++++++--- spec/swt_shoes/animation_spec.rb | 7 +++++-- 7 files changed, 74 insertions(+), 14 deletions(-) diff --git a/lib/shoes/animation.rb b/lib/shoes/animation.rb index 4934770b..1a86a93e 100644 --- a/lib/shoes/animation.rb +++ b/lib/shoes/animation.rb @@ -3,9 +3,27 @@ module Shoes class Animation < TimerBase - def initialize gui_container, fps, &blk + + # Creates a new Animation. + # + # Arguments + # + # gui_container - The gui element that is the parent of this animation + # opts - Either an integer, representing the framerate (frames per + # second) of the animation, or a Hash of options. Right now, + # framerate is the only supported option. If no framerate + # is provided, the default is 24. + # blk - A block of code to be executed for each frame of the + # animation. + # + def initialize gui_container, *opts, &blk @current_frame = 0 - super gui_container, fps, &blk + @style = opts.last.class == Hash ? opts.pop : {} + @style[:framerate] = opts.first if opts.length == 1 + @framerate = @style[:framerate] || 24 + super gui_container, opts, &blk end + + attr_reader :framerate end end diff --git a/lib/shoes/element_methods.rb b/lib/shoes/element_methods.rb index 89c8ddab..ba966c68 100644 --- a/lib/shoes/element_methods.rb +++ b/lib/shoes/element_methods.rb @@ -34,8 +34,27 @@ def button(text, opts={}, &blk) #button end - def animate(fps = 10, &blk) - animation = Shoes::Animation.new(gui_container, fps, &blk) + # Creates an animation that runs the given block of code. + # + # Signatures + # + # # Defaults to framerate of 24 frames per second + # animate do + # # animation code + # end + # + # # Uses a framerate of 10 frames per second + # animate 10 do + # # animation code + # end + # + # # Uses a framerate of 10 frames per second + # animate :framerate => 10 do + # # animation code + # end + # + def animate(opts = {}, &blk) + animation = Shoes::Animation.new(gui_container, opts, &blk) end # similar controls as Shoes::Video (#video) diff --git a/lib/shoes/timer_base.rb b/lib/shoes/timer_base.rb index 3e9a0900..a06a9c21 100644 --- a/lib/shoes/timer_base.rb +++ b/lib/shoes/timer_base.rb @@ -1,7 +1,8 @@ module Shoes class TimerBase - def initialize gui_container, fps, &blk - @gui_container, @fps, @blk = gui_container, fps, blk + def initialize gui_container, opts, &blk + @gui_container = gui_container + @blk = blk @stopped = false gui_init end diff --git a/lib/swt_shoes/animation.rb b/lib/swt_shoes/animation.rb index 25f01f0c..550f7423 100644 --- a/lib/swt_shoes/animation.rb +++ b/lib/swt_shoes/animation.rb @@ -10,9 +10,9 @@ def gui_init @blk.call(@current_frame) @current_frame += 1 @gui_container.redraw - Swt.display.timer_exec 1000 / @fps, task + Swt.display.timer_exec 1000 / @framerate, task end - Swt.display.timer_exec 1000 / @fps, task + Swt.display.timer_exec 1000 / @framerate, task end def run diff --git a/lib/white_shoes/animation.rb b/lib/white_shoes/animation.rb index 402b69ef..949a9b71 100644 --- a/lib/white_shoes/animation.rb +++ b/lib/white_shoes/animation.rb @@ -6,7 +6,7 @@ def gui_init loop do @blk.call(@current_frame) @current_frame += 1 - sleep(1/@fps) + sleep(1/@framerate) end end.start end diff --git a/spec/shoes/element_methods_spec.rb b/spec/shoes/element_methods_spec.rb index 930ef63d..1c7f6412 100644 --- a/spec/shoes/element_methods_spec.rb +++ b/spec/shoes/element_methods_spec.rb @@ -161,9 +161,28 @@ def initialize describe "animate" do let(:app) { ElementMethodsShoeLaces.new } - it "creates a Shoes::Animation" do - animation = app.animate(24) {} - animation.should be_an_instance_of(Shoes::Animation) + shared_examples_for "basic" do + it { should be_an_instance_of(Shoes::Animation) } + end + + shared_examples_for "10fps" do + its(:framerate) { should eq(10) } + end + + context "defaults" do + subject { app.animate {} } + it_behaves_like "basic" + its(:framerate) { should eq(24) } + end + + context "with numeric argument" do + subject { app.animate(10) {} } + it_behaves_like "basic" + it_behaves_like "10fps" + end + + context "with hash argument" do + end end #it "Should return 0 for left for button_one" do diff --git a/spec/swt_shoes/animation_spec.rb b/spec/swt_shoes/animation_spec.rb index d193b94d..024a8cf3 100644 --- a/spec/swt_shoes/animation_spec.rb +++ b/spec/swt_shoes/animation_spec.rb @@ -4,8 +4,11 @@ describe SwtShoes::Animation do class AnimationShoeLaces include SwtShoes::Animation - def initialize(fps = 24, &blk) - @fps = fps + # This is painfully duplicated from Shoes::Animation + def initialize(*opts, &blk) + @style = opts.last.class == Hash ? opts.pop : {} + @style[:framerate] = opts.first if opts.length == 1 + @framerate = @style[:framerate] || 24 @blk = blk @current_frame = 0 gui_init From 9767efdf7c738306f14d3e674651261971e3978d Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Fri, 11 May 2012 12:48:05 -0500 Subject: [PATCH 23/23] Finish adding move This adds move for Shape, Oval, and Button. Shoes-level implementation and an SWT gui implementation. Oval is straghtforward. Shape is somewhat complicated because it moves all elements of the shape. I believe this is a correct, but not optimized implementation. Button is also complicated because Buttons can be laid out in slots. The Button is removed from the slot's layout, so the remaining elements can reflow. The Button's gui element is disposed, and a new gui element is created and added to a new Swt::Composite layer so it is out of the layout flow. This only happens on the first move. Once the Button is in a container without a layout, it continues to use the same gui element. * Add NO_BACKGROUND so layers are transparent. This applies to all flow objects * Adjust framerate to approach Red Shoes. It's still not a perfect match, but it's closer. * Add new working sample: simple-move.rb --- lib/shoes/animation.rb | 2 +- lib/shoes/app.rb | 4 -- lib/shoes/timer_base.rb | 1 + lib/swt_shoes/animation.rb | 6 +-- lib/swt_shoes/app.rb | 1 - lib/swt_shoes/button.rb | 40 +++++-------------- lib/swt_shoes/flow.rb | 2 +- samples/working-swt/simple-move.rb | 1 + spec/swt_shoes/button_spec.rb | 23 ++++++++--- .../shared_examples/common_methods_spec.rb | 8 +++- 10 files changed, 42 insertions(+), 46 deletions(-) create mode 120000 samples/working-swt/simple-move.rb diff --git a/lib/shoes/animation.rb b/lib/shoes/animation.rb index 1a86a93e..fa041ade 100644 --- a/lib/shoes/animation.rb +++ b/lib/shoes/animation.rb @@ -21,7 +21,7 @@ def initialize gui_container, *opts, &blk @style = opts.last.class == Hash ? opts.pop : {} @style[:framerate] = opts.first if opts.length == 1 @framerate = @style[:framerate] || 24 - super gui_container, opts, &blk + super gui_container, @style, &blk end attr_reader :framerate diff --git a/lib/shoes/app.rb b/lib/shoes/app.rb index 9ec11120..4dff2e41 100644 --- a/lib/shoes/app.rb +++ b/lib/shoes/app.rb @@ -36,14 +36,10 @@ def initialize(opts={}, &blk) @app = self @style = DEFAULT_STYLE - puts "in app constructor, @app = #{@app}" - puts "in app constructor, @style = #{@style}" gui_init instance_eval &blk if blk - puts "in app constructor, @app = #{@app}" - puts "in app constructor, @style = #{@style}" gui_open diff --git a/lib/shoes/timer_base.rb b/lib/shoes/timer_base.rb index a06a9c21..bc2d2947 100644 --- a/lib/shoes/timer_base.rb +++ b/lib/shoes/timer_base.rb @@ -3,6 +3,7 @@ class TimerBase def initialize gui_container, opts, &blk @gui_container = gui_container @blk = blk + @app = opts[:app] @stopped = false gui_init end diff --git a/lib/swt_shoes/animation.rb b/lib/swt_shoes/animation.rb index 550f7423..c5fb19da 100644 --- a/lib/swt_shoes/animation.rb +++ b/lib/swt_shoes/animation.rb @@ -9,10 +9,10 @@ def gui_init task = Proc.new do @blk.call(@current_frame) @current_frame += 1 - @gui_container.redraw - Swt.display.timer_exec 1000 / @framerate, task + @app.gui_container.redraw + Swt.display.timer_exec (2000 / @framerate), task end - Swt.display.timer_exec 1000 / @framerate, task + Swt.display.timer_exec (2000 / @framerate), task end def run diff --git a/lib/swt_shoes/app.rb b/lib/swt_shoes/app.rb index 02651422..a843e607 100644 --- a/lib/swt_shoes/app.rb +++ b/lib/swt_shoes/app.rb @@ -20,7 +20,6 @@ def gui_init container.setText(self.title) container.addListener(Swt::SWT::Close, main_window_on_close) - puts "app gui_container (in app): #{self.gui_container.inspect}" end diff --git a/lib/swt_shoes/button.rb b/lib/swt_shoes/button.rb index b9451061..193599e6 100644 --- a/lib/swt_shoes/button.rb +++ b/lib/swt_shoes/button.rb @@ -14,46 +14,26 @@ def gui_button_init def move(left, top) super(left, top) - unless gui_element.is_disposed - puts "gui_element: #{gui_element.inspect}" - puts "parent: #{gui_container.inspect}" - - # This element is part of a layout, we need to pop it into its own + unless gui_element.disposed? + # If this element is part of a layout, we need to pop it into its own # composite layer before moving it, so the rest of of the elements in # the layout can reflow. if gui_container.get_layout - - # FIXME: we need a new gui_element for this button, that belongs to a - # different composite, with a different layout, so that it can be - # positioned. This is to pop it out of a RowLayout. But--once it's out, - # it should belong to the "whole canvas", and at that point, we don't - # need to recreate the gui element to move it. - old_gui_container = gui_container - puts "old gui_container: #{gui_container.inspect}" - puts "app gui_container: #{@app.gui_container.inspect}" - self.gui_container = Swt::Widgets::Composite.new(@app.gui_container, Swt::SWT::NONE) - puts "new gui_container: #{gui_container.inspect}" - puts "gui containers have same parent: #{self.gui_container.parent == old_gui_container.parent}" - # first attempt disposed and recreated gui_element... - gui_element.dispose - puts "disposed gui_element" + old_gui_container = self.gui_container + self.gui_container = Swt::Widgets::Composite.new(@app.gui_container, Swt::SWT::NO_BACKGROUND) + self.gui_element.dispose self.gui_container.set_layout nil - gui_element = Swt::Widgets::Button.new(gui_container, Swt::SWT::PUSH).tap do |button| + self.gui_element = Swt::Widgets::Button.new(gui_container, Swt::SWT::PUSH).tap do |button| button.set_text(self.text) button.add_selection_listener(self.click_event_lambda) if click_event_lambda button.pack end - gui_container.set_bounds(0, 0, @app.gui_container.size.x, @app.gui_container.size.y) - - puts "new gui_container's children:\n #{gui_container.children.map(&:inspect).join("\n ")}" - puts "new gui_container's bounds: #{gui_container.bounds}" - puts "old gui_container's children:\n #{old_gui_container.children.map(&:inspect).join("\n ")}" - puts "app gui_container's children:\n #{@app.gui_container.children.map(&:inspect).join("\n ")}" - + self.gui_container.set_bounds(0, 0, @app.gui_container.size.x, @app.gui_container.size.y) + self.gui_container.move_above(old_gui_container) old_gui_container.layout end - gui_element.set_location left, top - gui_element.redraw + self.gui_element.set_location left, top + self.gui_element.redraw end end end diff --git a/lib/swt_shoes/flow.rb b/lib/swt_shoes/flow.rb index ddc4d8ec..21b8679c 100644 --- a/lib/swt_shoes/flow.rb +++ b/lib/swt_shoes/flow.rb @@ -5,7 +5,7 @@ module SwtShoes module Flow def gui_flow_init - self.gui_container = container = Swt::Widgets::Composite.new(self.parent_gui_container, Swt::SWT::NONE) + self.gui_container = container = Swt::Widgets::Composite.new(self.parent_gui_container, Swt::SWT::NO_BACKGROUND) # RowLayout is horizontal by default, wrapping by default layout = Swt::Layout::RowLayout.new diff --git a/samples/working-swt/simple-move.rb b/samples/working-swt/simple-move.rb new file mode 120000 index 00000000..9f8ba55a --- /dev/null +++ b/samples/working-swt/simple-move.rb @@ -0,0 +1 @@ +../simple-move.rb \ No newline at end of file diff --git a/spec/swt_shoes/button_spec.rb b/spec/swt_shoes/button_spec.rb index 2e4f7249..525c9747 100644 --- a/spec/swt_shoes/button_spec.rb +++ b/spec/swt_shoes/button_spec.rb @@ -7,21 +7,34 @@ describe SwtShoes::Button do #it_should_behave_like "A Common Element" - it_behaves_like "movable object with disposable gui element" class ButtonShoeLaces - include SwtShoes::Button attr_accessor :gui_container, :gui_element, :text, :height, :width, :margin, :click_event_lambda + attr_accessor :app + + # because SwtShoes::Button#move calls super :( + def move(left, top) + # no-op + end end - let(:stub_gui_parent) { Swt.display } + let(:gui_container) { double("gui container", :get_layout => true) } + let(:gui_element) { double("gui element") } + let(:app_gui_container) { double("app gui container") } + let(:app) { double("app", :gui_container => app_gui_container) } let(:shoelace) { shoelace = ButtonShoeLaces.new - debugger - shoelace.parent_gui_container = stub_gui_parent + shoelace.extend described_class + shoelace.gui_container = gui_container + shoelace.gui_element = gui_element + shoelace.app = app shoelace } + subject { shoelace } + + it_behaves_like "movable object with disposable gui element" + describe "WhiteShoes requirements" do let(:mock_element) { mock(:element, :setText => true, :pack => true )} diff --git a/spec/swt_shoes/shared_examples/common_methods_spec.rb b/spec/swt_shoes/shared_examples/common_methods_spec.rb index ce9f86b3..a5044765 100644 --- a/spec/swt_shoes/shared_examples/common_methods_spec.rb +++ b/spec/swt_shoes/shared_examples/common_methods_spec.rb @@ -1,7 +1,13 @@ +# Requires gui_element shared_examples_for "movable object with disposable gui element" do + before :each do + Swt::Widgets::Composite.stub(:new) { double("composite").as_null_object } + end + it "disposes its gui element" do + pending "setup is WAAAY too complicated" + gui_element.should_receive(:disposed?) gui_element.should_receive(:dispose) subject.move(300, 200) - raise end end