glimmer 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +116 -95
  4. data/VERSION +1 -1
  5. data/lib/glimmer.rb +0 -20
  6. data/lib/glimmer/config.rb +0 -13
  7. data/lib/glimmer/dsl/engine.rb +25 -18
  8. data/lib/glimmer/dsl/expression.rb +0 -7
  9. data/lib/glimmer/dsl/static_expression.rb +2 -2
  10. metadata +47 -177
  11. data/RUBY_VERSION +0 -1
  12. data/bin/girb +0 -10
  13. data/bin/girb_runner.rb +0 -13
  14. data/bin/glimmer +0 -5
  15. data/icons/scaffold_app.icns +0 -0
  16. data/lib/glimmer/css/rule.rb +0 -25
  17. data/lib/glimmer/css/style_sheet.rb +0 -19
  18. data/lib/glimmer/data_binding/list_selection_binding.rb +0 -52
  19. data/lib/glimmer/data_binding/model_binding.rb +0 -248
  20. data/lib/glimmer/data_binding/observable.rb +0 -21
  21. data/lib/glimmer/data_binding/observable_array.rb +0 -107
  22. data/lib/glimmer/data_binding/observable_model.rb +0 -108
  23. data/lib/glimmer/data_binding/observable_widget.rb +0 -17
  24. data/lib/glimmer/data_binding/observer.rb +0 -124
  25. data/lib/glimmer/data_binding/shine.rb +0 -23
  26. data/lib/glimmer/data_binding/table_items_binding.rb +0 -56
  27. data/lib/glimmer/data_binding/tree_items_binding.rb +0 -71
  28. data/lib/glimmer/data_binding/widget_binding.rb +0 -33
  29. data/lib/glimmer/dsl/css/css_expression.rb +0 -21
  30. data/lib/glimmer/dsl/css/dsl.rb +0 -10
  31. data/lib/glimmer/dsl/css/dynamic_property_expression.rb +0 -12
  32. data/lib/glimmer/dsl/css/property_expression.rb +0 -22
  33. data/lib/glimmer/dsl/css/pv_expression.rb +0 -17
  34. data/lib/glimmer/dsl/css/rule_expression.rb +0 -25
  35. data/lib/glimmer/dsl/css/s_expression.rb +0 -26
  36. data/lib/glimmer/dsl/swt/async_exec_expression.rb +0 -14
  37. data/lib/glimmer/dsl/swt/bind_expression.rb +0 -37
  38. data/lib/glimmer/dsl/swt/color_expression.rb +0 -19
  39. data/lib/glimmer/dsl/swt/column_properties_expression.rb +0 -24
  40. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +0 -42
  41. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +0 -36
  42. data/lib/glimmer/dsl/swt/data_binding_expression.rb +0 -34
  43. data/lib/glimmer/dsl/swt/dialog_expression.rb +0 -26
  44. data/lib/glimmer/dsl/swt/display_expression.rb +0 -19
  45. data/lib/glimmer/dsl/swt/dsl.rb +0 -28
  46. data/lib/glimmer/dsl/swt/exec_expression.rb +0 -28
  47. data/lib/glimmer/dsl/swt/layout_data_expression.rb +0 -25
  48. data/lib/glimmer/dsl/swt/layout_expression.rb +0 -27
  49. data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +0 -44
  50. data/lib/glimmer/dsl/swt/menu_bar_expression.rb +0 -33
  51. data/lib/glimmer/dsl/swt/menu_expression.rb +0 -32
  52. data/lib/glimmer/dsl/swt/message_box_expression.rb +0 -29
  53. data/lib/glimmer/dsl/swt/observe_expression.rb +0 -32
  54. data/lib/glimmer/dsl/swt/property_expression.rb +0 -22
  55. data/lib/glimmer/dsl/swt/rgb_expression.rb +0 -12
  56. data/lib/glimmer/dsl/swt/rgba_expression.rb +0 -12
  57. data/lib/glimmer/dsl/swt/shell_expression.rb +0 -25
  58. data/lib/glimmer/dsl/swt/swt_expression.rb +0 -25
  59. data/lib/glimmer/dsl/swt/sync_exec_expression.rb +0 -15
  60. data/lib/glimmer/dsl/swt/tab_item_expression.rb +0 -33
  61. data/lib/glimmer/dsl/swt/table_items_data_binding_expression.rb +0 -31
  62. data/lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb +0 -31
  63. data/lib/glimmer/dsl/swt/tree_properties_expression.rb +0 -26
  64. data/lib/glimmer/dsl/swt/widget_expression.rb +0 -35
  65. data/lib/glimmer/dsl/swt/widget_listener_expression.rb +0 -32
  66. data/lib/glimmer/dsl/xml/dsl.rb +0 -11
  67. data/lib/glimmer/dsl/xml/html_expression.rb +0 -25
  68. data/lib/glimmer/dsl/xml/meta_expression.rb +0 -23
  69. data/lib/glimmer/dsl/xml/name_space_expression.rb +0 -37
  70. data/lib/glimmer/dsl/xml/node_parent_expression.rb +0 -33
  71. data/lib/glimmer/dsl/xml/tag_expression.rb +0 -29
  72. data/lib/glimmer/dsl/xml/text_expression.rb +0 -22
  73. data/lib/glimmer/dsl/xml/xml_expression.rb +0 -21
  74. data/lib/glimmer/launcher.rb +0 -199
  75. data/lib/glimmer/package.rb +0 -55
  76. data/lib/glimmer/rake_task.rb +0 -58
  77. data/lib/glimmer/scaffold.rb +0 -582
  78. data/lib/glimmer/swt/color_proxy.rb +0 -53
  79. data/lib/glimmer/swt/display_proxy.rb +0 -88
  80. data/lib/glimmer/swt/font_proxy.rb +0 -72
  81. data/lib/glimmer/swt/layout_data_proxy.rb +0 -84
  82. data/lib/glimmer/swt/layout_proxy.rb +0 -82
  83. data/lib/glimmer/swt/menu_proxy.rb +0 -101
  84. data/lib/glimmer/swt/message_box_proxy.rb +0 -48
  85. data/lib/glimmer/swt/packages.rb +0 -13
  86. data/lib/glimmer/swt/shell_proxy.rb +0 -152
  87. data/lib/glimmer/swt/swt_proxy.rb +0 -106
  88. data/lib/glimmer/swt/tab_item_proxy.rb +0 -65
  89. data/lib/glimmer/swt/table_proxy.rb +0 -150
  90. data/lib/glimmer/swt/tree_proxy.rb +0 -120
  91. data/lib/glimmer/swt/widget_listener_proxy.rb +0 -34
  92. data/lib/glimmer/swt/widget_proxy.rb +0 -489
  93. data/lib/glimmer/ui/custom_shell.rb +0 -45
  94. data/lib/glimmer/ui/custom_widget.rb +0 -244
  95. data/lib/glimmer/util/proc_tracker.rb +0 -16
  96. data/lib/glimmer/xml/depth_first_search_iterator.rb +0 -22
  97. data/lib/glimmer/xml/name_space_visitor.rb +0 -21
  98. data/lib/glimmer/xml/node.rb +0 -75
  99. data/lib/glimmer/xml/node_visitor.rb +0 -13
  100. data/lib/glimmer/xml/xml_visitor.rb +0 -65
  101. data/vendor/swt/linux/swt.jar +0 -0
  102. data/vendor/swt/mac/swt.jar +0 -0
  103. data/vendor/swt/windows/swt.jar +0 -0
@@ -1,120 +0,0 @@
1
- require 'glimmer/swt/widget_proxy'
2
-
3
- module Glimmer
4
- module SWT
5
- class TreeProxy < Glimmer::SWT::WidgetProxy
6
- include Glimmer
7
-
8
- attr_reader :tree_editor, :tree_editor_text_proxy
9
- attr_accessor :tree_properties
10
-
11
- def initialize(underscored_widget_name, parent, args)
12
- super
13
- @tree_editor = TreeEditor.new(swt_widget)
14
- @tree_editor.horizontalAlignment = SWTProxy[:left]
15
- @tree_editor.grabHorizontal = true
16
- @tree_editor.minimumHeight = 20
17
- end
18
-
19
- # Performs depth first search for tree items matching block condition
20
- # If no condition block is passed, returns all tree items
21
- # Returns a Java TreeItem array to easily set as selection on org.eclipse.swt.Tree if needed
22
- def depth_first_search(&condition)
23
- found = []
24
- recursive_depth_first_search(swt_widget.getItems.first, found, &condition)
25
- found.to_java(TreeItem)
26
- end
27
-
28
- # Returns all tree items including descendants
29
- def all_tree_items
30
- depth_first_search
31
- end
32
-
33
- def widget_property_listener_installers
34
- super.merge({
35
- Java::OrgEclipseSwtWidgets::Tree => {
36
- selection: lambda do |observer|
37
- on_widget_selected { |selection_event|
38
- observer.call(@swt_widget.getSelection)
39
- }
40
- end
41
- },
42
- })
43
- end
44
-
45
- def edit_in_progress?
46
- !!@edit_in_progress
47
- end
48
-
49
- def edit_selected_tree_item(before_write: nil, after_write: nil, after_cancel: nil)
50
- edit_tree_item(swt_widget.getSelection.first, before_write: before_write, after_write: after_write, after_cancel: after_cancel)
51
- end
52
-
53
- def edit_tree_item(tree_item, before_write: nil, after_write: nil, after_cancel: nil)
54
- return if tree_item.nil?
55
- content {
56
- @tree_editor_text_proxy = text {
57
- focus true
58
- text tree_item.getText
59
- action_taken = false
60
- cancel = lambda {
61
- @tree_editor_text_proxy.swt_widget.dispose
62
- @tree_editor_text_proxy = nil
63
- after_cancel&.call
64
- @edit_in_progress = false
65
- }
66
- action = lambda { |event|
67
- if !action_taken && !@edit_in_progress
68
- action_taken = true
69
- @edit_in_progress = true
70
- new_text = @tree_editor_text_proxy.swt_widget.getText
71
- if new_text == tree_item.getText
72
- cancel.call
73
- else
74
- before_write&.call
75
- tree_item.setText(new_text)
76
- model = tree_item.getData
77
- model.send("#{tree_properties[:text]}=", new_text) # makes tree update itself, so must search for selected tree item again
78
- edited_tree_item = depth_first_search { |ti| ti.getData == model }.first
79
- swt_widget.showItem(edited_tree_item)
80
- @tree_editor_text_proxy.swt_widget.dispose
81
- @tree_editor_text_proxy = nil
82
- after_write&.call(edited_tree_item)
83
- @edit_in_progress = false
84
- end
85
- end
86
- }
87
- on_focus_lost(&action)
88
- on_key_pressed { |key_event|
89
- if key_event.keyCode == swt(:cr)
90
- action.call(key_event)
91
- elsif key_event.keyCode == swt(:esc)
92
- cancel.call
93
- end
94
- }
95
- }
96
- @tree_editor_text_proxy.swt_widget.selectAll
97
- }
98
- @tree_editor.setEditor(@tree_editor_text_proxy.swt_widget, tree_item)
99
- end
100
-
101
- private
102
-
103
- def recursive_depth_first_search(tree_item, found, &condition)
104
- return if tree_item.nil?
105
- found << tree_item if condition.nil? || condition.call(tree_item)
106
- tree_item.getItems.each do |child_tree_item|
107
- recursive_depth_first_search(child_tree_item, found, &condition)
108
- end
109
- end
110
-
111
- def property_type_converters
112
- super.merge({
113
- selection: lambda do |value|
114
- depth_first_search {|ti| ti.getData == value}
115
- end,
116
- })
117
- end
118
- end
119
- end
120
- end
@@ -1,34 +0,0 @@
1
- module Glimmer
2
- module SWT
3
- # Proxy for widget listeners
4
- #
5
- # Follows the Proxy Design Pattern
6
- class WidgetListenerProxy
7
-
8
- attr_reader :swt_widget, :swt_listener, :widget_add_listener_method, :swt_listener_class, :swt_listener_method, :event_type, :swt_constant
9
-
10
- def initialize(swt_widget:, swt_listener:, widget_add_listener_method: nil, swt_listener_class: nil, swt_listener_method: nil, event_type: nil, swt_constant: nil)
11
- @swt_widget = swt_widget
12
- @swt_listener = swt_listener
13
- @widget_add_listener_method = widget_add_listener_method
14
- @swt_listener_class = swt_listener_class
15
- @swt_listener_method = swt_listener_method
16
- @event_type = event_type
17
- @swt_constant = swt_constant
18
- end
19
-
20
- def widget_remove_listener_method
21
- @widget_add_listener_method.sub('add', 'remove')
22
- end
23
-
24
- def unregister
25
- # TODO consider renaming to deregister (and in Observer too)
26
- if @event_type
27
- @swt_widget.removeListener(@event_type, @swt_listener)
28
- else
29
- @swt_widget.send(widget_remove_listener_method, @swt_listener)
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,489 +0,0 @@
1
- require 'glimmer'
2
- require 'glimmer/swt/widget_listener_proxy'
3
- require 'glimmer/swt/color_proxy'
4
- require 'glimmer/swt/font_proxy'
5
- require 'glimmer/swt/swt_proxy'
6
- require 'glimmer/data_binding/observable_widget'
7
-
8
- # TODO refactor to make file smaller and extract sub-widget-proxies out of this
9
-
10
- module Glimmer
11
- module SWT
12
- # Proxy for SWT Widget objects
13
- #
14
- # Sets default SWT styles to widgets upon inititalizing as
15
- # per DEFAULT_STYLES
16
- #
17
- # Also, auto-initializes widgets as per initializer blocks
18
- # in DEFAULT_INITIALIZERS (e.g. setting Composite default layout)
19
- #
20
- # Follows the Proxy Design Pattern
21
- class WidgetProxy
22
- include Packages
23
- include DataBinding::ObservableWidget
24
-
25
- DEFAULT_STYLES = {
26
- "text" => [:border],
27
- "table" => [:border],
28
- "tree" => [:virtual, :border, :h_scroll, :v_scroll],
29
- "spinner" => [:border],
30
- "styled_text" => [:border],
31
- "list" => [:border, :v_scroll],
32
- "button" => [:push],
33
- "menu_item" => [:push],
34
- }
35
-
36
- DEFAULT_INITIALIZERS = {
37
- "composite" => lambda do |composite|
38
- composite.setLayout(GridLayout.new)
39
- end,
40
- "table" => lambda do |table|
41
- table.setHeaderVisible(true)
42
- table.setLinesVisible(true)
43
- end,
44
- "table_column" => lambda do |table_column|
45
- table_column.setWidth(80)
46
- end,
47
- "group" => lambda do |group|
48
- group.setLayout(GridLayout.new)
49
- end,
50
- }
51
-
52
- attr_reader :swt_widget
53
-
54
- # Initializes a new SWT Widget
55
- #
56
- # Styles is a comma separate list of symbols representing SWT styles in lower case
57
- def initialize(underscored_widget_name, parent, args)
58
- styles, extra_options = extract_args(underscored_widget_name, args)
59
- swt_widget_class = self.class.swt_widget_class_for(underscored_widget_name)
60
- @swt_widget = swt_widget_class.new(parent.swt_widget, style(underscored_widget_name, styles), *extra_options)
61
- DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@swt_widget)
62
- end
63
-
64
- def extract_args(underscored_widget_name, args)
65
- @arg_extractor_mapping ||= {
66
- 'menu_item' => lambda do |args|
67
- index = args.delete(args.last) if args.last.is_a?(Numeric)
68
- extra_options = [index].compact
69
- styles = args
70
- [styles, extra_options]
71
- end,
72
- }
73
- if @arg_extractor_mapping[underscored_widget_name]
74
- @arg_extractor_mapping[underscored_widget_name].call(args)
75
- else
76
- [args, []]
77
- end
78
- end
79
-
80
- def has_attribute?(attribute_name, *args)
81
- widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
82
- if widget_custom_attribute
83
- @swt_widget.respond_to?(widget_custom_attribute[:setter][:name])
84
- else
85
- @swt_widget.respond_to?(attribute_setter(attribute_name), args)
86
- end
87
- end
88
-
89
- def set_attribute(attribute_name, *args)
90
- widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
91
- if widget_custom_attribute
92
- widget_custom_attribute[:setter][:invoker].call(@swt_widget, args)
93
- else
94
- apply_property_type_converters(attribute_name, args)
95
- @swt_widget.send(attribute_setter(attribute_name), *args) unless @swt_widget.send(attribute_getter(attribute_name)) == args.first
96
- end
97
- end
98
-
99
- def get_attribute(attribute_name)
100
- widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
101
- if widget_custom_attribute
102
- @swt_widget.send(widget_custom_attribute[:getter][:name])
103
- else
104
- @swt_widget.send(attribute_getter(attribute_name))
105
- end
106
- end
107
-
108
- def pack_same_size
109
- bounds = @swt_widget.getBounds
110
- listener = on_control_resized {
111
- @swt_widget.setSize(bounds.width, bounds.height)
112
- @swt_widget.setLocation(bounds.x, bounds.y)
113
- }
114
- if @swt_widget.is_a?(Composite)
115
- @swt_widget.layout(true, true)
116
- else
117
- @swt_widget.pack(true)
118
- end
119
- @swt_widget.removeControlListener(listener.swt_listener)
120
- end
121
-
122
- def widget_property_listener_installers
123
- @swt_widget_property_listener_installers ||= {
124
- Java::OrgEclipseSwtWidgets::Control => {
125
- :focus => lambda do |observer|
126
- on_focus_gained { |focus_event|
127
- observer.call(true)
128
- }
129
- on_focus_lost { |focus_event|
130
- observer.call(false)
131
- }
132
- end,
133
- },
134
- Java::OrgEclipseSwtWidgets::Text => {
135
- :text => lambda do |observer|
136
- on_modify_text { |modify_event|
137
- observer.call(@swt_widget.getText)
138
- }
139
- end,
140
- :caret_position => lambda do |observer|
141
- on_event_keydown { |event|
142
- observer.call(@swt_widget.getCaretPosition)
143
- }
144
- on_event_keyup { |event|
145
- observer.call(@swt_widget.getCaretPosition)
146
- }
147
- on_event_mousedown { |event|
148
- observer.call(@swt_widget.getCaretPosition)
149
- }
150
- on_event_mouseup { |event|
151
- observer.call(@swt_widget.getCaretPosition)
152
- }
153
- end,
154
- :selection => lambda do |observer|
155
- on_event_keydown { |event|
156
- observer.call(@swt_widget.getSelection)
157
- }
158
- on_event_keyup { |event|
159
- observer.call(@swt_widget.getSelection)
160
- }
161
- on_event_mousedown { |event|
162
- observer.call(@swt_widget.getSelection)
163
- }
164
- on_event_mouseup { |event|
165
- observer.call(@swt_widget.getSelection)
166
- }
167
- end,
168
- :selection_count => lambda do |observer|
169
- on_event_keydown { |event|
170
- observer.call(@swt_widget.getSelectionCount)
171
- }
172
- on_event_keyup { |event|
173
- observer.call(@swt_widget.getSelectionCount)
174
- }
175
- on_event_mousedown { |event|
176
- observer.call(@swt_widget.getSelectionCount)
177
- }
178
- on_event_mouseup { |event|
179
- observer.call(@swt_widget.getSelectionCount)
180
- }
181
- end,
182
- :top_index => lambda do |observer|
183
- @last_top_index = @swt_widget.getTopIndex
184
- on_paint_control { |event|
185
- if @swt_widget.getTopIndex != @last_top_index
186
- @last_top_index = @swt_widget.getTopIndex
187
- observer.call(@last_top_index)
188
- end
189
- }
190
- end,
191
- },
192
- Java::OrgEclipseSwtCustom::StyledText => {
193
- :text => lambda do |observer|
194
- on_modify_text { |modify_event|
195
- observer.call(@swt_widget.getText)
196
- }
197
- end,
198
- },
199
- Java::OrgEclipseSwtWidgets::Button => {
200
- :selection => lambda do |observer|
201
- on_widget_selected { |selection_event|
202
- observer.call(@swt_widget.getSelection)
203
- }
204
- end
205
- },
206
- Java::OrgEclipseSwtWidgets::MenuItem => {
207
- :selection => lambda do |observer|
208
- on_widget_selected { |selection_event|
209
- observer.call(@swt_widget.getSelection)
210
- }
211
- end
212
- },
213
- Java::OrgEclipseSwtWidgets::Spinner => {
214
- :selection => lambda do |observer|
215
- on_widget_selected { |selection_event|
216
- observer.call(@swt_widget.getSelection)
217
- }
218
- end
219
- },
220
- }
221
- end
222
-
223
- def self.widget_exists?(underscored_widget_name)
224
- !!swt_widget_class_for(underscored_widget_name)
225
- end
226
-
227
- # This supports widgets in and out of basic SWT
228
- def self.swt_widget_class_for(underscored_widget_name)
229
- swt_widget_name = underscored_widget_name.camelcase(:upper)
230
- swt_widget_class = eval(swt_widget_name)
231
- unless swt_widget_class.ancestors.include?(org.eclipse.swt.widgets.Widget)
232
- Glimmer::Config.logger&.debug("Class #{swt_widget_class} matching #{underscored_widget_name} is not a subclass of org.eclipse.swt.widgets.Widget")
233
- return nil
234
- end
235
- swt_widget_class
236
- rescue NameError => e
237
- Glimmer::Config.logger&.debug e.message
238
- # Glimmer::Config.logger&.debug("#{e.message}\n#{e.backtrace.join("\n")}")
239
- nil
240
- rescue => e
241
- Glimmer::Config.logger&.debug e.message
242
- # Glimmer::Config.logger&.debug("#{e.message}\n#{e.backtrace.join("\n")}")
243
- nil
244
- end
245
-
246
- def async_exec(&block)
247
- DisplayProxy.instance.async_exec(&block)
248
- end
249
-
250
- def sync_exec(&block)
251
- DisplayProxy.instance.sync_exec(&block)
252
- end
253
-
254
- def has_style?(style)
255
- (@swt_widget.style & SWTProxy[style]) == SWTProxy[style]
256
- end
257
-
258
- def dispose
259
- @swt_widget.dispose
260
- end
261
-
262
- # TODO Consider renaming these methods as they are mainly used for data-binding
263
-
264
- def can_add_observer?(property_name)
265
- @swt_widget.class.ancestors.map {|ancestor| widget_property_listener_installers[ancestor]}.compact.map(&:keys).flatten.map(&:to_s).include?(property_name.to_s)
266
- end
267
-
268
- # Used for data-binding only. Consider renaming or improving to avoid the confusion it causes
269
- def add_observer(observer, property_name)
270
- property_listener_installers = @swt_widget.class.ancestors.map {|ancestor| widget_property_listener_installers[ancestor]}.compact
271
- widget_listener_installers = property_listener_installers.map{|installer| installer[property_name.to_s.to_sym]}.compact if !property_listener_installers.empty?
272
- widget_listener_installers.to_a.each do |widget_listener_installer|
273
- widget_listener_installer.call(observer)
274
- end
275
- end
276
-
277
- def remove_observer(observer, property_name)
278
- # TODO consider implementing if remove_observer is needed (consumers can remove listener via SWT API)
279
- end
280
-
281
- # TODO eliminate duplication in the following methods perhaps by relying on exceptions
282
-
283
- def can_handle_observation_request?(observation_request)
284
- observation_request = observation_request.to_s
285
- if observation_request.start_with?('on_event_')
286
- constant_name = observation_request.sub(/^on_event_/, '')
287
- SWTProxy.has_constant?(constant_name)
288
- elsif observation_request.start_with?('on_')
289
- event = observation_request.sub(/^on_/, '')
290
- can_add_listener?(event)
291
- else
292
- false
293
- end
294
- end
295
-
296
- def handle_observation_request(observation_request, &block)
297
- if observation_request.start_with?('on_event_')
298
- constant_name = observation_request.sub(/^on_event_/, '')
299
- add_swt_event_listener(constant_name, &block)
300
- elsif observation_request.start_with?('on_')
301
- event = observation_request.sub(/^on_/, '')
302
- add_listener(event, &block)
303
- end
304
- end
305
-
306
- def content(&block)
307
- Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::SWT::WidgetExpression.new, &block)
308
- end
309
-
310
- private
311
-
312
- def style(underscored_widget_name, styles)
313
- styles = [styles].flatten.compact
314
- styles.empty? ? default_style(underscored_widget_name) : SWTProxy[*styles]
315
- end
316
-
317
- def default_style(underscored_widget_name)
318
- styles = DEFAULT_STYLES[underscored_widget_name] || [:none]
319
- SWTProxy[styles]
320
- end
321
-
322
- def attribute_setter(attribute_name)
323
- "set#{attribute_name.to_s.camelcase(:upper)}"
324
- end
325
-
326
- def attribute_getter(attribute_name)
327
- "get#{attribute_name.to_s.camelcase(:upper)}"
328
- end
329
-
330
- # TODO refactor following methods to eliminate duplication
331
- # perhaps consider relying on raising an exception to avoid checking first
332
- # unless that gives obscure SWT errors
333
- # Otherwise, consider caching results from can_add_lsitener and using them in
334
- # add_listener knowing it will be called for sure afterwards
335
-
336
- def can_add_listener?(underscored_listener_name)
337
- !self.class.find_listener(@swt_widget.getClass, underscored_listener_name).empty?
338
- end
339
-
340
- def add_listener(underscored_listener_name, &block)
341
- widget_add_listener_method, listener_class, listener_method = self.class.find_listener(@swt_widget.getClass, underscored_listener_name)
342
- widget_listener_proxy = nil
343
- safe_block = lambda { |event| block.call(event) unless @swt_widget.isDisposed }
344
- listener = listener_class.new(listener_method => safe_block)
345
- @swt_widget.send(widget_add_listener_method, listener)
346
- widget_listener_proxy = WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: listener, widget_add_listener_method: widget_add_listener_method, swt_listener_class: listener_class, swt_listener_method: listener_method)
347
- end
348
-
349
- # Looks through SWT class add***Listener methods till it finds one for which
350
- # the argument is a listener class that has an event method matching
351
- # underscored_listener_name
352
- def self.find_listener(swt_widget_class, underscored_listener_name)
353
- @listeners ||= {}
354
- listener_key = [swt_widget_class.name, underscored_listener_name]
355
- unless @listeners.has_key?(listener_key)
356
- listener_method_name = underscored_listener_name.camelcase(:lower)
357
- swt_widget_class.getMethods.each do |widget_add_listener_method|
358
- if widget_add_listener_method.getName.match(/add.*Listener/)
359
- widget_add_listener_method.getParameterTypes.each do |listener_type|
360
- listener_type.getMethods.each do |listener_method|
361
- if (listener_method.getName == listener_method_name)
362
- @listeners[listener_key] = [widget_add_listener_method.getName, listener_class(listener_type), listener_method.getName]
363
- return @listeners[listener_key]
364
- end
365
- end
366
- end
367
- end
368
- end
369
- @listeners[listener_key] = []
370
- end
371
- @listeners[listener_key]
372
- end
373
-
374
- # Returns a Ruby class that implements listener type Java interface with ability to easily
375
- # install a block that gets called upon calling a listener event method
376
- def self.listener_class(listener_type)
377
- @listener_classes ||= {}
378
- listener_class_key = listener_type.name
379
- unless @listener_classes.has_key?(listener_class_key)
380
- @listener_classes[listener_class_key] = Class.new(Object).tap do |listener_class|
381
- listener_class.send :include, (eval listener_type.name.sub("interface", ""))
382
- listener_class.define_method('initialize') do |event_method_block_mapping|
383
- @event_method_block_mapping = event_method_block_mapping
384
- end
385
- listener_type.getMethods.each do |event_method|
386
- listener_class.define_method(event_method.getName) do |event|
387
- @event_method_block_mapping[event_method.getName]&.call(event)
388
- end
389
- end
390
- end
391
- end
392
- @listener_classes[listener_class_key]
393
- end
394
-
395
- def add_swt_event_listener(swt_constant, &block)
396
- event_type = SWTProxy[swt_constant]
397
- widget_listener_proxy = nil
398
- safe_block = lambda { |event| block.call(event) unless @swt_widget.isDisposed }
399
- @swt_widget.addListener(event_type, &safe_block)
400
- widget_listener_proxy = WidgetListenerProxy.new(swt_widget: @swt_widget, swt_listener: @swt_widget.getListeners(event_type).last, event_type: event_type, swt_constant: swt_constant)
401
- end
402
-
403
- def widget_custom_attribute_mapping
404
- @swt_widget_custom_attribute_mapping ||= {
405
- 'focus' => {
406
- getter: {name: 'isFocusControl'},
407
- setter: {name: 'setFocus', invoker: lambda { |widget, args| @swt_widget.setFocus if args.first }},
408
- },
409
- 'caret_position' => {
410
- getter: {name: 'getCaretPosition'},
411
- setter: {name: 'setSelection', invoker: lambda { |widget, args| @swt_widget.setSelection(args.first) if args.first }},
412
- },
413
- 'selection_count' => {
414
- getter: {name: 'getSelectionCount'},
415
- setter: {name: 'setSelection', invoker: lambda { |widget, args| @swt_widget.setSelection(@swt_widget.getCaretPosition, @swt_widget.getCaretPosition + args.first) if args.first }},
416
- },
417
- }
418
- end
419
-
420
- def apply_property_type_converters(attribute_name, args)
421
- if args.count == 1
422
- value = args.first
423
- converter = property_type_converters[attribute_name.to_sym]
424
- args[0] = converter.call(value) if converter
425
- end
426
- if args.count == 1 && args.first.is_a?(ColorProxy)
427
- g_color = args.first
428
- args[0] = g_color.swt_color
429
- end
430
- end
431
-
432
- def property_type_converters
433
- color_converter = lambda do |value|
434
- if value.is_a?(Symbol) || value.is_a?(String)
435
- ColorProxy.new(value).swt_color
436
- else
437
- value
438
- end
439
- end
440
- # TODO consider detecting type on widget method and automatically invoking right converter (e.g. :to_s for String, :to_i for Integer)
441
- @property_type_converters ||= {
442
- :background => color_converter,
443
- :background_image => lambda do |value|
444
- if value.is_a?(String)
445
- if value.start_with?('uri:classloader')
446
- value = value.sub(/^uri\:classloader\:\//, '')
447
- object = java.lang.Object.new
448
- value = object.java_class.resource_as_stream(value)
449
- value = java.io.BufferedInputStream.new(value)
450
- end
451
- image_data = ImageData.new(value)
452
- # TODO in the future, look into unregistering this listener when no longer needed
453
- on_event_Resize do |resize_event|
454
- new_image_data = image_data.scaledTo(@swt_widget.getSize.x, @swt_widget.getSize.y)
455
- @swt_widget.getBackgroundImage&.dispose
456
- @swt_widget.setBackgroundImage(Image.new(@swt_widget.getDisplay, new_image_data))
457
- end
458
- Image.new(@swt_widget.getDisplay, image_data)
459
- else
460
- value
461
- end
462
- end,
463
- :foreground => color_converter,
464
- :font => lambda do |value|
465
- if value.is_a?(Hash)
466
- font_properties = value
467
- FontProxy.new(self, font_properties).swt_font
468
- else
469
- value
470
- end
471
- end,
472
- :items => lambda do |value|
473
- value.to_java :string
474
- end,
475
- :text => lambda do |value|
476
- if swt_widget.is_a?(Browser)
477
- value.to_s
478
- else
479
- value.to_s
480
- end
481
- end,
482
- :visible => lambda do |value|
483
- !!value
484
- end,
485
- }
486
- end
487
- end
488
- end
489
- end