glimmer-dsl-swt 4.18.4.1 → 4.18.4.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +84 -5072
  4. data/VERSION +1 -1
  5. data/docs/reference/GLIMMER_COMMAND.md +591 -0
  6. data/docs/reference/GLIMMER_CONFIGURATION.md +183 -0
  7. data/docs/reference/GLIMMER_GIRB.md +30 -0
  8. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +3251 -0
  9. data/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md +202 -0
  10. data/docs/reference/GLIMMER_SAMPLES.md +676 -0
  11. data/docs/reference/GLIMMER_STYLE_GUIDE.md +14 -0
  12. data/glimmer-dsl-swt.gemspec +16 -7
  13. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +3 -3
  14. data/lib/glimmer/dsl/swt/exec_expression.rb +1 -1
  15. data/lib/glimmer/dsl/swt/observe_expression.rb +8 -5
  16. data/lib/glimmer/dsl/swt/pixel_expression.rb +38 -0
  17. data/lib/glimmer/dsl/swt/timer_exec_expression.rb +35 -0
  18. data/lib/glimmer/dsl/swt/widget_expression.rb +1 -0
  19. data/lib/glimmer/swt/custom/animation.rb +9 -8
  20. data/lib/glimmer/swt/custom/code_text.rb +26 -18
  21. data/lib/glimmer/swt/custom/drawable.rb +21 -5
  22. data/lib/glimmer/swt/custom/shape.rb +42 -37
  23. data/lib/glimmer/swt/display_proxy.rb +11 -10
  24. data/lib/glimmer/swt/properties.rb +35 -10
  25. data/lib/glimmer/swt/shell_proxy.rb +1 -1
  26. data/lib/glimmer/swt/table_proxy.rb +2 -2
  27. data/lib/glimmer/swt/widget_proxy.rb +21 -6
  28. data/lib/glimmer/ui/custom_widget.rb +17 -0
  29. data/samples/elaborate/mandelbrot_fractal.rb +103 -0
  30. data/samples/elaborate/meta_sample.rb +14 -6
  31. data/samples/elaborate/tetris.rb +14 -17
  32. data/samples/elaborate/tetris/model/game.rb +1 -2
  33. data/samples/elaborate/tetris/view/high_score_dialog.rb +0 -7
  34. data/samples/elaborate/tetris/view/playfield.rb +1 -1
  35. data/samples/elaborate/tetris/view/tetris_menu_bar.rb +13 -11
  36. data/samples/hello/hello_canvas_transform.rb +1 -1
  37. data/samples/hello/hello_table.rb +1 -0
  38. metadata +14 -5
  39. data/samples/elaborate/meta_sample/meta_sample_logo.png +0 -0
@@ -0,0 +1,14 @@
1
+ ## Glimmer Style Guide
2
+
3
+ - Widgets are declared with underscored lowercase versions of their SWT names minus the SWT package name.
4
+ - Widget declarations may optionally have arguments and be followed by a block (to contain properties and content)
5
+ - Widget blocks are always declared with curly braces
6
+ - Widget arguments are always wrapped inside parentheses
7
+ - Widget properties are declared with underscored lowercase versions of the SWT properties
8
+ - Widget property declarations always have arguments and never take a block
9
+ - Widget property arguments are never wrapped inside parentheses
10
+ - Widget listeners are always declared starting with `on_` prefix and affixing listener event method name afterwards in underscored lowercase form
11
+ - Widget listeners are always followed by a block using curly braces (Only when declared in DSL. When invoked on widget object directly outside of GUI declarations, standard Ruby conventions apply)
12
+ - Data-binding is done via `bind` keyword, which always takes arguments wrapped in parentheses
13
+ - Custom widget body, before_body, and after_body blocks open their blocks and close them with curly braces.
14
+ - Custom widgets receive additional arguments to SWT style called options. These are passed as the last argument inside the parentheses, a hash of option names pointing to values.
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: glimmer-dsl-swt 4.18.4.1 ruby lib
5
+ # stub: glimmer-dsl-swt 4.18.4.6 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "glimmer-dsl-swt".freeze
9
- s.version = "4.18.4.1"
9
+ s.version = "4.18.4.6"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["AndyMaleh".freeze]
14
- s.date = "2021-02-03"
14
+ s.date = "2021-02-11"
15
15
  s.description = "Glimmer DSL for SWT (JRuby Desktop Development GUI Framework) is a native-GUI cross-platform desktop development library written in JRuby, an OS-threaded faster JVM version of Ruby. Glimmer's main innovation is a declarative Ruby DSL that enables productive and efficient authoring of desktop application user-interfaces by relying on the robust Eclipse SWT library. Glimmer additionally innovates by having built-in data-binding support, which greatly facilitates synchronizing the GUI with domain models, thus achieving true decoupling of object oriented components and enabling developers to solve business problems (test-first) without worrying about GUI concerns, or alternatively drive development GUI-first, and then write clean business models (test-first) afterwards. Not only does Glimmer provide a large set of GUI widgets, but it also supports drawing Canvas Graphics like Shapes and Animations. To get started quickly, Glimmer offers scaffolding options for Apps, Gems, and Custom Widgets. Glimmer also includes native-executable packaging support, sorely lacking in other libraries, thus enabling the delivery of desktop apps written in Ruby as truly native DMG/PKG/APP files on the Mac + App Store, MSI/EXE files on Windows, and Gem Packaged Shell Scripts on Linux.".freeze
16
16
  s.email = "andy.am@gmail.com".freeze
17
17
  s.executables = ["glimmer".freeze, "girb".freeze]
@@ -28,6 +28,13 @@ Gem::Specification.new do |s|
28
28
  "bin/girb",
29
29
  "bin/girb_runner.rb",
30
30
  "bin/glimmer",
31
+ "docs/reference/GLIMMER_COMMAND.md",
32
+ "docs/reference/GLIMMER_CONFIGURATION.md",
33
+ "docs/reference/GLIMMER_GIRB.md",
34
+ "docs/reference/GLIMMER_GUI_DSL_SYNTAX.md",
35
+ "docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md",
36
+ "docs/reference/GLIMMER_SAMPLES.md",
37
+ "docs/reference/GLIMMER_STYLE_GUIDE.md",
31
38
  "glimmer-dsl-swt.gemspec",
32
39
  "icons/scaffold_app.icns",
33
40
  "icons/scaffold_app.ico",
@@ -72,6 +79,7 @@ Gem::Specification.new do |s|
72
79
  "lib/glimmer/dsl/swt/message_box_expression.rb",
73
80
  "lib/glimmer/dsl/swt/multiply_expression.rb",
74
81
  "lib/glimmer/dsl/swt/observe_expression.rb",
82
+ "lib/glimmer/dsl/swt/pixel_expression.rb",
75
83
  "lib/glimmer/dsl/swt/property_expression.rb",
76
84
  "lib/glimmer/dsl/swt/radio_group_selection_data_binding_expression.rb",
77
85
  "lib/glimmer/dsl/swt/rgb_expression.rb",
@@ -82,6 +90,7 @@ Gem::Specification.new do |s|
82
90
  "lib/glimmer/dsl/swt/sync_exec_expression.rb",
83
91
  "lib/glimmer/dsl/swt/tab_item_expression.rb",
84
92
  "lib/glimmer/dsl/swt/table_items_data_binding_expression.rb",
93
+ "lib/glimmer/dsl/swt/timer_exec_expression.rb",
85
94
  "lib/glimmer/dsl/swt/transform_expression.rb",
86
95
  "lib/glimmer/dsl/swt/tree_items_data_binding_expression.rb",
87
96
  "lib/glimmer/dsl/swt/tree_properties_expression.rb",
@@ -135,8 +144,8 @@ Gem::Specification.new do |s|
135
144
  "samples/elaborate/contact_manager/contact_manager_presenter.rb",
136
145
  "samples/elaborate/contact_manager/contact_repository.rb",
137
146
  "samples/elaborate/login.rb",
147
+ "samples/elaborate/mandelbrot_fractal.rb",
138
148
  "samples/elaborate/meta_sample.rb",
139
- "samples/elaborate/meta_sample/meta_sample_logo.png",
140
149
  "samples/elaborate/tetris.rb",
141
150
  "samples/elaborate/tetris/model/block.rb",
142
151
  "samples/elaborate/tetris/model/game.rb",
@@ -200,7 +209,7 @@ Gem::Specification.new do |s|
200
209
  s.specification_version = 4
201
210
 
202
211
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
203
- s.add_runtime_dependency(%q<glimmer>.freeze, ["~> 1.0.11"])
212
+ s.add_runtime_dependency(%q<glimmer>.freeze, ["~> 1.1.1"])
204
213
  s.add_runtime_dependency(%q<super_module>.freeze, [">= 1.4.1", "< 2.0.0"])
205
214
  s.add_runtime_dependency(%q<nested_inherited_jruby_include_package>.freeze, [">= 0.3.0", "< 2.0.0"])
206
215
  s.add_runtime_dependency(%q<puts_debuggerer>.freeze, [">= 0.11.0", "< 2.0.0"])
@@ -219,7 +228,7 @@ Gem::Specification.new do |s|
219
228
  s.add_development_dependency(%q<simplecov>.freeze, ["~> 0.16.1"])
220
229
  s.add_development_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
221
230
  else
222
- s.add_dependency(%q<glimmer>.freeze, ["~> 1.0.11"])
231
+ s.add_dependency(%q<glimmer>.freeze, ["~> 1.1.1"])
223
232
  s.add_dependency(%q<super_module>.freeze, [">= 1.4.1", "< 2.0.0"])
224
233
  s.add_dependency(%q<nested_inherited_jruby_include_package>.freeze, [">= 0.3.0", "< 2.0.0"])
225
234
  s.add_dependency(%q<puts_debuggerer>.freeze, [">= 0.11.0", "< 2.0.0"])
@@ -239,7 +248,7 @@ Gem::Specification.new do |s|
239
248
  s.add_dependency(%q<simplecov-lcov>.freeze, ["~> 0.7.0"])
240
249
  end
241
250
  else
242
- s.add_dependency(%q<glimmer>.freeze, ["~> 1.0.11"])
251
+ s.add_dependency(%q<glimmer>.freeze, ["~> 1.1.1"])
243
252
  s.add_dependency(%q<super_module>.freeze, [">= 1.4.1", "< 2.0.0"])
244
253
  s.add_dependency(%q<nested_inherited_jruby_include_package>.freeze, [">= 0.3.0", "< 2.0.0"])
245
254
  s.add_dependency(%q<puts_debuggerer>.freeze, [">= 0.11.0", "< 2.0.0"])
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2007-2021 Andy Maleh
2
- #
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -41,7 +41,7 @@ module Glimmer
41
41
  end
42
42
 
43
43
  def interpret(parent, keyword, *args, &block)
44
- Glimmer::SWT::DisplayProxy.instance.swt_display.send(exec_operation) do |*args|
44
+ Glimmer::SWT::DisplayProxy.instance.swt_display.send(exec_operation, *args) do |*args|
45
45
  begin
46
46
  block.call(*args)
47
47
  rescue => e
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2007-2021 Andy Maleh
2
- #
2
+ #
3
3
  # Permission is hereby granted, free of charge, to any person obtaining
4
4
  # a copy of this software and associated documentation files (the
5
5
  # "Software"), to deal in the Software without restriction, including
@@ -7,10 +7,10 @@
7
7
  # distribute, sublicense, and/or sell copies of the Software, and to
8
8
  # permit persons to whom the Software is furnished to do so, subject to
9
9
  # the following conditions:
10
- #
10
+ #
11
11
  # The above copyright notice and this permission notice shall be
12
12
  # included in all copies or substantial portions of the Software.
13
- #
13
+ #
14
14
  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
15
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
16
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@@ -23,6 +23,7 @@ require 'glimmer/dsl/static_expression'
23
23
  require 'glimmer/dsl/top_level_expression'
24
24
  require 'glimmer/data_binding/observer'
25
25
  require 'glimmer/data_binding/model_binding'
26
+ require 'glimmer/ui/custom_widget'
26
27
 
27
28
  module Glimmer
28
29
  module DSL
@@ -42,10 +43,12 @@ module Glimmer
42
43
  def interpret(parent, keyword, *args, &block)
43
44
  observer = DataBinding::Observer.proc(&block)
44
45
  if args[1].to_s.match(REGEX_NESTED_OR_INDEXED_PROPERTY)
45
- observer.observe(DataBinding::ModelBinding.new(args[0], args[1]))
46
+ observer_registration = observer.observe(DataBinding::ModelBinding.new(args[0], args[1]))
46
47
  else
47
- observer.observe(args[0], args[1])
48
+ observer_registration = observer.observe(args[0], args[1])
48
49
  end
50
+ Glimmer::UI::CustomWidget.current_custom_widgets.last&.observer_registrations&.push(observer_registration)
51
+ observer_registration
49
52
  end
50
53
  end
51
54
  end
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/dsl/static_expression'
23
+ require 'glimmer/swt/swt_proxy'
24
+ require 'glimmer/swt/custom/shape'
25
+ require 'glimmer/swt/custom/drawable'
26
+
27
+ module Glimmer
28
+ module DSL
29
+ module SWT
30
+ class PixelExpression < StaticExpression
31
+
32
+ def interpret(parent, keyword, *args, &block)
33
+ Glimmer::SWT::Custom::Shape.new(parent, 'point', *args, &block)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 2007-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/dsl/static_expression'
23
+ require 'glimmer/dsl/swt/exec_expression'
24
+
25
+ module Glimmer
26
+ module DSL
27
+ module SWT
28
+ # Asynchronously executes code block against the SWT Event Loop
29
+ # after a certain time elapsed
30
+ class TimerExecExpression < StaticExpression
31
+ include ExecExpression
32
+ end
33
+ end
34
+ end
35
+ end
@@ -46,6 +46,7 @@ module Glimmer
46
46
  def add_content(parent, &block)
47
47
  super
48
48
  parent.post_add_content
49
+ parent.finish_add_content!
49
50
  end
50
51
 
51
52
  end
@@ -26,7 +26,7 @@ module Glimmer
26
26
  module Custom
27
27
  # Represents an animation declaratively
28
28
  class Animation
29
- include Properties # TODO rename to Properties
29
+ include Properties
30
30
 
31
31
  class << self
32
32
  def schedule_frame_animation(animation, &frame_animation_block)
@@ -92,8 +92,10 @@ module Glimmer
92
92
  end
93
93
 
94
94
  def post_add_content
95
- @parent.on_widget_disposed { stop }
96
- start if started?
95
+ if @dispose_listener_registration.nil?
96
+ @dispose_listener_registration = @parent.on_widget_disposed { stop }
97
+ start if started?
98
+ end
97
99
  end
98
100
 
99
101
  # Starts an animation that is indefinite or has never been started before (i.e. having `started: false` option).
@@ -212,11 +214,10 @@ module Glimmer
212
214
  current_cycle_count_index = @cycle_count_index
213
215
  self.class.schedule_frame_animation(self) do
214
216
  if started? && start_number == @start_number && within_duration_limit?
215
- @parent.clear_shapes
216
- @parent.content {
217
- frame_block.call(*block_args)
218
- }
219
- @parent.redraw
217
+ unless @parent.isDisposed
218
+ @parent.clear_shapes # TODO adjust this to clear only the shapes of this animation (not all shapes) to allow simultaneous animations to occur on the same parent
219
+ @parent.content { frame_block.call(*block_args) }
220
+ end
220
221
  else
221
222
  if stopped? && @frame_index > current_frame_index
222
223
  @started = false
@@ -22,8 +22,6 @@ module Glimmer
22
22
  REGEX_COLOR_HEX6 = /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/
23
23
 
24
24
  # TODO support auto language detection
25
- # TODO support end of line via CMD+E and beginning of line via CMD+A
26
- # TODO support select all via CMD+A
27
25
 
28
26
  option :language, default: 'ruby'
29
27
  # TODO consider supporting data-binding of language
@@ -31,6 +29,9 @@ module Glimmer
31
29
  # TODO support method for redrawing the syntax highlighting
32
30
  option :theme, default: 'glimmer'
33
31
  option :lines, default: false
32
+
33
+ # This option indicates if default keyboard handlers/menus should be activated
34
+ option :default_behavior, default: true
34
35
 
35
36
  alias lines? lines
36
37
  attr_accessor :styled_text_proxy_text, :styled_text_proxy_top_pixel
@@ -42,6 +43,7 @@ module Glimmer
42
43
  args.pop if args.last.is_a?(Hash) && args.last[:dsl]
43
44
  super(method_name, *args, &block)
44
45
  elsif @styled_text_proxy&.respond_to?(method_name, *args, &block)
46
+ @line_numbers_styled_text_proxy&.send(method_name, *args, &block) if method_name.to_s == 'font='
45
47
  @styled_text_proxy&.send(method_name, *args, &block)
46
48
  else
47
49
  super
@@ -88,24 +90,29 @@ module Glimmer
88
90
  }
89
91
 
90
92
  body {
91
- # TODO enable this once fully implemented
92
93
  if lines
93
94
  composite {
94
95
  grid_layout(2, false)
95
96
 
96
97
  @line_numbers_styled_text_proxy = styled_text(swt(swt(swt_style), :h_scroll!, :v_scroll!)) {
97
98
  layout_data(:right, :fill, false, true)
98
- text ' '*lines_width.to_i
99
- text bind(self, :styled_text_proxy_text, read_only: true) { |text_value|
100
- line_count = text_value.to_s.split("\n").count
101
- line_count = 1 if line_count == 0
102
- lines_text_size = [line_count.to_s.size, @lines_width].max
103
- if lines_text_size > @lines_width
104
- async_exec { swt_widget.layout }
105
- @lines_width = lines_text_size
106
- end
107
- line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n") + "\n"
108
- }
99
+ top_pixel_before_read = nil
100
+ text bind(self,
101
+ :styled_text_proxy_text,
102
+ read_only: true,
103
+ on_read: lambda { |text_value|
104
+ line_count = "#{text_value} ".split("\n").count
105
+ line_count = 1 if line_count == 0
106
+ lines_text_size = [line_count.to_s.size, @lines_width].max
107
+ if lines_text_size > @lines_width
108
+ @lines_width = lines_text_size
109
+ end
110
+ line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n") + "\n"
111
+ },
112
+ after_read: lambda {
113
+ @line_numbers_styled_text_proxy&.top_pixel = styled_text_proxy_top_pixel
114
+ }
115
+ )
109
116
  top_pixel bind(self, :styled_text_proxy_top_pixel, read_only: true)
110
117
  font name: @font_name, height: OS.mac? ? 15 : 12
111
118
  background color(:widget_background)
@@ -140,22 +147,22 @@ module Glimmer
140
147
  layout_data :fill, :fill, true, true if lines
141
148
  text bind(self, :styled_text_proxy_text) if lines
142
149
  top_pixel bind(self, :styled_text_proxy_top_pixel) if lines
143
- font name: @font_name, height: 15
150
+ font name: @font_name, height: OS.mac? ? 15 : 12
144
151
  foreground rgb(75, 75, 75)
145
152
  left_margin 5
146
153
  top_margin 5
147
154
  right_margin 5
148
155
  bottom_margin 5
149
156
 
150
- if lines
157
+ if default_behavior
151
158
  on_key_pressed { |event|
152
159
  character = event.keyCode.chr rescue nil
153
160
  case [event.stateMask, character]
154
161
  when [(OS.mac? ? swt(:command) : swt(:ctrl)), 'a']
155
162
  @styled_text_proxy.swt_widget.selectAll
156
- when [(swt(:ctrl) unless OS.windows?), 'a']
163
+ when [(swt(:ctrl) if OS.mac?), 'a']
157
164
  jump_to_beginning_of_line
158
- when [(swt(:ctrl) unless OS.windows?), 'e']
165
+ when [(swt(:ctrl) if OS.mac?), 'e']
159
166
  jump_to_end_of_line
160
167
  end
161
168
  }
@@ -224,6 +231,7 @@ module Glimmer
224
231
  @lexer ||= Rouge::Lexer.find_fancy('ruby') # default to Ruby if no lexer is found
225
232
  end
226
233
 
234
+ # TODO extract this to ColorProxy
227
235
  def hex_color_to_swt_color(color_data, default_color)
228
236
  color_data = "##{color_data.chars.drop(1).map {|c| c*2}.join}" if color_data.is_a?(String) && color_data.start_with?('#') && color_data&.size == 4
229
237
  color_data = color_data.match(REGEX_COLOR_HEX6).to_a.drop(1).map {|c| "0x#{c}".hex}.to_a if color_data.is_a?(String) && color_data.start_with?('#')
@@ -32,14 +32,30 @@ module Glimmer
32
32
  shapes.dup.each(&:dispose)
33
33
  end
34
34
 
35
- def resetup_shape_painting
35
+ def deregister_shape_painting
36
+ @paint_listener_proxy&.deregister
37
+ end
38
+
39
+ def setup_shape_painting
36
40
  # TODO consider performance optimization relating to order of shape rendering (affecting only further shapes not previous ones)
37
- reset_gc if respond_to?(:reset_gc)
38
- shapes.each do |shape|
39
- shape.paint_listener_proxy&.unregister
40
- shape.setup_painting
41
+ if @paint_listener_proxy.nil?
42
+ shape_painter = lambda do |paint_event|
43
+ shapes.each do |shape|
44
+ shape.paint(paint_event)
45
+ end
46
+ end
47
+
48
+ # TODO consider making this logic polymorphic (image vs other)
49
+ if respond_to?(:swt_image)
50
+ shape_painter.call(self) # treat self as paint event since image has its own gc and doesn't do repaints (it's a one time deal for now though could be adjusted in the future.)
51
+ else
52
+ @paint_listener_proxy = on_swt_paint(&shape_painter)
53
+ end
54
+ else
55
+ redraw if @finished_add_content && !is_disposed
41
56
  end
42
57
  end
58
+ alias resetup_shape_painting setup_shape_painting
43
59
  end
44
60
 
45
61
  end
@@ -39,7 +39,7 @@ module Glimmer
39
39
 
40
40
  class << self
41
41
  def valid?(parent, keyword, *args, &block)
42
- gc_instance_methods.include?(method_name(keyword, args))
42
+ gc_instance_methods.include?(method_name(keyword, arg_options(args)))
43
43
  end
44
44
 
45
45
  def gc_instance_methods
@@ -62,14 +62,14 @@ module Glimmer
62
62
  options.nil? ? {} : options.symbolize_keys
63
63
  end
64
64
 
65
- def method_name(keyword, args)
66
- method_arg_options = arg_options(args)
65
+ def method_name(keyword, method_arg_options)
66
+ keyword = keyword.to_s
67
+ method_arg_options = method_arg_options.select {|key, value| %w[fill gradient round].include?(key.to_s)}
67
68
  unless flyweight_method_names.keys.include?([keyword, method_arg_options])
68
- keyword = keyword.to_s
69
- gradient = 'gradient_' if method_arg_options[:gradient]
70
- round = 'round_' if method_arg_options[:round]
71
- gc_instance_method_name_prefix = !['polyline', 'point', 'image', 'focus'].include?(keyword) && (method_arg_options[:fill] || method_arg_options[:gradient]) ? 'fill_' : 'draw_'
72
- flyweight_method_names[[keyword, method_arg_options]] = "#{gc_instance_method_name_prefix}#{gradient}#{round}#{keyword}"
69
+ gradient = 'Gradient' if method_arg_options[:gradient]
70
+ round = 'Round' if method_arg_options[:round]
71
+ gc_instance_method_name_prefix = !['polyline', 'point', 'image', 'focus'].include?(keyword) && (method_arg_options[:fill] || method_arg_options[:gradient]) ? 'fill' : 'draw'
72
+ flyweight_method_names[[keyword, method_arg_options]] = "#{gc_instance_method_name_prefix}#{gradient}#{round}#{keyword.capitalize}"
73
73
  end
74
74
  flyweight_method_names[[keyword, method_arg_options]]
75
75
  end
@@ -91,15 +91,18 @@ module Glimmer
91
91
  end
92
92
  end
93
93
 
94
- attr_reader :parent, :name, :args, :options, :paint_listener_proxy
94
+ attr_reader :parent, :name, :args, :options
95
95
 
96
96
  def initialize(parent, keyword, *args, &property_block)
97
97
  @parent = parent
98
98
  @name = keyword
99
- @method_name = self.class.method_name(keyword, args)
100
99
  @options = self.class.arg_options(args, extract: true)
100
+ @method_name = self.class.method_name(keyword, @options)
101
101
  @args = args
102
102
  @properties = {}
103
+ @options.reject {|key, value| %w[fill gradient round].include?(key.to_s)}.each do |property, property_args|
104
+ @properties[property] = property_args
105
+ end
103
106
  @parent.shapes << self
104
107
  post_add_content if property_block.nil?
105
108
  end
@@ -129,9 +132,11 @@ module Glimmer
129
132
  end
130
133
 
131
134
  def post_add_content
132
- amend_method_name_options_based_on_properties
133
- setup_painting
134
- @content_added = true
135
+ unless @content_added
136
+ amend_method_name_options_based_on_properties
137
+ @parent.setup_shape_painting
138
+ @content_added = true
139
+ end
135
140
  end
136
141
 
137
142
  def apply_property_arg_conversions(method_name, property, args)
@@ -207,6 +212,7 @@ module Glimmer
207
212
  end
208
213
 
209
214
  def amend_method_name_options_based_on_properties
215
+ return if @name == 'point'
210
216
  if has_some_background? && !has_some_foreground?
211
217
  @options[:fill] = true
212
218
  elsif !has_some_background? && has_some_foreground?
@@ -218,7 +224,7 @@ module Glimmer
218
224
  if @name == 'rectangle' && @args.size > 4 && @args.last.is_a?(Numeric)
219
225
  @options[:round] = true
220
226
  end
221
- @method_name = self.class.method_name(@name, @args + [@options])
227
+ @method_name = self.class.method_name(@name, @options)
222
228
  end
223
229
 
224
230
  def has_attribute?(attribute_name, *args)
@@ -228,7 +234,7 @@ module Glimmer
228
234
  def set_attribute(attribute_name, *args)
229
235
  @properties[attribute_name] = args
230
236
  if @content_added && !@parent.is_disposed
231
- @parent.resetup_shape_painting
237
+ @calculated_paint_args = false
232
238
  @parent.redraw
233
239
  end
234
240
  end
@@ -247,7 +253,6 @@ module Glimmer
247
253
  end
248
254
 
249
255
  def dispose
250
- paint_listener_proxy&.unregister
251
256
  @background_pattern&.dispose
252
257
  @background_pattern = nil
253
258
  @foreground_pattern&.dispose
@@ -257,36 +262,36 @@ module Glimmer
257
262
  @parent.shapes.delete(self)
258
263
  end
259
264
 
260
- def setup_painting
261
- # TODO consider moving this method to parent (making the logic polymorphic)
262
- return if @parent.is_disposed
263
- if parent.respond_to?(:swt_display)
264
- @paint_listener_proxy = @parent.on_swt_paint(&method(:paint))
265
- elsif parent.respond_to?(:swt_image)
266
- paint(parent) # treat parent as paint event since you don't do repaints with images, it's a one time deal.
267
- elsif parent.respond_to?(:swt_widget)
268
- @paint_listener_proxy = @parent.on_paint_control(&method(:paint))
269
- end
270
- end
271
-
272
265
  def paint(paint_event)
273
- @properties['background'] = [@parent.background] if fill? && !has_some_background?
274
- @properties['foreground'] = [@parent.foreground] if @parent.respond_to?(:foreground) && draw? && !has_some_foreground?
275
- @properties['font'] = [@parent.font] if @parent.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
276
- @properties['transform'] = [nil] if @parent.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
266
+ calculate_paint_args!
277
267
  @properties.each do |property, args|
278
268
  method_name = attribute_setter(property)
279
- converted_args = apply_property_arg_conversions(method_name, property, args)
280
- paint_event.gc.send(method_name, *converted_args)
269
+ # TODO consider optimization of not setting a background/foreground/font if it didn't change from last shape
270
+ paint_event.gc.send(method_name, *args)
281
271
  if property == 'transform' && args.first.is_a?(TransformProxy)
282
272
  args.first.swt_transform.dispose
283
273
  end
284
274
  end
285
- apply_shape_arg_conversions(@method_name, @args)
286
- apply_shape_arg_defaults(@method_name, @args)
287
- tolerate_shape_extra_args(@method_name, @args)
288
275
  paint_event.gc.send(@method_name, *@args)
289
276
  end
277
+
278
+ def calculate_paint_args!
279
+ unless @name == 'point' || @calculated_paint_args
280
+ @properties['background'] = [@parent.background] if fill? && !has_some_background?
281
+ @properties['foreground'] = [@parent.foreground] if @parent.respond_to?(:foreground) && draw? && !has_some_foreground?
282
+ @properties['font'] = [@parent.font] if @parent.respond_to?(:font) && draw? && !@properties.keys.map(&:to_s).include?('font')
283
+ @properties['transform'] = [nil] if @parent.respond_to?(:transform) && !@properties.keys.map(&:to_s).include?('transform')
284
+ @properties.each do |property, args|
285
+ method_name = attribute_setter(property)
286
+ converted_args = apply_property_arg_conversions(method_name, property, args)
287
+ @properties[property] = converted_args
288
+ end
289
+ apply_shape_arg_conversions(@method_name, @args)
290
+ apply_shape_arg_defaults(@method_name, @args)
291
+ tolerate_shape_extra_args(@method_name, @args)
292
+ @calculated_paint_args = true
293
+ end
294
+ end
290
295
 
291
296
  end
292
297