sweet 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/README.rdoc +9 -5
  2. data/bin/sweet +3 -1
  3. data/examples/fox/hello_world.rb +12 -0
  4. data/examples/gtk2/hello_world.rb +14 -0
  5. data/examples/swing/hello_world.rb +12 -0
  6. data/examples/swt/components.rb +112 -0
  7. data/examples/swt/components/buttons.rb +35 -0
  8. data/examples/{hello_world.rb → swt/hello_world.rb} +2 -2
  9. data/examples/{snippet108.rb → swt/snippet108.rb} +2 -2
  10. data/examples/{snippet128.rb → swt/snippet128.rb} +7 -8
  11. data/examples/{snippet169.rb → swt/snippet169.rb} +2 -2
  12. data/examples/{snippet82.rb → swt/snippet82.rb} +2 -2
  13. data/examples/wx/hello_world.rb +12 -0
  14. data/lib/sweet.rb +22 -1
  15. data/lib/sweet/base.rb +151 -177
  16. data/lib/sweet/fox.rb +47 -0
  17. data/lib/sweet/fox/application.rb +9 -0
  18. data/lib/sweet/fox/object.rb +19 -0
  19. data/lib/sweet/gtk2.rb +56 -0
  20. data/lib/sweet/gtk2/application.rb +11 -0
  21. data/lib/sweet/gtk2/widget.rb +5 -0
  22. data/lib/sweet/hacks.rb +0 -17
  23. data/lib/sweet/swing.rb +97 -0
  24. data/lib/sweet/swing/application.rb +9 -0
  25. data/lib/sweet/swing/component.rb +23 -0
  26. data/lib/sweet/swing/frame.rb +13 -0
  27. data/lib/sweet/swt.rb +193 -0
  28. data/lib/sweet/swt/application.rb +17 -0
  29. data/lib/sweet/{composite.rb → swt/composite.rb} +5 -2
  30. data/lib/sweet/{dialog.rb → swt/dialog.rb} +0 -0
  31. data/lib/sweet/{downloader.rb → swt/downloader.rb} +1 -1
  32. data/lib/sweet/swt/shell.rb +22 -0
  33. data/lib/sweet/swt/src.zip +0 -0
  34. data/lib/sweet/swt/swt.jar +0 -0
  35. data/lib/sweet/swt/widget.rb +89 -0
  36. data/lib/sweet/wx.rb +57 -0
  37. data/lib/sweet/wx/application.rb +9 -0
  38. data/lib/sweet/wx/object.rb +19 -0
  39. data/spec/api_spec.rb +15 -0
  40. data/spec/downloader_spec.rb +28 -26
  41. data/spec/fox_spec.rb +15 -0
  42. data/spec/gtk2_spec.rb +15 -0
  43. data/spec/sweet_spec.rb +15 -0
  44. data/spec/swing_spec.rb +15 -0
  45. data/spec/swt_spec.rb +15 -0
  46. data/spec/wx_spec.rb +15 -0
  47. metadata +44 -17
  48. data/lib/sweet/shell.rb +0 -53
  49. data/lib/sweet/widget.rb +0 -151
data/README.rdoc CHANGED
@@ -1,9 +1,13 @@
1
- == Sweet: The SWT wrapper for JRuby
1
+ == Sweet: The GUI wrapper for Ruby/JRuby
2
2
 
3
3
  Sweet is designed to provide the most readable and straight-forward DSL for the
4
- SWT toolkit while maintaining all of its flexibility. If you find any limits to
5
- this claim, please open a bug report or fix it on a fork if you feel
6
- adventurous.
4
+ most common GUI toolkits while maintaining all of their flexibility. If you find
5
+ any limits to this claim, please open a bug report or fix it on a fork if you
6
+ feel adventurous.
7
+
8
+ The primary and most complete toolkit right now is SWT, which requires JRuby.
9
+ Swing, wxRuby and Gnome2 exist with rudimentary support so far. Cocoa is in
10
+ the making. Pull requests for new widgets and toolkits are always welcome.
7
11
 
8
12
  === Install
9
13
 
@@ -11,7 +15,7 @@ Sweet is available as a gem:
11
15
 
12
16
  sudo gem install sweet
13
17
 
14
- To install the necessary SWT for your platform libraries, run:
18
+ To install the necessary SWT libraries for your platform, run:
15
19
 
16
20
  sudo sweet install
17
21
 
data/bin/sweet CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env jruby
2
2
 
3
+ # TODO means to create distributables (jar / WebStart / InstallAnywhere / ...)
4
+
3
5
  require 'rubygems'
4
- require 'sweet/downloader'
6
+ require 'sweet/swt/downloader'
5
7
 
6
8
  cmd = ARGV[0]
7
9
 
@@ -0,0 +1,12 @@
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/fox'
3
+ Sweet.set_debug
4
+
5
+ Sweet.app 'My first Application', :layout => :flow do
6
+ label 'Your name:'
7
+ @name = edit_line :columns => 10
8
+
9
+ button 'Push me' do
10
+ puts "Hello, #{@name.text}!"
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/gtk2'
3
+ Sweet.set_debug
4
+
5
+ Sweet.app 'My first Application', :border_width => 10 do
6
+ flow do
7
+ label 'Your name:'
8
+ @name = edit_line :columns => 10
9
+
10
+ button 'Push me' do
11
+ puts "Hello, #{@name.text}!"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/swing'
3
+ Sweet.set_debug
4
+
5
+ Sweet.app 'My first Application', :layout => :flow do
6
+ label 'Your name:'
7
+ @name = edit_line :columns => 10
8
+
9
+ button 'Push me' do
10
+ puts "Hello, #{@name.text}!"
11
+ end
12
+ end
@@ -0,0 +1,112 @@
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/swt'
3
+
4
+ class Tab < Sweet::VarContainer
5
+ def self.title(title = nil)
6
+ title ? instances[@title = title] = self : @title
7
+ end
8
+
9
+ def self.instances
10
+ @instances ||= {}
11
+ end
12
+
13
+ def create
14
+ @style = 0
15
+ group :layout => :grid, :grid_data => {:align => [:fill, :fill], :grab => [true, true]} do
16
+ create_example_group
17
+ end
18
+ group 'Parameters', :layout => :grid, :grid_data => {:align => [:fill, :fill]} do
19
+ create_parameter_group
20
+ end
21
+ end
22
+
23
+ def create_example_group
24
+ example_layout =
25
+ @example_group = group('Examples', example_layout) do
26
+ example_groups if respond_to? :example_group
27
+ end
28
+ @parameters_group =
29
+ create_example_widgets
30
+ end
31
+
32
+ def create_example_widgets
33
+ if widgets = @example_widgets
34
+ widgets.each { |widget| widget.dispose }
35
+ end
36
+ @example_widgets = example_widgets.flatten
37
+ # TODO hook listener and set state
38
+ @example_widgets.each do |widget|
39
+ widget.alignment = widget_alignment
40
+ widget.visible = true
41
+ end
42
+ end
43
+
44
+ def create_style_group
45
+ listener = proc { |event|
46
+ if event.widget.selection
47
+ self.widget_style = event.widget
48
+ create_example_widgets
49
+ end
50
+ }
51
+
52
+ @style_group = group('Styles', :grid_data => {:align => [:fill, :fill]}) do
53
+ %w{PUSH CHECK RADIO TOGGLE}.each{ |type| radio_button type, &listener}
54
+ %w{FLAT BORDER}.each{ |type| check_button type, &listener}
55
+ end
56
+ end
57
+
58
+ def widget_style
59
+ @style ||= 0
60
+ end
61
+ def widget_style=(value)
62
+ @style = value
63
+ end
64
+ end
65
+
66
+ class AlignableTab < Tab
67
+ def create_alignment_group
68
+ listener = proc { |event|
69
+ if event.widget.selection
70
+ self.widget_alignment = event.widget
71
+ create_example_widgets
72
+ end
73
+ }
74
+
75
+ group = @parent.append{ group('Alignment', :layout => :grid, :grid_data => {:align => [:fill, :fill]}) }
76
+ group.append do
77
+ radio_button 'Left', :selection => true, &listener
78
+ radio_button 'Center', &listener
79
+ radio_button 'Right', &listener
80
+ end
81
+
82
+ alignment_group(group, listener) if respond_to? :alignment_group
83
+ end
84
+
85
+ def widget_alignment
86
+ @widget_alignment ||= 0
87
+ end
88
+ def widget_alignment=(value)
89
+ @widget_alignment |= value.text.to_sym.swt_const
90
+ end
91
+ def widget_style
92
+ super | widget_alignment
93
+ end
94
+ end
95
+
96
+ Dir.glob(File.join(File.dirname(__FILE__), 'components/*.rb')).each{|file| load file}
97
+
98
+
99
+ Sweet.app 'Component DEMO', :layout => :fill do
100
+
101
+ tab_folder do
102
+ tab_item do
103
+ buttons = Buttons.new(:layout => :grid.conf(:numColumns => 3), :style => swt::CLOSE)
104
+
105
+ buttons.create_alignment_group
106
+ buttons.create_example_group
107
+ buttons.create_style_group
108
+ end
109
+ end
110
+
111
+ end
112
+
@@ -0,0 +1,35 @@
1
+ class Buttons < AlignableTab
2
+ title "Buttons"
3
+
4
+ def alignment_group(listener)
5
+ radio_button 'Up', &listener
6
+ radio_button 'Down', &listener
7
+ end
8
+
9
+ def example_group
10
+ # TODO densify with :grid_data => [:fill_both, :grab_both] or alike
11
+ group_layout = {:layout => :grid.conf(:numColumns => 3), :grid_data => {:align => [:fill, :fill], :grab => [true, true]}}
12
+
13
+ @text_buttons = group('Text Buttons', group_layout)
14
+ @image_buttons = group('Image Buttons', group_layout)
15
+ @image_text_buttons = group('Image Text Buttons', group_layout)
16
+ end
17
+
18
+ def example_widgets(style)
19
+ [ #returns all created widgets
20
+ @text_buttons.append do
21
+ %w{One Two Three}.map { |caption| button caption, :style => style }
22
+ end,
23
+ @image_buttons.append do
24
+ # TODO images
25
+ %w{One Two Three}.map { |type| button type, :style => style }
26
+ end,
27
+ @image_text_buttons.append do
28
+ # TODO images
29
+ %w{One Two Three}.map { |type| button type, :style => style }
30
+ end
31
+ ].map(&:children)
32
+ end
33
+
34
+ end
35
+
@@ -1,5 +1,5 @@
1
- $: << File.join(__FILE__, '../lib')
2
- require 'sweet'
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/swt'
3
3
 
4
4
  Sweet.app 'My first Application', :layout => :fill do
5
5
  label 'Your name:'
@@ -1,5 +1,5 @@
1
- $: << File.join(__FILE__, '../lib')
2
- require 'sweet'
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/swt'
3
3
 
4
4
  # Display display = new Display ();
5
5
  # Shell shell = new Shell (display);
@@ -1,5 +1,5 @@
1
- $: << File.join(__FILE__, '../lib')
2
- require 'sweet'
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/swt'
3
3
 
4
4
  # Display display = new Display();
5
5
  # final Shell shell = new Shell(display);
@@ -36,6 +36,11 @@ Sweet.app :layout => :grid.conf(:numColumns => 3) do
36
36
  # else if (string.equals("Go")) browser.setUrl(location.getText());
37
37
  # }
38
38
  # };
39
+ # itemBack.addListener(SWT.Selection, listener);
40
+ # itemForward.addListener(SWT.Selection, listener);
41
+ # itemStop.addListener(SWT.Selection, listener);
42
+ # itemRefresh.addListener(SWT.Selection, listener);
43
+ # itemGo.addListener(SWT.Selection, listener);
39
44
  %w{Back Forward Stop Refresh}.each do |caption|
40
45
  tool_item(caption) { @browser.send(caption.downcase) }
41
46
  end
@@ -140,12 +145,6 @@ Sweet.app :layout => :grid.conf(:numColumns => 3) do
140
145
  @location.text = event.location if event.top
141
146
  end
142
147
 
143
- # itemBack.addListener(SWT.Selection, listener);
144
- # itemForward.addListener(SWT.Selection, listener);
145
- # itemStop.addListener(SWT.Selection, listener);
146
- # itemRefresh.addListener(SWT.Selection, listener);
147
- # itemGo.addListener(SWT.Selection, listener);
148
- #
149
148
  # shell.open();
150
149
  # browser.setUrl("http://eclipse.org");
151
150
  @browser.setUrl "http://eclipse.org"
@@ -1,5 +1,5 @@
1
- $: << File.join(__FILE__, '../lib')
2
- require 'sweet'
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/swt'
3
3
 
4
4
  # Display display = new Display ();
5
5
  # final Shell shell = new Shell (display);
@@ -1,5 +1,5 @@
1
- $: << File.join(__FILE__, '../lib')
2
- require 'sweet'
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/swt'
3
3
 
4
4
  #Display display = new Display();
5
5
  # Shell shell = new Shell(display);
@@ -0,0 +1,12 @@
1
+ $: << File.join(File.dirname(__FILE__), '../../lib')
2
+ require 'sweet/wxruby'
3
+ Sweet.set_debug
4
+
5
+ Sweet.app 'My first Application', :layout => :flow do
6
+ label 'Your name:'
7
+ @name = edit_line :columns => 10
8
+
9
+ button 'Push me' do
10
+ puts "Hello, #{@name.text}!"
11
+ end
12
+ end
data/lib/sweet.rb CHANGED
@@ -1 +1,22 @@
1
- require 'sweet/base'
1
+ case RUBY_PLATFORM
2
+ when /java/
3
+ begin
4
+ require 'sweet/swt'
5
+ rescue
6
+ require 'sweet/swing'
7
+ end
8
+ when /linux/
9
+ begin
10
+ require 'sweet/gtk2'
11
+ rescue
12
+ begin
13
+ require 'sweet/fox'
14
+ rescue
15
+ require 'sweet/wx'
16
+ end
17
+ end
18
+ when /win/i
19
+ require 'sweet/fox'
20
+ else # MacOS
21
+ require 'sweet/fox'
22
+ end
data/lib/sweet/base.rb CHANGED
@@ -1,95 +1,7 @@
1
- require 'sweet/downloader'
2
-
3
- begin
4
- load Sweet::SWT_JAR
5
- rescue LoadError => e
6
- STDERR.puts "No swt.jar found. Run:"
7
- STDERR.puts " sweet install [toolkit]"
8
- exit
9
- end
10
-
11
- require 'java'
12
- %w{hacks widget composite shell dialog}.each{|file| require "sweet/#{file}"}
1
+ require 'sweet/hacks'
13
2
 
14
- # TODO create gemspec
15
- # TODO evaluate integration of jface
16
- # TODO enable additive and replacing :style on widget creation
17
3
  module Sweet
18
4
 
19
- import 'org.eclipse.swt'
20
- import 'org.eclipse.swt.widgets'
21
- import 'org.eclipse.swt.custom'
22
- import 'org.eclipse.swt.browser'
23
-
24
- # TODO integrate all standard widgets
25
- WIDGET_HACKS = {
26
- ProgressBar => {:custom_code => proc {
27
- def fraction=(value)
28
- setSelection value.to_f * maximum
29
- end
30
- def fraction
31
- selection / maximum
32
- end
33
- }},
34
- Text => {:custom_code => proc{
35
- def password=(value)
36
- self.echo_char = ?* if value
37
- end
38
- def password
39
- ! echo_char.nil?
40
- end
41
- }},
42
- CTabFolder => {:default_listener => 'CTabFolder2'}
43
- }
44
-
45
- DEFAULT = {:init_args => :text, :block_handler => SWT::Selection}
46
- WIDGET_OPTIONS = {
47
- # Text components
48
- :label => {:style => SWT::WRAP, :init_args => :text},
49
- :edit_line => {:class => Text, :style => SWT::SINGLE | SWT::BORDER, :init_args => :text, :block_handler => :on_widget_default_selected},
50
- :edit_area => {:class => Text, :style => SWT::MULTI | SWT::BORDER, :init_args => :text, :block_handler => :on_widget_default_selected},
51
-
52
- # Buttons
53
- :button => DEFAULT.merge(:style => SWT::PUSH),
54
- :toggle_button => DEFAULT.merge(:class => Button, :style => SWT::TOGGLE),
55
- :radio_button => DEFAULT.merge(:class => Button, :style => SWT::RADIO),
56
- :check_button => DEFAULT.merge(:class => Button, :style => SWT::CHECK),
57
- :arrow_button => DEFAULT.merge(:class => Button, :style => SWT::ARROW),
58
-
59
- # Menus
60
- :menubar => {:class => Menu, :style => SWT::BAR},
61
- :popup => {:class => Menu, :style => SWT::POP_UP},
62
- :item => {:class => MenuItem, :style => SWT::PUSH, :init_args => :text, :block_handler => :on_widget_selected},
63
- :separator => {:class => MenuItem, :style => SWT::SEPARATOR},
64
- :submenu => {:class => MenuItem, :style => SWT::CASCADE, :init_args => :text, :block_handler => proc{|c, opts, block|
65
- sub = Menu.new(c.app, SWT::DROP_DOWN)
66
- sub.sweeten(c.app, opts, &block)
67
- c.menu = sub
68
- }
69
- },
70
-
71
- # Toolbars
72
- :tool_item => DEFAULT.merge(:style => SWT::PUSH),
73
- # TODO make CoolBar work
74
- # :cool_item => {:init_args => :control, :block_handler => proc{ |c, opts, proc|
75
- # c.control = proc.call
76
- # }},
77
-
78
- # Tabs
79
- :tab_folder => {:class => CTabFolder, :style => SWT::BORDER},
80
- :tab_item => {:class => CTabItem, :style => SWT::CLOSE, :init_args => [:text, :control], :block_handler => proc{|c, opts, proc|
81
- c.control = proc.call
82
- }},
83
-
84
- # Other components
85
- :tree => {:style => SWT::VIRTUAL, :block_handler => SWT::Selection},
86
- :progress => {:class => ProgressBar, :style => SWT::SMOOTH},
87
- :group => {:init_args => :text},
88
-
89
- # Dialogs
90
- :color_dialog => {:style => SWT::APPLICATION_MODAL, :init_args => :text}
91
- }.unify
92
-
93
5
  WIDGETS = {}
94
6
 
95
7
  def self.app(*args, &block)
@@ -99,25 +11,11 @@ module Sweet
99
11
  raise ArgumentError.new(count, 2) if args.size > 1
100
12
  opts = args.first || {}
101
13
 
102
- # build the UI
103
- Display.setAppName(name)
104
- display = Display.new
105
-
106
- # TODO allow multiple shells
107
- shell = Shell.new(display)
108
- shell.sweeten(display, name, opts, &block)
109
- shell.open
110
-
111
- # dispatch loop
112
- while (!shell.isDisposed) do
113
- display.sleep unless display.readAndDispatch
114
- end
115
-
116
- display.dispose
14
+ create_app(name, opts, &block)
117
15
  end
118
16
 
119
17
  def self.create_widget(parent, name, *args, &block)
120
- init = WIDGET_OPTIONS[name] || {}
18
+ init = WIDGET_DEFAULTS[name] || {}
121
19
 
122
20
  unless cls = WIDGETS[name]
123
21
  # puts "Loading widget #{name}"
@@ -125,99 +23,175 @@ module Sweet
125
23
  # begin
126
24
  # require filename
127
25
  # rescue LoadError
128
- cls = create_widget_class(name, init)
26
+ class_name = init[:class] || name
27
+ class_name = class_name.to_s.camelize(:upper) if class_name.is_a?(Symbol)
28
+ cls = create_widget_class(class_name, init)
29
+
30
+ unless WIDGETS.values.member? cls
31
+ delegate_events(cls)
32
+ if hacks = WIDGET_HACKS[cls]
33
+ if custom_code = hacks[:custom_code]
34
+ cls.class_eval &custom_code
35
+ end
36
+ end
37
+ end
38
+
129
39
  # end
130
40
  end
131
41
 
132
42
  opts = args.last.is_a?(Hash) ? args.pop.dup : {}
133
-
134
- style = opts.delete(:style) || init[:style] || SWT::NONE
135
- style = Array(style).inject(0) do |result, value|
136
- value = value.swt_const if value.is_a? Symbol
137
- result | value
138
- end
139
-
140
- Sweet.debug "Creating #{cls.java_class.simple_name}(#{parent}, #{style})"
141
- result = cls.new(parent, style)
142
- result.instance_variable_set(:@block_handler, init[:block_handler])
143
-
144
43
  if init_args = init[:init_args]
145
- Hash[Array(init_args).zip(args)].each do |k, v|
146
- opts.merge! k => v if v
44
+ Array(init_args).zip(args).each do |(k, v)|
45
+ opts.merge!(k => v) if v
147
46
  end
148
47
  end
149
- result.sweeten(parent.app, opts, &block)
150
48
 
151
- result
49
+ widget = initialize_widget(parent, cls, opts, init)
50
+ widget.instance_variable_set(:@block_handler, init[:block_handler])
51
+
52
+ widget.sweeten(parent.app, opts, &block)
53
+
54
+ widget
55
+ end
56
+
57
+ @debug = ARGV.delete('--debug')
58
+ def self.set_debug(value = true)
59
+ @debug = value
60
+ end
61
+ def self.debug(text)
62
+ # TODO add a decent logging mechanism
63
+ puts text if @debug
152
64
  end
153
65
 
154
- def self.create_widget_class(name, init)
155
- # build widget with default accessors
156
- class_name = init[:class] || name
157
- class_name = class_name.to_s.camelize(:upper) if class_name.is_a?(Symbol)
158
- cls = class_name.is_a?(Class) ? class_name : const_get(class_name)
159
-
160
- unless WIDGETS.values.member? cls
161
- delegate_events(cls)
162
- if hacks = WIDGET_HACKS[cls]
163
- if custom_code = hacks[:custom_code]
164
- cls.class_eval &custom_code
66
+ module Component
67
+
68
+ def self.included(cls)
69
+ puts "extending #{cls}"
70
+ cls.extend(ClassMethods)
71
+ end
72
+
73
+ attr_reader :app
74
+
75
+ def sweeten(app, opts, &block)
76
+ @app = app
77
+ self.options = opts
78
+
79
+ if block
80
+ case handler = @block_handler
81
+ when nil
82
+ handle_container &block
83
+ when Symbol
84
+ handle_event handler, &block
85
+ when Proc
86
+ instance_eval do
87
+ handler.call self, opts, block
88
+ end
89
+ else
90
+ raise("Invalid :block_handler ",handler) unless sweet_block_handler(handler, &block)
165
91
  end
166
92
  end
93
+
94
+ puts "Unknown properties for class #{self.class}: #{opts.keys.inspect}" unless opts.empty?
167
95
  end
96
+ alias handle_event send
168
97
 
169
- cls
170
- end
98
+ def app(&block)
99
+ return @app unless block
100
+ @app.var_containers.last.instance_eval(&block)
101
+ end
171
102
 
172
- def self.delegate_events(cls)
173
- hacks = WIDGET_HACKS[cls]
174
- default_listener = (hacks[:default_listener] || '').underscore if hacks
175
-
176
- methods = cls.java_class.java_instance_methods
177
- methods.each do |m|
178
- next unless m.name =~ /(add(.*)Listener)/
179
- j = $1
180
- n = $2.underscore
181
- p = m.parameter_types[0]
182
- evts = p.declared_instance_methods
183
-
184
- if evts.size == 1
185
- s = "on_#{n}"
186
- cls.send(:alias_method, s, j) unless cls.respond_to?(s)
187
- else
188
- evts.each do |evt|
189
- s = evt.name.underscore
190
- if s.split(/_/).size == 1 && n != default_listener
191
- s = n + "_" + s
103
+ def append(&block)
104
+ raise "Append called without block" unless block
105
+ handle_container &block
106
+ end
107
+
108
+ def meta(&block)
109
+ @meta ||= class << self
110
+ self
111
+ end
112
+ block ? @meta.class_eval(&block) : @meta
113
+ end
114
+
115
+ def options=(opts)
116
+ # TODO reader method
117
+ opts.each_pair do |k, v|
118
+ case k
119
+ when :hidden
120
+ setVisible !v
121
+ else
122
+ name = k.to_s + "="
123
+ next unless respond_to? name
124
+ if v
125
+ classname = respond_to?(:java_class) ? self.java_class.simple_name : self.class.name
126
+ Sweet.debug "#{classname}.#{k} = #{v.inspect}"
127
+ send name, *v
192
128
  end
193
- # TODO provide addListener SWT::Xxx option
194
- unused_events = evts.select{ |e| e.name != evt.name }.map{ |e| "def #{e.name.underscore}(e)\nend" }.join("\n")
195
- cls.class_eval <<-EOF
196
- def on_#{s}(&block)
197
- l = Class.new do
198
- include Java.#{p}
199
- def initialize(&block)
200
- @block = block
201
- end
202
- def #{evt.name}(e)
203
- @block.call e
204
- end
205
- #{unused_events}
206
- end
207
- #{j} l.new(&block)
208
- end
209
- EOF
129
+ opts.delete(k)
130
+ end
131
+ end
132
+ end
133
+
134
+ def perform(&block)
135
+ app.perform &block
136
+ end
137
+
138
+ def method_missing(name, *args, &block)
139
+ app.send(name, *args, &block) rescue super
140
+ end
141
+
142
+ private
143
+ def handle_container(&block)
144
+ app.sweet_containers.push self
145
+ app &block
146
+ ensure
147
+ app.sweet_containers.pop
148
+ end
149
+
150
+ module ClassMethods
151
+ def alias_property(aliases = {})
152
+ aliases.each do |from, to|
153
+ alias_method from, to unless respond_to? to
154
+ alias_method "#{from}=", "#{to}=" unless respond_to? "#{to}="
210
155
  end
211
156
  end
212
157
  end
158
+
213
159
  end
214
160
 
215
- def self.set_debug
216
- @debug = true
161
+ module Application
162
+ def initialize_app(root)
163
+ sweet_containers << root
164
+ var_containers << root
165
+ end
166
+ def sweet_containers
167
+ @sweet_containers ||= []
168
+ end
169
+ def var_containers
170
+ @var_containers ||= []
171
+ end
172
+ # TODO find suitable exception
173
+ def perform(&block)
174
+ raise 'perform is not implemented'
175
+ end
176
+
177
+ def busy(&block)
178
+ raise 'busy is not implemented'
179
+ end
180
+ def method_missing(name, *args, &block)
181
+ Sweet.create_widget(sweet_containers.last, name, *args, &block) || super
182
+ end
217
183
  end
218
- def self.debug(text)
219
- # TODO add a decent logging mechanism
220
- puts text if @debug
184
+
185
+ class VarContainer
186
+ include Component
187
+
188
+ private
189
+ def handle_container(&block)
190
+ app.var_containers.push self
191
+ app &block
192
+ ensure
193
+ app.var_containers.pop
194
+ end
221
195
  end
222
- end
223
196
 
197
+ end