glimmer-dsl-swt 4.21.0.1 → 4.21.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/README.md +17 -11
- data/RUBY_VERSION +1 -1
- data/VERSION +1 -1
- data/docs/reference/GLIMMER_COMMAND.md +1 -1
- data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +45 -26
- data/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md +73 -16
- data/glimmer-dsl-swt.gemspec +0 -0
- data/lib/glimmer/data_binding/widget_binding.rb +3 -3
- data/lib/glimmer/rake_task/package.rb +1 -1
- data/lib/glimmer/rake_task/scaffold.rb +4 -22
- data/lib/glimmer/rake_task.rb +1 -5
- data/lib/glimmer/swt/image_proxy.rb +5 -3
- data/lib/glimmer/swt/shell_proxy.rb +5 -3
- data/lib/glimmer/swt/style_constantizable.rb +2 -0
- data/lib/glimmer/swt/widget_proxy.rb +80 -0
- data/samples/elaborate/battleship/view/grid.rb +3 -3
- data/samples/elaborate/battleship/view/ship.rb +1 -1
- data/samples/elaborate/meta_sample.rb +12 -5
- data/samples/elaborate/tetris/view/tetris_menu_bar.rb +2 -2
- data/samples/elaborate/tetris.rb +12 -14
- data/samples/elaborate/tic_tac_toe.rb +6 -3
- data/samples/elaborate/timer.rb +0 -1
- data/samples/elaborate/weather.rb +3 -0
- data/samples/hello/hello_canvas.rb +1 -1
- data/samples/hello/hello_canvas_transform.rb +1 -1
- data/samples/hello/hello_cool_bar.rb +5 -60
- data/samples/hello/hello_drag_and_drop.rb +172 -11
- data/samples/hello/hello_scale.rb +1 -4
- data/samples/hello/hello_slider.rb +1 -4
- data/samples/hello/hello_tool_bar.rb +7 -53
- data/samples/hello/images/copy.png +0 -0
- data/samples/hello/images/cut.png +0 -0
- data/samples/hello/images/paste.png +0 -0
- metadata +11 -9
@@ -116,10 +116,12 @@ module Glimmer
|
|
116
116
|
GEMFILE_APP_MIDFIX = <<~MULTI_LINE_STRING
|
117
117
|
|
118
118
|
gem 'glimmer-dsl-swt', '~> #{VERSION}'
|
119
|
+
gem 'psych', '3.3.2' # Fixed temporarily because installing latest on JDK16 was causing issues
|
119
120
|
MULTI_LINE_STRING
|
120
121
|
GEMFILE_GEM_MIDFIX = <<~MULTI_LINE_STRING
|
121
122
|
|
122
123
|
gem 'glimmer-dsl-swt', '~> #{VERSION.split('.')[0...2].join('.')}'
|
124
|
+
gem 'psych', '3.3.2' # Fixed temporarily because installing latest on JDK16 was causing issues
|
123
125
|
MULTI_LINE_STRING
|
124
126
|
GEMFILE_SUFFIX = <<~MULTI_LINE_STRING
|
125
127
|
|
@@ -182,11 +184,6 @@ module Glimmer
|
|
182
184
|
cp File.expand_path('../../../../icons/scaffold_app.png', __FILE__), icon_file
|
183
185
|
puts "Created #{current_dir_name}/#{icon_file}"
|
184
186
|
|
185
|
-
write "Resource.java", resource_java_file(app_name)
|
186
|
-
cd '..'
|
187
|
-
system "javac #{file_name(app_name)}/Resource.java"
|
188
|
-
cd gem_name
|
189
|
-
|
190
187
|
mkdir_p "app/#{file_name(app_name)}"
|
191
188
|
write "app/#{file_name(app_name)}/launch.rb", app_launch_file(app_name)
|
192
189
|
mkdir_p 'bin'
|
@@ -298,11 +295,6 @@ module Glimmer
|
|
298
295
|
cp File.expand_path('../../../../icons/scaffold_app.png', __FILE__), icon_file
|
299
296
|
puts "Created #{current_dir_name}/#{icon_file}"
|
300
297
|
|
301
|
-
write "Resource.java", resource_java_file(custom_shell_name)
|
302
|
-
cd '..'
|
303
|
-
system "javac #{file_name(custom_shell_name)}/Resource.java"
|
304
|
-
cd gem_name
|
305
|
-
|
306
298
|
if OS.windows?
|
307
299
|
system "glimmer package" # TODO handle windows properly with batch file
|
308
300
|
system "\"packages/bundles/#{human_name(custom_shell_name)}/#{human_name(custom_shell_name)}.exe\""
|
@@ -496,16 +488,6 @@ module Glimmer
|
|
496
488
|
MULTI_LINE_STRING
|
497
489
|
end
|
498
490
|
|
499
|
-
def resource_java_file(app_name)
|
500
|
-
<<~MULTI_LINE_STRING
|
501
|
-
package #{file_name(app_name)};
|
502
|
-
|
503
|
-
/** The soul purpose of this class is to retrieve icons for uri:classloader paths used from JAR */
|
504
|
-
class Resource {
|
505
|
-
}
|
506
|
-
MULTI_LINE_STRING
|
507
|
-
end
|
508
|
-
|
509
491
|
def app_bin_command_file(app_name_or_gem_name, custom_shell_name=nil, namespace=nil)
|
510
492
|
if custom_shell_name.nil?
|
511
493
|
runner = "File.expand_path('../../app/#{file_name(app_name_or_gem_name)}/launch.rb', __FILE__)"
|
@@ -545,7 +527,7 @@ module Glimmer
|
|
545
527
|
lines.insert(require_rake_line_index, "require 'glimmer/launcher'")
|
546
528
|
gem_files_line_index = lines.index(lines.detect {|l| l.include?('# dependencies defined in Gemfile') })
|
547
529
|
if custom_shell_name
|
548
|
-
lines.insert(gem_files_line_index, " gem.files = Dir['
|
530
|
+
lines.insert(gem_files_line_index, " gem.files = Dir['VERSION', 'LICENSE.txt', 'app/**/*', 'bin/**/*', 'config/**/*', 'db/**/*', 'docs/**/*', 'fonts/**/*', 'icons/**/*', 'images/**/*', 'lib/**/*', 'script/**/*', 'sounds/**/*', 'vendor/**/*', 'videos/**/*']")
|
549
531
|
# the second executable is needed for warbler as it matches the gem name, which is the default expected file (alternatively in the future, we could do away with it and configure warbler to use the other file)
|
550
532
|
lines.insert(gem_files_line_index+1, " gem.require_paths = ['vendor', 'lib', 'app']")
|
551
533
|
lines.insert(gem_files_line_index+2, " gem.executables = ['#{file_name(custom_shell_name)}']") if custom_shell_name
|
@@ -561,7 +543,7 @@ module Glimmer
|
|
561
543
|
Glimmer::RakeTask::Package.jpackage_extra_args =
|
562
544
|
" --name '#{human_name(custom_shell_name)}'" +
|
563
545
|
" --description '#{human_name(custom_shell_name)}'"
|
564
|
-
# You can add more options from https://docs.oracle.com/en/java/javase/
|
546
|
+
# You can add more options from https://docs.oracle.com/en/java/javase/16/jpackage/packaging-tool-user-guide.pdf
|
565
547
|
MULTI_LINE_STRING
|
566
548
|
end
|
567
549
|
file_content
|
data/lib/glimmer/rake_task.rb
CHANGED
@@ -111,11 +111,7 @@ namespace :glimmer do
|
|
111
111
|
Rake::Task['glimmer:package:lock_jars'].execute
|
112
112
|
Rake::Task['glimmer:package:config'].execute
|
113
113
|
Rake::Task['glimmer:package:jar'].execute
|
114
|
-
|
115
|
-
Rake::Task['glimmer:package:gem'].execute
|
116
|
-
else
|
117
|
-
Rake::Task['glimmer:package:native'].execute(args)
|
118
|
-
end
|
114
|
+
Rake::Task['glimmer:package:native'].execute(args)
|
119
115
|
end
|
120
116
|
|
121
117
|
desc 'Scaffold Glimmer application directory structure to build a new app'
|
@@ -122,9 +122,11 @@ module Glimmer
|
|
122
122
|
def input_stream
|
123
123
|
if @file_path.start_with?('uri:classloader')
|
124
124
|
@jar_file_path = @file_path
|
125
|
-
file_path = @jar_file_path.sub(/^uri\:classloader\:/, '').sub(
|
126
|
-
|
127
|
-
|
125
|
+
file_path = @jar_file_path.sub(/^uri\:classloader\:/, '').sub(/^\/+/, '')
|
126
|
+
require 'jruby'
|
127
|
+
jcl = JRuby.runtime.jruby_class_loader
|
128
|
+
resource = jcl.get_resource_as_stream(file_path)
|
129
|
+
file_input_stream = resource.to_io.to_input_stream
|
128
130
|
else
|
129
131
|
file_input_stream = java.io.FileInputStream.new(@file_path)
|
130
132
|
end
|
@@ -35,7 +35,8 @@ module Glimmer
|
|
35
35
|
WIDTH_MIN = 190
|
36
36
|
HEIGHT_MIN = 0
|
37
37
|
|
38
|
-
attr_reader :opened_before
|
38
|
+
attr_reader :opened_before, :last_shell_closing
|
39
|
+
alias last_shell_closing? last_shell_closing
|
39
40
|
alias opened_before? opened_before
|
40
41
|
|
41
42
|
# Instantiates ShellProxy with same arguments expected by SWT Shell
|
@@ -85,9 +86,10 @@ module Glimmer
|
|
85
86
|
end
|
86
87
|
end
|
87
88
|
end
|
88
|
-
on_widget_disposed
|
89
|
+
on_widget_disposed do
|
90
|
+
@last_shell_closing = true if @display.shells.count == 1 && @display.shells.first == @swt_widget
|
89
91
|
clear_shapes
|
90
|
-
|
92
|
+
end
|
91
93
|
@display ||= @swt_widget.getDisplay
|
92
94
|
end
|
93
95
|
end
|
@@ -198,6 +198,10 @@ module Glimmer
|
|
198
198
|
@finished_add_content = true
|
199
199
|
end
|
200
200
|
|
201
|
+
def shell_proxy
|
202
|
+
@swt_widget.shell.get_data('proxy')
|
203
|
+
end
|
204
|
+
|
201
205
|
def extract_args(underscored_widget_name, args)
|
202
206
|
@arg_extractor_mapping ||= {
|
203
207
|
'menu_item' => lambda do |args|
|
@@ -739,6 +743,13 @@ module Glimmer
|
|
739
743
|
|
740
744
|
def handle_observation_request(observation_request, &block)
|
741
745
|
observation_request = normalize_observation_request(observation_request)
|
746
|
+
if observation_request.start_with?('on_drag_enter')
|
747
|
+
original_block = block
|
748
|
+
block = Proc.new do |event|
|
749
|
+
event.detail = DNDProxy[:drop_copy]
|
750
|
+
original_block.call(event)
|
751
|
+
end
|
752
|
+
end
|
742
753
|
if observation_request.start_with?('on_swt_')
|
743
754
|
constant_name = observation_request.sub(/^on_swt_/, '')
|
744
755
|
add_swt_event_listener(constant_name, &block)
|
@@ -882,6 +893,75 @@ module Glimmer
|
|
882
893
|
def widget_custom_attribute_mapping
|
883
894
|
# TODO scope per widget class type just like other mappings
|
884
895
|
@swt_widget_custom_attribute_mapping ||= {
|
896
|
+
'drag_source' => {
|
897
|
+
getter: {name: 'getShell', invoker: lambda { |widget, args|
|
898
|
+
@drag_source
|
899
|
+
}},
|
900
|
+
setter: {name: 'getShell', invoker: lambda { |widget, args|
|
901
|
+
@drag_source = args.first
|
902
|
+
if @drag_source
|
903
|
+
case @swt_widget
|
904
|
+
when List
|
905
|
+
on_drag_set_data do |event|
|
906
|
+
drag_widget = event.widget.control
|
907
|
+
event.data = drag_widget.selection.first
|
908
|
+
end
|
909
|
+
when Label
|
910
|
+
on_drag_set_data do |event|
|
911
|
+
drag_widget = event.widget.control
|
912
|
+
event.data = drag_widget.text
|
913
|
+
end
|
914
|
+
when Text
|
915
|
+
on_drag_set_data do |event|
|
916
|
+
drag_widget = event.widget.control
|
917
|
+
event.data = drag_widget.selection_text
|
918
|
+
end
|
919
|
+
when Spinner
|
920
|
+
on_drag_set_data do |event|
|
921
|
+
drag_widget = event.widget.control
|
922
|
+
event.data = drag_widget.selection.to_s
|
923
|
+
end
|
924
|
+
end
|
925
|
+
end
|
926
|
+
}},
|
927
|
+
},
|
928
|
+
'drop_target' => {
|
929
|
+
getter: {name: 'getShell', invoker: lambda { |widget, args|
|
930
|
+
@drop_target
|
931
|
+
}},
|
932
|
+
setter: {name: 'getShell', invoker: lambda { |widget, args|
|
933
|
+
@drop_target = args.first
|
934
|
+
if @drop_target
|
935
|
+
case @swt_widget
|
936
|
+
when List
|
937
|
+
on_drop do |event|
|
938
|
+
drop_widget = event.widget.control
|
939
|
+
drop_widget.add(event.data) unless @drop_target == :unique && drop_widget.items.include?(event.data)
|
940
|
+
drop_widget.select(drop_widget.items.count - 1)
|
941
|
+
end
|
942
|
+
when Label
|
943
|
+
on_drop do |event|
|
944
|
+
drop_widget = event.widget.control
|
945
|
+
drop_widget.text = event.data
|
946
|
+
end
|
947
|
+
when Text
|
948
|
+
on_drop do |event|
|
949
|
+
drop_widget = event.widget.control
|
950
|
+
if @drop_target == :replace
|
951
|
+
drop_widget.text = event.data
|
952
|
+
else
|
953
|
+
drop_widget.insert(event.data)
|
954
|
+
end
|
955
|
+
end
|
956
|
+
when Spinner
|
957
|
+
on_drop do |event|
|
958
|
+
drop_widget = event.widget.control
|
959
|
+
drop_widget.selection = event.data.to_f
|
960
|
+
end
|
961
|
+
end
|
962
|
+
end
|
963
|
+
}},
|
964
|
+
},
|
885
965
|
'window' => {
|
886
966
|
getter: {name: 'getShell'},
|
887
967
|
setter: {name: 'getShell', invoker: lambda { |widget, args| @swt_widget.getShell }}, # No Op
|
@@ -45,21 +45,21 @@ class Battleship
|
|
45
45
|
}
|
46
46
|
|
47
47
|
text player.to_s.capitalize
|
48
|
-
font height: 20, style: :bold
|
48
|
+
font height: OS.windows? ? 18 : 20, style: :bold
|
49
49
|
}
|
50
50
|
|
51
51
|
label # filler
|
52
52
|
Model::Grid::WIDTH.times do |column_index|
|
53
53
|
label {
|
54
54
|
text (column_index + 1).to_s
|
55
|
-
font height: 16
|
55
|
+
font height: OS.windows? ? 14 : 16
|
56
56
|
}
|
57
57
|
end
|
58
58
|
|
59
59
|
Model::Grid::HEIGHT.times do |row_index|
|
60
60
|
label {
|
61
61
|
text Model::Grid::ROW_ALPHABETS[row_index]
|
62
|
-
font height: 16
|
62
|
+
font height: OS.windows? ? 14 : 16
|
63
63
|
}
|
64
64
|
Model::Grid::WIDTH.times do |column_index|
|
65
65
|
cell(game: game, player: player, row_index: row_index, column_index: column_index) {
|
@@ -23,8 +23,6 @@ require 'glimmer-dsl-swt'
|
|
23
23
|
require 'fileutils'
|
24
24
|
|
25
25
|
class Sample
|
26
|
-
include Glimmer::DataBinding::ObservableModel
|
27
|
-
|
28
26
|
class << self
|
29
27
|
def glimmer_directory
|
30
28
|
File.expand_path('../../..', __FILE__)
|
@@ -42,6 +40,10 @@ class Sample
|
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|
43
|
+
|
44
|
+
include Glimmer::DataBinding::ObservableModel
|
45
|
+
|
46
|
+
UNEDITABLE = ['meta_sample.rb'] + (OS.windows? ? ['calculator.rb', 'weather.rb'] : []) # Windows StyledText does not support unicode characters found in certain samples
|
45
47
|
|
46
48
|
attr_accessor :sample_directory, :file, :selected
|
47
49
|
|
@@ -74,9 +76,13 @@ class Sample
|
|
74
76
|
end
|
75
77
|
|
76
78
|
def editable
|
79
|
+
!UNEDITABLE.include?(File.basename(file))
|
80
|
+
end
|
81
|
+
alias editable? editable
|
82
|
+
|
83
|
+
def launchable
|
77
84
|
File.basename(file) != 'meta_sample.rb'
|
78
85
|
end
|
79
|
-
alias launchable editable
|
80
86
|
|
81
87
|
def file_relative_path
|
82
88
|
file.sub(self.class.glimmer_directory, '')
|
@@ -97,6 +103,7 @@ class Sample
|
|
97
103
|
def launch(modified_code)
|
98
104
|
launch_file = user_file
|
99
105
|
begin
|
106
|
+
raise 'Unsupported through editor!' unless editable?
|
100
107
|
FileUtils.cp_r(file, user_file_parent_directory)
|
101
108
|
FileUtils.cp_r(directory, user_file_parent_directory) if File.exist?(directory)
|
102
109
|
File.write(user_file, modified_code)
|
@@ -202,12 +209,12 @@ class MetaSampleApplication
|
|
202
209
|
|
203
210
|
body {
|
204
211
|
shell(:fill_screen) {
|
205
|
-
minimum_size
|
212
|
+
minimum_size 640, 384
|
206
213
|
text 'Glimmer Meta-Sample (The Sample of Samples)'
|
207
214
|
image File.expand_path('../../icons/scaffold_app.png', __dir__)
|
208
215
|
|
209
216
|
sash_form {
|
210
|
-
weights
|
217
|
+
weights 1, 2
|
211
218
|
|
212
219
|
composite {
|
213
220
|
grid_layout(1, false) {
|
@@ -45,8 +45,8 @@ class Tetris
|
|
45
45
|
menu_item(:check) {
|
46
46
|
text '&Pause'
|
47
47
|
accelerator COMMAND_KEY, :p
|
48
|
-
enabled <= [game, :game_over, on_read: ->(value) { value && !game.show_high_scores }]
|
49
|
-
enabled <= [game, :show_high_scores, on_read: ->(value) { value && !game.game_over }]
|
48
|
+
enabled <= [game, :game_over, on_read: ->(value) { !value && !game.show_high_scores }]
|
49
|
+
enabled <= [game, :show_high_scores, on_read: ->(value) { !value && !game.game_over }]
|
50
50
|
selection <=> [game, :paused]
|
51
51
|
}
|
52
52
|
menu_item {
|
data/samples/elaborate/tetris.rb
CHANGED
@@ -57,7 +57,17 @@ class Tetris
|
|
57
57
|
on_swt_keydown { |key_event|
|
58
58
|
case key_event.keyCode
|
59
59
|
when swt(:arrow_down), 's'.bytes.first
|
60
|
-
|
60
|
+
if OS.mac?
|
61
|
+
game.down!
|
62
|
+
else
|
63
|
+
# rate limit downs in Windows/Linux as they go too fast when key is held
|
64
|
+
@queued_downs ||= 0
|
65
|
+
@queued_downs += 1
|
66
|
+
async_exec do
|
67
|
+
game.down! if @queued_downs < 3
|
68
|
+
@queued_downs -= 1
|
69
|
+
end
|
70
|
+
end
|
61
71
|
when swt(:arrow_up)
|
62
72
|
case game.up_arrow_action
|
63
73
|
when :instant_down
|
@@ -80,16 +90,6 @@ class Tetris
|
|
80
90
|
end
|
81
91
|
}
|
82
92
|
|
83
|
-
# invoke game.down! on keyup with Windows/Linux since they seem to group-render similar events, preventing intermediate renders (causing invisiblity while holding keys)
|
84
|
-
if !OS.mac?
|
85
|
-
on_swt_keyup { |key_event|
|
86
|
-
case key_event.keyCode
|
87
|
-
when swt(:arrow_down), 's'.bytes.first
|
88
|
-
game.down!
|
89
|
-
end
|
90
|
-
}
|
91
|
-
end
|
92
|
-
|
93
93
|
# if running in app mode, set the Mac app about dialog (ignored in platforms)
|
94
94
|
on_about {
|
95
95
|
show_about_dialog
|
@@ -170,9 +170,7 @@ class Tetris
|
|
170
170
|
sleep @game.delay
|
171
171
|
break if @game.game_over? || body_root.disposed?
|
172
172
|
# ensure entire game tetromino down movement happens as one GUI update event with sync_exec (to avoid flicker/stutter)
|
173
|
-
sync_exec {
|
174
|
-
@game.down! unless @game.paused?
|
175
|
-
}
|
173
|
+
sync_exec { @game.down! unless @game.paused? }
|
176
174
|
end
|
177
175
|
end
|
178
176
|
end
|
@@ -41,18 +41,21 @@ class TicTacToe
|
|
41
41
|
shell {
|
42
42
|
text "Tic-Tac-Toe"
|
43
43
|
minimum_size 176, 200
|
44
|
+
|
44
45
|
composite {
|
45
46
|
grid_layout 3, true
|
47
|
+
|
46
48
|
(1..3).each { |row|
|
47
49
|
(1..3).each { |column|
|
48
50
|
button {
|
49
51
|
layout_data :fill, :fill, true, true
|
50
52
|
text <= [@tic_tac_toe_board[row, column], :sign]
|
51
53
|
enabled <= [@tic_tac_toe_board[row, column], :empty]
|
52
|
-
font style: :bold, height: 20
|
53
|
-
|
54
|
+
font style: :bold, height: (OS.windows? ? 18 : 20)
|
55
|
+
|
56
|
+
on_widget_selected do
|
54
57
|
@tic_tac_toe_board.mark(row, column)
|
55
|
-
|
58
|
+
end
|
56
59
|
}
|
57
60
|
}
|
58
61
|
}
|
data/samples/elaborate/timer.rb
CHANGED
@@ -102,6 +102,7 @@ class Weather
|
|
102
102
|
layout_data(:fill, :center, true, false)
|
103
103
|
text <= [self, field_name, on_read: ->(t) { "#{kelvin_to_temp_unit(t, temp_unit).to_f.round}°" }]
|
104
104
|
font height: DEFAULT_FONT_HEIGHT
|
105
|
+
background DEFAULT_BACKGROUND
|
105
106
|
foreground DEFAULT_FOREGROUND
|
106
107
|
}
|
107
108
|
end
|
@@ -112,6 +113,7 @@ class Weather
|
|
112
113
|
layout_data(:fill, :center, true, false)
|
113
114
|
text <= [self, 'humidity', on_read: ->(h) { "#{h.to_f.round}%" }]
|
114
115
|
font height: DEFAULT_FONT_HEIGHT
|
116
|
+
background DEFAULT_BACKGROUND
|
115
117
|
foreground DEFAULT_FOREGROUND
|
116
118
|
}
|
117
119
|
end
|
@@ -121,6 +123,7 @@ class Weather
|
|
121
123
|
layout_data :fill, :center, false, false
|
122
124
|
text field_name.titlecase
|
123
125
|
font height: DEFAULT_FONT_HEIGHT
|
126
|
+
background DEFAULT_BACKGROUND
|
124
127
|
foreground DEFAULT_FOREGROUND
|
125
128
|
}
|
126
129
|
end
|
@@ -65,7 +65,7 @@ class HelloCanvas
|
|
65
65
|
y :default, 1 # add 1 pixel to default y (shape centered within parent vertically)
|
66
66
|
background :yellow
|
67
67
|
foreground :dark_magenta
|
68
|
-
font name: 'Courier', height: 30
|
68
|
+
font name: 'Courier', height: (OS.windows? ? 26 : 30)
|
69
69
|
}
|
70
70
|
}
|
71
71
|
rectangle(155, 30) { # width and height are assumed to be the default (calculated from children)
|
@@ -40,27 +40,28 @@ class HelloCoolBar
|
|
40
40
|
margin_width 0
|
41
41
|
margin_height 0
|
42
42
|
}
|
43
|
-
|
43
|
+
|
44
44
|
text 'Hello, Cool Bar!'
|
45
|
+
minimum_size 280, 50
|
45
46
|
|
46
47
|
cool_bar { # optionally takes a :flat style and/or :vertical style if you need vertical layout
|
47
48
|
tool_bar {
|
48
49
|
tool_item {
|
49
|
-
image
|
50
|
+
image File.expand_path('./images/cut.png', __dir__), height: 16
|
50
51
|
|
51
52
|
on_widget_selected do
|
52
53
|
self.operation = 'Cut'
|
53
54
|
end
|
54
55
|
}
|
55
56
|
tool_item {
|
56
|
-
image
|
57
|
+
image File.expand_path('./images/copy.png', __dir__), height: 16
|
57
58
|
|
58
59
|
on_widget_selected do
|
59
60
|
self.operation = 'Copy'
|
60
61
|
end
|
61
62
|
}
|
62
63
|
tool_item {
|
63
|
-
image
|
64
|
+
image File.expand_path('./images/paste.png', __dir__), height: 16
|
64
65
|
|
65
66
|
on_widget_selected do
|
66
67
|
self.operation = 'Paste'
|
@@ -86,62 +87,6 @@ class HelloCoolBar
|
|
86
87
|
}
|
87
88
|
}
|
88
89
|
}
|
89
|
-
|
90
|
-
def cut_image
|
91
|
-
# building image on the fly with Canvas Shape DSL
|
92
|
-
image(25, 25) {
|
93
|
-
rectangle(0, 0, 25, 25) {
|
94
|
-
background_pattern 0, 0, 0, 25, :white, :gray
|
95
|
-
line(20, 2, 9, 15) {
|
96
|
-
line_width 2
|
97
|
-
}
|
98
|
-
line(5, 2, 16, 15) {
|
99
|
-
line_width 2
|
100
|
-
}
|
101
|
-
oval(2, 15, 8, 8) {
|
102
|
-
line_width 2
|
103
|
-
}
|
104
|
-
oval(16, 15, 8, 8) {
|
105
|
-
line_width 2
|
106
|
-
}
|
107
|
-
}
|
108
|
-
}
|
109
|
-
end
|
110
|
-
|
111
|
-
def copy_image
|
112
|
-
# building image on the fly with Canvas Shape DSL
|
113
|
-
image(25, 25) {
|
114
|
-
rectangle(0, 0, 25, 25) {
|
115
|
-
background_pattern 0, 0, 0, 25, :white, :gray
|
116
|
-
rectangle([:default, 2], [:default, -2], 14, 14, 5, 5) {
|
117
|
-
line_width 2
|
118
|
-
}
|
119
|
-
rectangle([:default, -2], [:default, 2], 14, 14, 5, 5) {
|
120
|
-
line_width 2
|
121
|
-
}
|
122
|
-
}
|
123
|
-
}
|
124
|
-
end
|
125
|
-
|
126
|
-
def paste_image
|
127
|
-
image(25, 25) {
|
128
|
-
rectangle(0, 0, 25, 25) {
|
129
|
-
background_pattern 0, 0, 0, 25, :white, :gray
|
130
|
-
rectangle(:default, [:default, 1], 15, 20, 5, 5) {
|
131
|
-
line_width 2
|
132
|
-
}
|
133
|
-
line(7, 8, 18, 8) {
|
134
|
-
line_width 2
|
135
|
-
}
|
136
|
-
line(7, 13, 18, 13) {
|
137
|
-
line_width 2
|
138
|
-
}
|
139
|
-
line(7, 18, 18, 18) {
|
140
|
-
line_width 2
|
141
|
-
}
|
142
|
-
}
|
143
|
-
}
|
144
|
-
end
|
145
90
|
end
|
146
91
|
|
147
92
|
HelloCoolBar.launch
|