glimmer-dsl-swt 4.18.3.4 → 4.18.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -0
- data/README.md +600 -331
- data/VERSION +1 -1
- data/glimmer-dsl-swt.gemspec +8 -3
- data/lib/ext/rouge/themes/glimmer.rb +29 -0
- data/lib/glimmer-dsl-swt.rb +0 -1
- data/lib/glimmer/data_binding/widget_binding.rb +1 -1
- data/lib/glimmer/swt/custom/code_text.rb +200 -51
- data/lib/glimmer/swt/custom/drawable.rb +1 -4
- data/lib/glimmer/swt/custom/shape.rb +50 -6
- data/lib/glimmer/swt/date_time_proxy.rb +1 -3
- data/lib/glimmer/swt/display_proxy.rb +11 -0
- data/lib/glimmer/swt/font_proxy.rb +1 -0
- data/lib/glimmer/swt/image_proxy.rb +11 -0
- data/lib/glimmer/swt/layout_proxy.rb +4 -1
- data/lib/glimmer/swt/shell_proxy.rb +4 -1
- data/lib/glimmer/swt/table_proxy.rb +17 -13
- data/lib/glimmer/swt/widget_proxy.rb +11 -3
- data/samples/elaborate/meta_sample.rb +15 -4
- data/samples/elaborate/meta_sample/meta_sample_logo.png +0 -0
- data/samples/elaborate/tetris.rb +16 -6
- data/samples/elaborate/tetris/model/game.rb +3 -3
- data/samples/elaborate/tetris/model/past_game.rb +14 -1
- data/samples/elaborate/tetris/view/block.rb +1 -1
- data/samples/elaborate/tetris/view/high_score_dialog.rb +1 -10
- data/samples/elaborate/tetris/view/playfield.rb +1 -1
- data/samples/elaborate/tetris/view/tetris_menu_bar.rb +13 -11
- data/samples/hello/hello_canvas.rb +7 -6
- data/samples/hello/hello_canvas_animation.rb +3 -3
- data/samples/hello/hello_canvas_transform.rb +1 -1
- data/samples/hello/hello_canvas_transform/hello_canvas_transform_image.png +0 -0
- data/samples/hello/hello_code_text.rb +104 -0
- data/samples/hello/hello_table.rb +7 -4
- data/samples/hello/hello_table/baseball_park.png +0 -0
- metadata +7 -2
@@ -71,6 +71,9 @@ module Glimmer
|
|
71
71
|
Display.app_name ||= 'Glimmer'
|
72
72
|
@swt_display = Display.new(*args)
|
73
73
|
@swt_display.set_data('proxy', self)
|
74
|
+
on_swt_Dispose {
|
75
|
+
clear_shapes
|
76
|
+
}
|
74
77
|
end
|
75
78
|
|
76
79
|
def content(&block)
|
@@ -88,6 +91,14 @@ module Glimmer
|
|
88
91
|
def timer_exec(&block)
|
89
92
|
@swt_display.timer_exec(&block)
|
90
93
|
end
|
94
|
+
|
95
|
+
def on_widget_disposed(&block)
|
96
|
+
on_swt_Dispose(&block)
|
97
|
+
end
|
98
|
+
|
99
|
+
def disposed?
|
100
|
+
@swt_display.isDisposed
|
101
|
+
end
|
91
102
|
|
92
103
|
def method_missing(method, *args, &block)
|
93
104
|
if can_handle_observation_request?(method)
|
@@ -83,6 +83,13 @@ module Glimmer
|
|
83
83
|
@swt_image = Image.new(*@args)
|
84
84
|
@original_image_data = @image_data = @swt_image.image_data
|
85
85
|
end
|
86
|
+
@swt_image.singleton_class.alias_method(:dispose_without_glimmer, :dispose)
|
87
|
+
proxy = self
|
88
|
+
# TODO consider adding a get_data/set_data method to conform with other SWT widgets
|
89
|
+
@swt_image.singleton_class.define_method(:dispose) do
|
90
|
+
proxy.clear_shapes
|
91
|
+
dispose_without_glimmer
|
92
|
+
end
|
86
93
|
post_add_content if content.nil?
|
87
94
|
end
|
88
95
|
|
@@ -120,6 +127,10 @@ module Glimmer
|
|
120
127
|
@gc = org.eclipse.swt.graphics.GC.new(swt_image)
|
121
128
|
end
|
122
129
|
|
130
|
+
def disposed?
|
131
|
+
@swt_image.isDisposed
|
132
|
+
end
|
133
|
+
|
123
134
|
def has_attribute?(attribute_name, *args)
|
124
135
|
@swt_image.respond_to?(attribute_setter(attribute_name), args) || respond_to?(ruby_attribute_setter(attribute_name), args)
|
125
136
|
end
|
@@ -72,7 +72,9 @@ module Glimmer
|
|
72
72
|
@swt_layout.marginRight = 0 if @swt_layout.respond_to?(:marginRight)
|
73
73
|
@swt_layout.marginBottom = 0 if @swt_layout.respond_to?(:marginBottom)
|
74
74
|
@swt_layout.marginLeft = 0 if @swt_layout.respond_to?(:marginLeft)
|
75
|
+
old_layout = @widget_proxy.swt_widget.getLayout
|
75
76
|
@widget_proxy.swt_widget.setLayout(@swt_layout)
|
77
|
+
@widget_proxy.swt_widget.layout if old_layout
|
76
78
|
end
|
77
79
|
|
78
80
|
def has_attribute?(attribute_name, *args)
|
@@ -83,7 +85,8 @@ module Glimmer
|
|
83
85
|
apply_property_type_converters(attribute_name, args)
|
84
86
|
if args.first != @swt_layout.send(attribute_getter(attribute_name))
|
85
87
|
@swt_layout.send(attribute_setter(attribute_name), *args)
|
86
|
-
@widget_proxy.swt_widget.
|
88
|
+
@widget_proxy.swt_widget.layout
|
89
|
+
@widget_proxy.swt_widget.getShell.layout
|
87
90
|
end
|
88
91
|
end
|
89
92
|
|
@@ -82,6 +82,9 @@ module Glimmer
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
85
|
+
on_widget_disposed {
|
86
|
+
clear_shapes
|
87
|
+
}
|
85
88
|
@display ||= @swt_widget.getDisplay
|
86
89
|
end
|
87
90
|
|
@@ -161,7 +164,7 @@ module Glimmer
|
|
161
164
|
minimum_size = @swt_widget.getMinimumSize
|
162
165
|
@swt_widget.setMinimumSize(bounds.width, bounds.height)
|
163
166
|
listener = on_control_resized { @swt_widget.setBounds(bounds) }
|
164
|
-
@swt_widget.
|
167
|
+
@swt_widget.layout(true, true)
|
165
168
|
@swt_widget.removeControlListener(listener.swt_listener)
|
166
169
|
@swt_widget.setMinimumSize(minimum_size)
|
167
170
|
elsif OS.linux?
|
@@ -457,7 +457,7 @@ module Glimmer
|
|
457
457
|
edit_table_item(swt_widget.getSelection.first, column_index, before_write: before_write, after_write: after_write, after_cancel: after_cancel)
|
458
458
|
end
|
459
459
|
|
460
|
-
def edit_table_item(table_item, column_index, before_write: nil, after_write: nil, after_cancel: nil)
|
460
|
+
def edit_table_item(table_item, column_index, before_write: nil, after_write: nil, after_cancel: nil, write_on_cancel: false)
|
461
461
|
return if table_item.nil?
|
462
462
|
model = table_item.data
|
463
463
|
property = column_properties[column_index]
|
@@ -476,29 +476,33 @@ module Glimmer
|
|
476
476
|
widget_value_property = TableProxy::editors.symbolize_keys[editor_widget][:widget_value_property]
|
477
477
|
|
478
478
|
@cancel_edit = lambda do |event=nil|
|
479
|
-
|
480
|
-
|
481
|
-
@table_editor_widget_proxy = nil
|
482
|
-
if after_cancel&.arity == 0
|
483
|
-
after_cancel&.call
|
479
|
+
if write_on_cancel
|
480
|
+
@finish_edit.call(event)
|
484
481
|
else
|
485
|
-
|
482
|
+
@cancel_in_progress = true
|
483
|
+
@table_editor_widget_proxy&.swt_widget&.dispose
|
484
|
+
@table_editor_widget_proxy = nil
|
485
|
+
if after_cancel&.arity == 0
|
486
|
+
after_cancel&.call
|
487
|
+
else
|
488
|
+
after_cancel&.call(table_item)
|
489
|
+
end
|
490
|
+
@edit_in_progress = false
|
491
|
+
@cancel_in_progress = false
|
492
|
+
@cancel_edit = nil
|
493
|
+
@edit_mode = false
|
486
494
|
end
|
487
|
-
@edit_in_progress = false
|
488
|
-
@cancel_in_progress = false
|
489
|
-
@cancel_edit = nil
|
490
|
-
@edit_mode = false
|
491
495
|
end
|
492
496
|
|
493
497
|
@finish_edit = lambda do |event=nil|
|
494
498
|
new_value = @table_editor_widget_proxy&.send(widget_value_property)
|
495
499
|
if table_item.isDisposed
|
496
|
-
@cancel_edit.call
|
500
|
+
@cancel_edit.call unless write_on_cancel
|
497
501
|
elsif !new_value.nil? && !action_taken && !@edit_in_progress && !@cancel_in_progress
|
498
502
|
action_taken = true
|
499
503
|
@edit_in_progress = true
|
500
504
|
if new_value == model.send(model_editing_property)
|
501
|
-
@cancel_edit.call
|
505
|
+
@cancel_edit.call unless write_on_cancel
|
502
506
|
else
|
503
507
|
if before_write&.arity == 0
|
504
508
|
before_write&.call
|
@@ -165,6 +165,12 @@ module Glimmer
|
|
165
165
|
DEFAULT_INITIALIZERS[underscored_widget_name.to_s.to_sym]&.call(@swt_widget)
|
166
166
|
@parent_proxy.post_initialize_child(self)
|
167
167
|
end
|
168
|
+
@keyword = underscored_widget_name.to_s
|
169
|
+
if respond_to?(:on_widget_disposed)
|
170
|
+
on_widget_disposed {
|
171
|
+
clear_shapes
|
172
|
+
}
|
173
|
+
end
|
168
174
|
end
|
169
175
|
|
170
176
|
# Subclasses may override to perform post initialization work on an added child
|
@@ -559,9 +565,11 @@ module Glimmer
|
|
559
565
|
|
560
566
|
# Used for data-binding only. Consider renaming or improving to avoid the confusion it causes
|
561
567
|
def add_observer(observer, property_name)
|
562
|
-
|
563
|
-
|
564
|
-
|
568
|
+
if !observer.respond_to?(:binding_options) || !observer.binding_options[:read_only]
|
569
|
+
property_listener_installers = @swt_widget.class.ancestors.map {|ancestor| widget_property_listener_installers[ancestor]}.compact
|
570
|
+
widget_listener_installers = property_listener_installers.map{|installer| installer[property_name.to_s.to_sym]}.compact if !property_listener_installers.empty?
|
571
|
+
widget_listener_installers.to_a.first&.call(observer)
|
572
|
+
end
|
565
573
|
end
|
566
574
|
|
567
575
|
def remove_observer(observer, property_name)
|
@@ -20,7 +20,6 @@
|
|
20
20
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
21
|
|
22
22
|
require 'fileutils'
|
23
|
-
require 'etc'
|
24
23
|
|
25
24
|
class Sample
|
26
25
|
include Glimmer::DataBinding::ObservableModel
|
@@ -31,7 +30,7 @@ class Sample
|
|
31
30
|
end
|
32
31
|
|
33
32
|
def user_glimmer_directory
|
34
|
-
File.join(
|
33
|
+
File.join(File.expand_path('~'), '.glimmer-dsl-swt')
|
35
34
|
end
|
36
35
|
|
37
36
|
def ensure_user_glimmer_directory
|
@@ -204,7 +203,7 @@ class MetaSampleApplication
|
|
204
203
|
shell(:fill_screen) {
|
205
204
|
minimum_size 1280, 768
|
206
205
|
text 'Glimmer Meta-Sample (The Sample of Samples)'
|
207
|
-
image File.expand_path('
|
206
|
+
image File.expand_path('meta_sample/meta_sample_logo.png', __dir__)
|
208
207
|
|
209
208
|
sash_form {
|
210
209
|
composite {
|
@@ -264,9 +263,21 @@ class MetaSampleApplication
|
|
264
263
|
}
|
265
264
|
}
|
266
265
|
|
267
|
-
@code_text = code_text {
|
266
|
+
@code_text = code_text(lines: {width: 3}) {
|
267
|
+
root {
|
268
|
+
grid_layout(2, false) {
|
269
|
+
horizontal_spacing 0
|
270
|
+
margin_width 0
|
271
|
+
margin_height 0
|
272
|
+
}
|
273
|
+
}
|
274
|
+
line_numbers {
|
275
|
+
background :white
|
276
|
+
}
|
268
277
|
text bind(SampleDirectory, 'selected_sample.code', read_only: true)
|
269
278
|
editable bind(SampleDirectory, 'selected_sample.editable')
|
279
|
+
left_margin 7
|
280
|
+
right_margin 7
|
270
281
|
}
|
271
282
|
|
272
283
|
weights 4, 11
|
Binary file
|
data/samples/elaborate/tetris.rb
CHANGED
@@ -51,11 +51,12 @@ class Tetris
|
|
51
51
|
end
|
52
52
|
|
53
53
|
Display.app_name = 'Glimmer Tetris'
|
54
|
+
|
54
55
|
display {
|
55
|
-
@
|
56
|
+
@keyboard_down_listener = on_swt_keydown { |key_event|
|
56
57
|
case key_event.keyCode
|
57
58
|
when swt(:arrow_down), 's'.bytes.first
|
58
|
-
game.down!
|
59
|
+
game.down! if OS.mac?
|
59
60
|
when swt(:arrow_up)
|
60
61
|
case game.up_arrow_action
|
61
62
|
when :instant_down
|
@@ -75,10 +76,18 @@ class Tetris
|
|
75
76
|
elsif key_event.keyLocation == swt(:left) # left shift key
|
76
77
|
game.rotate!(:left)
|
77
78
|
end
|
78
|
-
when swt(:ctrl)
|
79
|
-
game.rotate!(:left)
|
80
79
|
end
|
81
80
|
}
|
81
|
+
|
82
|
+
# invoke game.down! on keyup with Windows/Linux since they seem to group-render similar events, preventing intermediate renders (causing invisiblity while holding keys)
|
83
|
+
if !OS.mac?
|
84
|
+
@keyboard_up_listener = on_swt_keyup { |key_event|
|
85
|
+
case key_event.keyCode
|
86
|
+
when swt(:arrow_down), 's'.bytes.first
|
87
|
+
game.down!
|
88
|
+
end
|
89
|
+
}
|
90
|
+
end
|
82
91
|
|
83
92
|
# if running in app mode, set the Mac app about dialog (ignored in platforms)
|
84
93
|
@about_observer = on_about {
|
@@ -169,7 +178,7 @@ class Tetris
|
|
169
178
|
}
|
170
179
|
}
|
171
180
|
end
|
172
|
-
|
181
|
+
|
173
182
|
def start_moving_tetrominos_down
|
174
183
|
Thread.new do
|
175
184
|
@mutex.synchronize do
|
@@ -201,7 +210,8 @@ class Tetris
|
|
201
210
|
def deregister_observers
|
202
211
|
@show_high_scores_observer&.deregister
|
203
212
|
@game_over_observer&.deregister
|
204
|
-
@
|
213
|
+
@keyboard_down_listener&.deregister
|
214
|
+
@keyboard_up_listener&.deregister
|
205
215
|
@about_observer&.deregister
|
206
216
|
@quit_observer&.deregister
|
207
217
|
end
|
@@ -20,7 +20,7 @@
|
|
20
20
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
21
|
|
22
22
|
require 'fileutils'
|
23
|
-
require '
|
23
|
+
require 'json'
|
24
24
|
require 'glimmer/data_binding/observer'
|
25
25
|
require 'glimmer/config'
|
26
26
|
|
@@ -50,7 +50,7 @@ class Tetris
|
|
50
50
|
@high_scores = []
|
51
51
|
@show_high_scores = false
|
52
52
|
@beeping = true
|
53
|
-
@up_arrow_action = :
|
53
|
+
@up_arrow_action = :rotate_left
|
54
54
|
load_high_scores!
|
55
55
|
end
|
56
56
|
|
@@ -111,7 +111,7 @@ class Tetris
|
|
111
111
|
end
|
112
112
|
|
113
113
|
def tetris_dir
|
114
|
-
@tetris_dir ||= File.join(
|
114
|
+
@tetris_dir ||= File.join(File.expand_path('~'), '.glimmer-tetris')
|
115
115
|
end
|
116
116
|
|
117
117
|
def tetris_high_score_file
|
@@ -21,6 +21,19 @@
|
|
21
21
|
|
22
22
|
class Tetris
|
23
23
|
module Model
|
24
|
-
PastGame
|
24
|
+
class PastGame
|
25
|
+
attr_accessor :name, :score, :lines, :level
|
26
|
+
|
27
|
+
def initialize(name, score, lines, level)
|
28
|
+
@name = name
|
29
|
+
@score = score.to_i
|
30
|
+
@lines = lines.to_i
|
31
|
+
@level = level.to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_a
|
35
|
+
[@name, @score, @lines, @level]
|
36
|
+
end
|
37
|
+
end
|
25
38
|
end
|
26
39
|
end
|
@@ -27,7 +27,7 @@ class Tetris
|
|
27
27
|
options :game_playfield, :block_size, :row, :column
|
28
28
|
|
29
29
|
body {
|
30
|
-
canvas {
|
30
|
+
canvas(:double_buffered) {
|
31
31
|
background bind(game_playfield[row][column], :color)
|
32
32
|
polygon(0, 0, block_size, 0, block_size - 4, 4, 4, 4) {
|
33
33
|
background bind(game_playfield[row][column], :color) { |color_value|
|
@@ -71,13 +71,6 @@ class Tetris
|
|
71
71
|
composite {
|
72
72
|
row_layout :horizontal
|
73
73
|
|
74
|
-
button {
|
75
|
-
text 'Clear'
|
76
|
-
|
77
|
-
on_widget_selected {
|
78
|
-
game.clear_high_scores!
|
79
|
-
}
|
80
|
-
}
|
81
74
|
@play_close_button = button {
|
82
75
|
text bind(game, :game_over) {|game_over| game_over ? 'Play Again?' : 'Close'}
|
83
76
|
focus true # initial focus
|
@@ -99,13 +92,11 @@ class Tetris
|
|
99
92
|
@high_score_table.edit_table_item(
|
100
93
|
@high_score_table.items.first, # row item
|
101
94
|
0, # column
|
95
|
+
write_on_cancel: true,
|
102
96
|
after_write: -> {
|
103
97
|
game.save_high_scores!
|
104
98
|
@play_close_button.set_focus
|
105
99
|
},
|
106
|
-
after_cancel: -> {
|
107
|
-
@play_close_button.set_focus
|
108
|
-
},
|
109
100
|
)
|
110
101
|
end
|
111
102
|
}
|
@@ -23,6 +23,8 @@ class Tetris
|
|
23
23
|
module View
|
24
24
|
class TetrisMenuBar
|
25
25
|
include Glimmer::UI::CustomWidget
|
26
|
+
|
27
|
+
COMMAND_KEY = OS.mac? ? :command : :ctrl
|
26
28
|
|
27
29
|
options :game
|
28
30
|
|
@@ -34,7 +36,7 @@ class Tetris
|
|
34
36
|
menu_item {
|
35
37
|
text '&Start'
|
36
38
|
enabled bind(game, :game_over)
|
37
|
-
accelerator
|
39
|
+
accelerator COMMAND_KEY, :s
|
38
40
|
|
39
41
|
on_widget_selected {
|
40
42
|
game.start!
|
@@ -42,14 +44,14 @@ class Tetris
|
|
42
44
|
}
|
43
45
|
menu_item(:check) {
|
44
46
|
text '&Pause'
|
45
|
-
accelerator
|
47
|
+
accelerator COMMAND_KEY, :p
|
46
48
|
enabled bind(game, :game_over, on_read: :!) {|value| value && !game.show_high_scores}
|
47
49
|
enabled bind(game, :show_high_scores, on_read: :!) {|value| value && !game.game_over}
|
48
50
|
selection bind(game, :paused)
|
49
51
|
}
|
50
52
|
menu_item {
|
51
53
|
text '&Restart'
|
52
|
-
accelerator
|
54
|
+
accelerator COMMAND_KEY, :r
|
53
55
|
|
54
56
|
on_widget_selected {
|
55
57
|
game.restart!
|
@@ -58,7 +60,7 @@ class Tetris
|
|
58
60
|
menu_item(:separator)
|
59
61
|
menu_item {
|
60
62
|
text '&Exit'
|
61
|
-
accelerator
|
63
|
+
accelerator COMMAND_KEY, :x
|
62
64
|
|
63
65
|
on_widget_selected {
|
64
66
|
parent_proxy.close
|
@@ -73,12 +75,12 @@ class Tetris
|
|
73
75
|
text '&High Scores'
|
74
76
|
menu_item(:check) {
|
75
77
|
text '&Show'
|
76
|
-
accelerator
|
78
|
+
accelerator COMMAND_KEY, :shift, :h
|
77
79
|
selection bind(game, :show_high_scores)
|
78
80
|
}
|
79
81
|
menu_item {
|
80
82
|
text '&Clear'
|
81
|
-
accelerator
|
83
|
+
accelerator COMMAND_KEY, :shift, :c
|
82
84
|
|
83
85
|
on_widget_selected {
|
84
86
|
game.clear_high_scores!
|
@@ -91,24 +93,24 @@ class Tetris
|
|
91
93
|
text '&Options'
|
92
94
|
menu_item(:check) {
|
93
95
|
text '&Beeping'
|
94
|
-
accelerator
|
96
|
+
accelerator COMMAND_KEY, :b
|
95
97
|
selection bind(game, :beeping)
|
96
98
|
}
|
97
99
|
menu {
|
98
100
|
text 'Up Arrow'
|
99
101
|
menu_item(:radio) {
|
100
102
|
text '&Instant Down'
|
101
|
-
accelerator
|
103
|
+
accelerator COMMAND_KEY, :shift, :i
|
102
104
|
selection bind(game, :instant_down_on_up, computed_by: :up_arrow_action)
|
103
105
|
}
|
104
106
|
menu_item(:radio) {
|
105
107
|
text 'Rotate &Right'
|
106
|
-
accelerator
|
108
|
+
accelerator COMMAND_KEY, :shift, :r
|
107
109
|
selection bind(game, :rotate_right_on_up, computed_by: :up_arrow_action)
|
108
110
|
}
|
109
111
|
menu_item(:radio) {
|
110
112
|
text 'Rotate &Left'
|
111
|
-
accelerator
|
113
|
+
accelerator COMMAND_KEY, :shift, :l
|
112
114
|
selection bind(game, :rotate_left_on_up, computed_by: :up_arrow_action)
|
113
115
|
}
|
114
116
|
}
|
@@ -119,7 +121,7 @@ class Tetris
|
|
119
121
|
|
120
122
|
menu_item {
|
121
123
|
text '&About'
|
122
|
-
accelerator
|
124
|
+
accelerator COMMAND_KEY, :shift, :a
|
123
125
|
|
124
126
|
on_widget_selected {
|
125
127
|
parent_custom_shell&.show_about_dialog
|