glimmer-dsl-swt 4.18.3.4 → 4.18.4.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|