sweet 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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