glimmer 0.5.8 → 0.5.9
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.
- checksums.yaml +4 -4
- data/README.markdown +138 -84
- data/bin/gladiator +6 -0
- data/lib/glimmer.rb +1 -0
- data/lib/glimmer/data_binding/list_selection_binding.rb +1 -1
- data/lib/glimmer/data_binding/widget_binding.rb +33 -33
- data/lib/glimmer/dsl/custom_widget_expression.rb +0 -1
- data/lib/glimmer/dsl/display_expression.rb +2 -0
- data/lib/glimmer/dsl/tree_items_data_binding_expression.rb +9 -10
- data/lib/glimmer/dsl/widget_listener_expression.rb +4 -3
- data/lib/glimmer/launcher.rb +8 -2
- data/lib/glimmer/swt/display_proxy.rb +25 -0
- data/lib/glimmer/swt/layout_proxy.rb +0 -1
- data/lib/glimmer/swt/shell_proxy.rb +17 -0
- data/lib/glimmer/swt/swt_proxy.rb +4 -0
- data/lib/glimmer/swt/widget_proxy.rb +444 -391
- data/lib/glimmer/ui/custom_shell.rb +1 -1
- data/lib/glimmer/ui/custom_widget.rb +38 -19
- data/lib/glimmer/ui/video.rb +0 -1
- data/samples/gladiator.rb +709 -0
- metadata +35 -4
data/lib/glimmer/launcher.rb
CHANGED
@@ -64,7 +64,13 @@ module Glimmer
|
|
64
64
|
jruby_options_string = jruby_options.join(' ') + ' ' if jruby_options.any?
|
65
65
|
env_vars_string = env_vars.map {|k,v| "#{k}=#{v}"}.join(' ')
|
66
66
|
env_vars_string = [env_vars_string, glimmer_option_env_vars(glimmer_options)].join(' ')
|
67
|
-
|
67
|
+
the_glimmer_lib = glimmer_lib
|
68
|
+
devmode_require = nil
|
69
|
+
if the_glimmer_lib == GLIMMER_LIB_LOCAL
|
70
|
+
devmode_require = '-r puts_debuggerer '
|
71
|
+
end
|
72
|
+
puts "#{env_vars_string} jruby #{jruby_options_string}#{jruby_os_specific_options} -r #{the_glimmer_lib} #{devmode_require}-S \"#{application}\"" if jruby_options_string.to_s.include?('--debug')
|
73
|
+
system "#{env_vars_string} jruby #{jruby_options_string}#{jruby_os_specific_options} -r #{the_glimmer_lib} #{devmode_require}-S \"#{application}\""
|
68
74
|
end
|
69
75
|
end
|
70
76
|
|
@@ -87,7 +93,7 @@ module Glimmer
|
|
87
93
|
|
88
94
|
def launch_application
|
89
95
|
threads = @application_paths.map do |application_path|
|
90
|
-
puts "Launching Glimmer Application: #{application_path}" unless application_path.to_s.
|
96
|
+
puts "Launching Glimmer Application: #{application_path}" unless application_path.to_s.match(/(irb)|(gladiator)/)
|
91
97
|
Thread.new do
|
92
98
|
self.class.launch(
|
93
99
|
application_path,
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'glimmer/swt/widget_listener_proxy'
|
2
|
+
|
1
3
|
module Glimmer
|
2
4
|
module SWT
|
3
5
|
# Proxy for org.eclipse.swt.widgets.Display
|
@@ -44,6 +46,29 @@ module Glimmer
|
|
44
46
|
def sync_exec(&block)
|
45
47
|
@swt_display.syncExec(&block)
|
46
48
|
end
|
49
|
+
|
50
|
+
def can_handle_observation_request?(observation_request)
|
51
|
+
observation_request = observation_request.to_s
|
52
|
+
if observation_request.start_with?('on_event_')
|
53
|
+
constant_name = observation_request.sub(/^on_event_/, '')
|
54
|
+
SWTProxy.has_constant?(constant_name)
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def handle_observation_request(observation_request, &block)
|
61
|
+
if observation_request.start_with?('on_event_')
|
62
|
+
constant_name = observation_request.sub(/^on_event_/, '')
|
63
|
+
add_swt_event_listener(constant_name, &block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def add_swt_event_listener(swt_constant, &block)
|
68
|
+
event_type = SWTProxy[swt_constant]
|
69
|
+
@swt_display.addFilter(event_type, &block)
|
70
|
+
#WidgetListenerProxy.new(@swt_display.getListeners(event_type).last)
|
71
|
+
end
|
47
72
|
end
|
48
73
|
end
|
49
74
|
end
|
@@ -84,6 +84,23 @@ module Glimmer
|
|
84
84
|
visibility ? show : hide
|
85
85
|
end
|
86
86
|
|
87
|
+
def pack
|
88
|
+
@swt_widget.pack
|
89
|
+
end
|
90
|
+
|
91
|
+
def pack_same_size
|
92
|
+
minimum_size = @swt_widget.getMinimumSize
|
93
|
+
bounds = @swt_widget.getBounds
|
94
|
+
@swt_widget.setMinimumSize(bounds.width, bounds.height)
|
95
|
+
listener = on_control_resized {
|
96
|
+
@swt_widget.setSize(bounds.width, bounds.height)
|
97
|
+
@swt_widget.setLocation(bounds.x, bounds.y)
|
98
|
+
}
|
99
|
+
@swt_widget.pack
|
100
|
+
@swt_widget.removeControlListener(listener.swt_listener)
|
101
|
+
@swt_widget.setMinimumSize(minimum_size)
|
102
|
+
end
|
103
|
+
|
87
104
|
def content(&block)
|
88
105
|
Glimmer::DSL::Engine.add_content(self, DSL::ShellExpression.new, &block)
|
89
106
|
end
|
@@ -1,391 +1,444 @@
|
|
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
|
-
require 'glimmer/dsl/widget_expression'
|
8
|
-
|
9
|
-
module Glimmer
|
10
|
-
module SWT
|
11
|
-
# Proxy for SWT Widget objects
|
12
|
-
#
|
13
|
-
# Sets default SWT styles to widgets upon inititalizing as
|
14
|
-
# per DEFAULT_STYLES
|
15
|
-
#
|
16
|
-
# Also, auto-initializes widgets as per initializer blocks
|
17
|
-
# in DEFAULT_INITIALIZERS (e.g. setting Composite default layout)
|
18
|
-
#
|
19
|
-
# Follows the Proxy Design Pattern
|
20
|
-
class WidgetProxy
|
21
|
-
include Packages
|
22
|
-
include DataBinding::ObservableWidget
|
23
|
-
|
24
|
-
DEFAULT_STYLES = {
|
25
|
-
"text" => [:border],
|
26
|
-
"table" => [:border],
|
27
|
-
"spinner" => [:border],
|
28
|
-
"
|
29
|
-
"
|
30
|
-
"
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
table.
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
#
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
end
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
end
|
239
|
-
|
240
|
-
def
|
241
|
-
|
242
|
-
end
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
end
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
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
|
+
require 'glimmer/dsl/widget_expression'
|
8
|
+
|
9
|
+
module Glimmer
|
10
|
+
module SWT
|
11
|
+
# Proxy for SWT Widget objects
|
12
|
+
#
|
13
|
+
# Sets default SWT styles to widgets upon inititalizing as
|
14
|
+
# per DEFAULT_STYLES
|
15
|
+
#
|
16
|
+
# Also, auto-initializes widgets as per initializer blocks
|
17
|
+
# in DEFAULT_INITIALIZERS (e.g. setting Composite default layout)
|
18
|
+
#
|
19
|
+
# Follows the Proxy Design Pattern
|
20
|
+
class WidgetProxy
|
21
|
+
include Packages
|
22
|
+
include DataBinding::ObservableWidget
|
23
|
+
|
24
|
+
DEFAULT_STYLES = {
|
25
|
+
"text" => [:border],
|
26
|
+
"table" => [:border],
|
27
|
+
"spinner" => [:border],
|
28
|
+
"styled_text" => [:border],
|
29
|
+
"list" => [:border, :v_scroll],
|
30
|
+
"button" => [:push],
|
31
|
+
"menu_item" => [:push],
|
32
|
+
}
|
33
|
+
|
34
|
+
DEFAULT_INITIALIZERS = {
|
35
|
+
"composite" => proc do |composite|
|
36
|
+
composite.setLayout(GridLayout.new)
|
37
|
+
end,
|
38
|
+
"table" => proc do |table|
|
39
|
+
table.setHeaderVisible(true)
|
40
|
+
table.setLinesVisible(true)
|
41
|
+
end,
|
42
|
+
"table_column" => proc do |table_column|
|
43
|
+
table_column.setWidth(80)
|
44
|
+
end,
|
45
|
+
"group" => proc do |group|
|
46
|
+
group.setLayout(GridLayout.new)
|
47
|
+
end,
|
48
|
+
}
|
49
|
+
|
50
|
+
attr_reader :swt_widget
|
51
|
+
|
52
|
+
# Initializes a new SWT Widget
|
53
|
+
#
|
54
|
+
# Styles is a comma separate list of symbols representing SWT styles in lower case
|
55
|
+
def initialize(underscored_widget_name, parent, args)
|
56
|
+
styles, extra_options = extract_args(underscored_widget_name, args)
|
57
|
+
swt_widget_class = self.class.swt_widget_class_for(underscored_widget_name)
|
58
|
+
@swt_widget = swt_widget_class.new(parent.swt_widget, style(underscored_widget_name, styles), *extra_options)
|
59
|
+
DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@swt_widget)
|
60
|
+
end
|
61
|
+
|
62
|
+
def extract_args(underscored_widget_name, args)
|
63
|
+
@arg_extractor_mapping ||= {
|
64
|
+
'menu_item' => lambda do |args|
|
65
|
+
index = args.delete(args.last) if args.last.is_a?(Numeric)
|
66
|
+
extra_options = [index].compact
|
67
|
+
styles = args
|
68
|
+
[styles, extra_options]
|
69
|
+
end,
|
70
|
+
}
|
71
|
+
if @arg_extractor_mapping[underscored_widget_name]
|
72
|
+
@arg_extractor_mapping[underscored_widget_name].call(args)
|
73
|
+
else
|
74
|
+
[args, []]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def has_attribute?(attribute_name, *args)
|
79
|
+
widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
|
80
|
+
if widget_custom_attribute
|
81
|
+
@swt_widget.respond_to?(widget_custom_attribute[:setter][:name])
|
82
|
+
else
|
83
|
+
@swt_widget.respond_to?(attribute_setter(attribute_name), args)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def set_attribute(attribute_name, *args)
|
88
|
+
widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
|
89
|
+
if widget_custom_attribute
|
90
|
+
widget_custom_attribute[:setter][:invoker].call(@swt_widget, args)
|
91
|
+
else
|
92
|
+
apply_property_type_converters(attribute_name, args)
|
93
|
+
@swt_widget.send(attribute_setter(attribute_name), *args) unless @swt_widget.send(attribute_getter(attribute_name)) == args.first
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def get_attribute(attribute_name)
|
98
|
+
widget_custom_attribute = widget_custom_attribute_mapping[attribute_name.to_s]
|
99
|
+
if widget_custom_attribute
|
100
|
+
@swt_widget.send(widget_custom_attribute[:getter][:name])
|
101
|
+
else
|
102
|
+
@swt_widget.send(attribute_getter(attribute_name))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def widget_property_listener_installers
|
107
|
+
@swt_widget_property_listener_installers ||= {
|
108
|
+
Java::OrgEclipseSwtWidgets::Control => {
|
109
|
+
:focus => proc do |observer|
|
110
|
+
on_focus_gained { |focus_event|
|
111
|
+
observer.call(true)
|
112
|
+
}
|
113
|
+
on_focus_lost { |focus_event|
|
114
|
+
observer.call(false)
|
115
|
+
}
|
116
|
+
end,
|
117
|
+
},
|
118
|
+
Java::OrgEclipseSwtWidgets::Text => {
|
119
|
+
:text => proc do |observer|
|
120
|
+
on_modify_text { |modify_event|
|
121
|
+
observer.call(@swt_widget.getText)
|
122
|
+
}
|
123
|
+
end,
|
124
|
+
:caret_position => proc do |observer|
|
125
|
+
on_event_keydown { |event|
|
126
|
+
observer.call(@swt_widget.getCaretPosition)
|
127
|
+
}
|
128
|
+
on_event_keyup { |event|
|
129
|
+
observer.call(@swt_widget.getCaretPosition)
|
130
|
+
}
|
131
|
+
on_event_mousedown { |event|
|
132
|
+
observer.call(@swt_widget.getCaretPosition)
|
133
|
+
}
|
134
|
+
on_event_mouseup { |event|
|
135
|
+
observer.call(@swt_widget.getCaretPosition)
|
136
|
+
}
|
137
|
+
end,
|
138
|
+
:selection_count => proc do |observer|
|
139
|
+
on_event_keydown { |event|
|
140
|
+
observer.call(@swt_widget.getSelectionCount)
|
141
|
+
}
|
142
|
+
on_event_keyup { |event|
|
143
|
+
observer.call(@swt_widget.getSelectionCount)
|
144
|
+
}
|
145
|
+
on_event_mousedown { |event|
|
146
|
+
observer.call(@swt_widget.getSelectionCount)
|
147
|
+
}
|
148
|
+
on_event_mouseup { |event|
|
149
|
+
observer.call(@swt_widget.getSelectionCount)
|
150
|
+
}
|
151
|
+
end,
|
152
|
+
:top_index => proc do |observer|
|
153
|
+
@last_top_index = @swt_widget.getTopIndex
|
154
|
+
on_paint_control { |event|
|
155
|
+
if @swt_widget.getTopIndex != @last_top_index
|
156
|
+
@last_top_index = @swt_widget.getTopIndex
|
157
|
+
observer.call(@last_top_index)
|
158
|
+
end
|
159
|
+
}
|
160
|
+
end,
|
161
|
+
},
|
162
|
+
Java::OrgEclipseSwtCustom::StyledText => {
|
163
|
+
:text => proc do |observer|
|
164
|
+
on_modify_text { |modify_event|
|
165
|
+
observer.call(@swt_widget.getText)
|
166
|
+
}
|
167
|
+
end,
|
168
|
+
},
|
169
|
+
Java::OrgEclipseSwtWidgets::Button => {
|
170
|
+
:selection => proc do |observer|
|
171
|
+
on_widget_selected { |selection_event|
|
172
|
+
observer.call(@swt_widget.getSelection)
|
173
|
+
}
|
174
|
+
end
|
175
|
+
},
|
176
|
+
Java::OrgEclipseSwtWidgets::Spinner => {
|
177
|
+
:selection => proc do |observer|
|
178
|
+
on_widget_selected { |selection_event|
|
179
|
+
observer.call(@swt_widget.getSelection)
|
180
|
+
}
|
181
|
+
end
|
182
|
+
}
|
183
|
+
}
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.widget_exists?(underscored_widget_name)
|
187
|
+
!!swt_widget_class_for(underscored_widget_name)
|
188
|
+
end
|
189
|
+
|
190
|
+
# This supports widgets in and out of basic SWT
|
191
|
+
def self.swt_widget_class_for(underscored_widget_name)
|
192
|
+
swt_widget_name = underscored_widget_name.camelcase(:upper)
|
193
|
+
swt_widget_class = eval(swt_widget_name)
|
194
|
+
unless swt_widget_class.ancestors.include?(org.eclipse.swt.widgets.Widget)
|
195
|
+
Glimmer.logger&.debug("Class #{swt_widget_class} matching #{underscored_widget_name} is not a subclass of org.eclipse.swt.widgets.Widget")
|
196
|
+
return nil
|
197
|
+
end
|
198
|
+
swt_widget_class
|
199
|
+
rescue NameError => e
|
200
|
+
Glimmer.logger&.debug e.message
|
201
|
+
# Glimmer.logger&.debug("#{e.message}\n#{e.backtrace.join("\n")}")
|
202
|
+
nil
|
203
|
+
rescue => e
|
204
|
+
Glimmer.logger&.debug e.message
|
205
|
+
# Glimmer.logger&.debug("#{e.message}\n#{e.backtrace.join("\n")}")
|
206
|
+
nil
|
207
|
+
end
|
208
|
+
|
209
|
+
def async_exec(&block)
|
210
|
+
DisplayProxy.instance.async_exec(&block)
|
211
|
+
end
|
212
|
+
|
213
|
+
def sync_exec(&block)
|
214
|
+
DisplayProxy.instance.sync_exec(&block)
|
215
|
+
end
|
216
|
+
|
217
|
+
def has_style?(style)
|
218
|
+
(@swt_widget.style & SWTProxy[style]) == SWTProxy[style]
|
219
|
+
end
|
220
|
+
|
221
|
+
def dispose
|
222
|
+
@swt_widget.dispose
|
223
|
+
end
|
224
|
+
|
225
|
+
# TODO Consider renaming these methods as they are mainly used for data-binding
|
226
|
+
|
227
|
+
def can_add_observer?(property_name)
|
228
|
+
@swt_widget.class.ancestors.map {|ancestor| widget_property_listener_installers[ancestor]}.compact.map(&:keys).flatten.map(&:to_s).include?(property_name.to_s)
|
229
|
+
end
|
230
|
+
|
231
|
+
# Used for data-binding only. Consider renaming or improving to avoid the confusion it causes
|
232
|
+
def add_observer(observer, property_name)
|
233
|
+
property_listener_installers = @swt_widget.class.ancestors.map {|ancestor| widget_property_listener_installers[ancestor]}.compact
|
234
|
+
widget_listener_installers = property_listener_installers.map{|installer| installer[property_name.to_s.to_sym]}.compact if !property_listener_installers.empty?
|
235
|
+
widget_listener_installers.each do |widget_listener_installer|
|
236
|
+
widget_listener_installer.call(observer)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def remove_observer(observer, property_name)
|
241
|
+
# TODO consider implementing if remove_observer is needed (consumers can remove listener via SWT API)
|
242
|
+
end
|
243
|
+
|
244
|
+
# TODO eliminate duplication in the following methods perhaps by relying on exceptions
|
245
|
+
|
246
|
+
def can_handle_observation_request?(observation_request)
|
247
|
+
observation_request = observation_request.to_s
|
248
|
+
if observation_request.start_with?('on_event_')
|
249
|
+
constant_name = observation_request.sub(/^on_event_/, '')
|
250
|
+
SWTProxy.has_constant?(constant_name)
|
251
|
+
elsif observation_request.start_with?('on_')
|
252
|
+
event = observation_request.sub(/^on_/, '')
|
253
|
+
can_add_listener?(event)
|
254
|
+
else
|
255
|
+
false
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def handle_observation_request(observation_request, &block)
|
260
|
+
if observation_request.start_with?('on_event_')
|
261
|
+
constant_name = observation_request.sub(/^on_event_/, '')
|
262
|
+
add_swt_event_listener(constant_name, &block)
|
263
|
+
elsif observation_request.start_with?('on_')
|
264
|
+
event = observation_request.sub(/^on_/, '')
|
265
|
+
add_listener(event, &block)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def content(&block)
|
270
|
+
Glimmer::DSL::Engine.add_content(self, DSL::WidgetExpression.new, &block)
|
271
|
+
end
|
272
|
+
|
273
|
+
private
|
274
|
+
|
275
|
+
def style(underscored_widget_name, styles)
|
276
|
+
styles = [styles].flatten.compact
|
277
|
+
styles.empty? ? default_style(underscored_widget_name) : SWTProxy[*styles]
|
278
|
+
end
|
279
|
+
|
280
|
+
def default_style(underscored_widget_name)
|
281
|
+
styles = DEFAULT_STYLES[underscored_widget_name] || [:none]
|
282
|
+
SWTProxy[styles]
|
283
|
+
end
|
284
|
+
|
285
|
+
def attribute_setter(attribute_name)
|
286
|
+
"set#{attribute_name.to_s.camelcase(:upper)}"
|
287
|
+
end
|
288
|
+
|
289
|
+
def attribute_getter(attribute_name)
|
290
|
+
"get#{attribute_name.to_s.camelcase(:upper)}"
|
291
|
+
end
|
292
|
+
|
293
|
+
# TODO refactor following methods to eliminate duplication
|
294
|
+
# perhaps consider relying on raising an exception to avoid checking first
|
295
|
+
# unless that gives obscure SWT errors
|
296
|
+
# Otherwise, consider caching results from can_add_lsitener and using them in
|
297
|
+
# add_listener knowing it will be called for sure afterwards
|
298
|
+
|
299
|
+
def can_add_listener?(underscored_listener_name)
|
300
|
+
!self.class.find_listener(@swt_widget.getClass, underscored_listener_name).empty?
|
301
|
+
end
|
302
|
+
|
303
|
+
def add_listener(underscored_listener_name, &block)
|
304
|
+
widget_add_listener_method, listener_class, listener_method = self.class.find_listener(@swt_widget.getClass, underscored_listener_name)
|
305
|
+
listener = listener_class.new(listener_method => block)
|
306
|
+
@swt_widget.send(widget_add_listener_method, listener)
|
307
|
+
WidgetListenerProxy.new(listener)
|
308
|
+
end
|
309
|
+
|
310
|
+
# Looks through SWT class add***Listener methods till it finds one for which
|
311
|
+
# the argument is a listener class that has an event method matching
|
312
|
+
# underscored_listener_name
|
313
|
+
def self.find_listener(swt_widget_class, underscored_listener_name)
|
314
|
+
@listeners ||= {}
|
315
|
+
listener_key = [swt_widget_class.name, underscored_listener_name]
|
316
|
+
unless @listeners.has_key?(listener_key)
|
317
|
+
listener_method_name = underscored_listener_name.camelcase(:lower)
|
318
|
+
swt_widget_class.getMethods.each do |widget_add_listener_method|
|
319
|
+
if widget_add_listener_method.getName.match(/add.*Listener/)
|
320
|
+
widget_add_listener_method.getParameterTypes.each do |listener_type|
|
321
|
+
listener_type.getMethods.each do |listener_method|
|
322
|
+
if (listener_method.getName == listener_method_name)
|
323
|
+
@listeners[listener_key] = [widget_add_listener_method.getName, listener_class(listener_type), listener_method.getName]
|
324
|
+
return @listeners[listener_key]
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
@listeners[listener_key] = []
|
331
|
+
end
|
332
|
+
@listeners[listener_key]
|
333
|
+
end
|
334
|
+
|
335
|
+
# Returns a Ruby class that implements listener type Java interface with ability to easily
|
336
|
+
# install a block that gets called upon calling a listener event method
|
337
|
+
def self.listener_class(listener_type)
|
338
|
+
@listener_classes ||= {}
|
339
|
+
listener_class_key = listener_type.name
|
340
|
+
unless @listener_classes.has_key?(listener_class_key)
|
341
|
+
@listener_classes[listener_class_key] = Class.new(Object).tap do |listener_class|
|
342
|
+
listener_class.send :include, (eval listener_type.name.sub("interface", ""))
|
343
|
+
listener_class.define_method('initialize') do |event_method_block_mapping|
|
344
|
+
@event_method_block_mapping = event_method_block_mapping
|
345
|
+
end
|
346
|
+
listener_type.getMethods.each do |event_method|
|
347
|
+
listener_class.define_method(event_method.getName) do |event|
|
348
|
+
@event_method_block_mapping[event_method.getName]&.call(event)
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
end
|
353
|
+
@listener_classes[listener_class_key]
|
354
|
+
end
|
355
|
+
|
356
|
+
def add_swt_event_listener(swt_constant, &block)
|
357
|
+
event_type = SWTProxy[swt_constant]
|
358
|
+
@swt_widget.addListener(event_type, &block)
|
359
|
+
WidgetListenerProxy.new(@swt_widget.getListeners(event_type).last)
|
360
|
+
end
|
361
|
+
|
362
|
+
def widget_custom_attribute_mapping
|
363
|
+
@swt_widget_custom_attribute_mapping ||= {
|
364
|
+
'focus' => {
|
365
|
+
getter: {name: 'isFocusControl'},
|
366
|
+
setter: {name: 'setFocus', invoker: lambda { |widget, args| @swt_widget.setFocus if args.first }},
|
367
|
+
},
|
368
|
+
'caret_position' => {
|
369
|
+
getter: {name: 'getCaretPosition'},
|
370
|
+
setter: {name: 'setSelection', invoker: lambda { |widget, args| @swt_widget.setSelection(args.first) if args.first }},
|
371
|
+
},
|
372
|
+
'selection_count' => {
|
373
|
+
getter: {name: 'getSelectionCount'},
|
374
|
+
setter: {name: 'setSelection', invoker: lambda { |widget, args| @swt_widget.setSelection(@swt_widget.getCaretPosition, @swt_widget.getCaretPosition + args.first) if args.first }},
|
375
|
+
},
|
376
|
+
}
|
377
|
+
end
|
378
|
+
|
379
|
+
def apply_property_type_converters(attribute_name, args)
|
380
|
+
if args.count == 1
|
381
|
+
value = args.first
|
382
|
+
converter = property_type_converters[attribute_name.to_sym]
|
383
|
+
args[0] = converter.call(value) if converter
|
384
|
+
end
|
385
|
+
if args.count == 1 && args.first.is_a?(ColorProxy)
|
386
|
+
g_color = args.first
|
387
|
+
args[0] = g_color.swt_color
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def property_type_converters
|
392
|
+
color_converter = proc do |value|
|
393
|
+
if value.is_a?(Symbol) || value.is_a?(String)
|
394
|
+
ColorProxy.new(value).swt_color
|
395
|
+
else
|
396
|
+
value
|
397
|
+
end
|
398
|
+
end
|
399
|
+
# TODO consider detecting type on widget method and automatically invoking right converter (e.g. :to_s for String, :to_i for Integer)
|
400
|
+
@property_type_converters ||= {
|
401
|
+
:background => color_converter,
|
402
|
+
:background_image => proc do |value|
|
403
|
+
if value.is_a?(String)
|
404
|
+
if value.start_with?('uri:classloader')
|
405
|
+
value = value.sub(/^uri\:classloader\:\//, '')
|
406
|
+
object = java.lang.Object.new
|
407
|
+
value = object.java_class.resource_as_stream(value)
|
408
|
+
value = java.io.BufferedInputStream.new(value)
|
409
|
+
end
|
410
|
+
image_data = ImageData.new(value)
|
411
|
+
# TODO in the future, look into unregistering this listener when no longer needed
|
412
|
+
on_event_Resize do |resize_event|
|
413
|
+
new_image_data = image_data.scaledTo(@swt_widget.getSize.x, @swt_widget.getSize.y)
|
414
|
+
@swt_widget.getBackgroundImage&.dispose
|
415
|
+
@swt_widget.setBackgroundImage(Image.new(@swt_widget.getDisplay, new_image_data))
|
416
|
+
end
|
417
|
+
Image.new(@swt_widget.getDisplay, image_data)
|
418
|
+
else
|
419
|
+
value
|
420
|
+
end
|
421
|
+
end,
|
422
|
+
:foreground => color_converter,
|
423
|
+
:font => proc do |value|
|
424
|
+
if value.is_a?(Hash)
|
425
|
+
font_properties = value
|
426
|
+
FontProxy.new(self, font_properties).swt_font
|
427
|
+
else
|
428
|
+
value
|
429
|
+
end
|
430
|
+
end,
|
431
|
+
:items => proc do |value|
|
432
|
+
value.to_java :string
|
433
|
+
end,
|
434
|
+
:text => proc do |value|
|
435
|
+
value.to_s
|
436
|
+
end,
|
437
|
+
:visible => proc do |value|
|
438
|
+
!!value
|
439
|
+
end,
|
440
|
+
}
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
end
|