glimmer-dsl-swt 4.18.7.6 → 4.20.0.0

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.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +34 -21
  4. data/RUBY_VERSION +1 -1
  5. data/VERSION +1 -1
  6. data/bin/girb +10 -9
  7. data/bin/girb_runner.rb +8 -3
  8. data/bin/glimmer +10 -1
  9. data/bin/glimmer-setup +58 -0
  10. data/bin/glimmer_runner.rb +4 -0
  11. data/docs/reference/GLIMMER_COMMAND.md +19 -30
  12. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +39 -10
  13. data/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md +7 -1
  14. data/docs/reference/GLIMMER_SAMPLES.md +27 -0
  15. data/glimmer-dsl-swt.gemspec +0 -0
  16. data/lib/glimmer-dsl-swt.rb +8 -0
  17. data/lib/glimmer/data_binding/shine.rb +41 -26
  18. data/lib/glimmer/data_binding/widget_binding.rb +1 -1
  19. data/lib/glimmer/dsl/swt/c_tab_item_expression.rb +58 -0
  20. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +2 -1
  21. data/lib/glimmer/dsl/swt/dsl.rb +2 -1
  22. data/lib/glimmer/dsl/swt/shine_data_binding_expression.rb +49 -0
  23. data/lib/glimmer/dsl/swt/tab_item_expression.rb +7 -3
  24. data/lib/glimmer/dsl/swt/widget_expression.rb +1 -1
  25. data/lib/glimmer/launcher.rb +33 -51
  26. data/lib/glimmer/rake_task.rb +1 -1
  27. data/lib/glimmer/rake_task/package.rb +7 -2
  28. data/lib/glimmer/rake_task/scaffold.rb +227 -254
  29. data/lib/glimmer/swt/c_tab_item_proxy.rb +53 -0
  30. data/lib/glimmer/swt/custom/code_text.rb +17 -9
  31. data/lib/glimmer/swt/custom/shape.rb +15 -1
  32. data/lib/glimmer/swt/sash_form_proxy.rb +6 -0
  33. data/lib/glimmer/swt/shell_proxy.rb +3 -1
  34. data/lib/glimmer/swt/tab_folder_proxy.rb +1 -0
  35. data/lib/glimmer/swt/tab_item_proxy.rb +17 -18
  36. data/lib/glimmer/swt/widget_proxy.rb +9 -0
  37. data/samples/elaborate/contact_manager.rb +7 -5
  38. data/samples/elaborate/login.rb +7 -7
  39. data/samples/elaborate/mandelbrot_fractal.rb +13 -8
  40. data/samples/elaborate/meta_sample.rb +4 -2
  41. data/samples/elaborate/metronome.rb +4 -4
  42. data/samples/elaborate/stock_ticker.rb +2 -2
  43. data/samples/elaborate/tic_tac_toe.rb +2 -2
  44. data/samples/hello/hello_button.rb +1 -1
  45. data/samples/hello/hello_c_combo.rb +69 -0
  46. data/samples/hello/hello_c_tab.rb +174 -0
  47. data/samples/hello/hello_c_tab/denmark.png +0 -0
  48. data/samples/hello/hello_c_tab/finland.png +0 -0
  49. data/samples/hello/hello_c_tab/france.png +0 -0
  50. data/samples/hello/hello_c_tab/germany.png +0 -0
  51. data/samples/hello/hello_c_tab/italy.png +0 -0
  52. data/samples/hello/hello_c_tab/mexico.png +0 -0
  53. data/samples/hello/hello_c_tab/netherlands.png +0 -0
  54. data/samples/hello/hello_c_tab/norway.png +0 -0
  55. data/samples/hello/hello_c_tab/usa.png +0 -0
  56. data/samples/hello/hello_canvas.rb +5 -5
  57. data/samples/hello/hello_canvas_animation_data_binding.rb +1 -1
  58. data/samples/hello/hello_canvas_data_binding.rb +16 -16
  59. data/samples/hello/hello_checkbox.rb +4 -4
  60. data/samples/hello/hello_code_text.rb +3 -57
  61. data/samples/hello/hello_color_dialog.rb +1 -1
  62. data/samples/hello/hello_combo.rb +1 -1
  63. data/samples/hello/hello_computed.rb +5 -5
  64. data/samples/hello/hello_custom_widget.rb +1 -1
  65. data/samples/hello/hello_date_time.rb +4 -4
  66. data/samples/hello/hello_dialog.rb +3 -2
  67. data/samples/hello/hello_drag_and_drop.rb +1 -1
  68. data/samples/hello/hello_file_dialog.rb +1 -1
  69. data/samples/hello/hello_font_dialog.rb +3 -3
  70. data/samples/hello/hello_group.rb +6 -6
  71. data/samples/hello/hello_link.rb +56 -50
  72. data/samples/hello/hello_list_multi_selection.rb +1 -1
  73. data/samples/hello/hello_list_single_selection.rb +1 -1
  74. data/samples/hello/hello_progress_bar.rb +10 -10
  75. data/samples/hello/hello_radio.rb +6 -6
  76. data/samples/hello/hello_sash_form.rb +4 -4
  77. data/samples/hello/hello_shape.rb +1 -0
  78. data/samples/hello/hello_spinner.rb +6 -2
  79. data/samples/hello/hello_styled_text.rb +11 -11
  80. data/samples/hello/hello_tab.rb +2 -0
  81. data/vendor/swt/linux/swt.jar +0 -0
  82. data/vendor/swt/linux_aarch64/swt.jar +0 -0
  83. data/vendor/swt/mac/swt.jar +0 -0
  84. data/vendor/swt/mac_aarch64/swt.jar +0 -0
  85. data/vendor/swt/windows/swt.jar +0 -0
  86. metadata +76 -32
@@ -0,0 +1,53 @@
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/swt/widget_proxy'
23
+ require 'glimmer/swt/tab_item_proxy'
24
+
25
+ module Glimmer
26
+ module SWT
27
+ # Proxy for org.eclipse.swt.custom.CTabItem
28
+ #
29
+ # Functions differently from other widget proxies.
30
+ #
31
+ # Glimmer instantiates an SWT Composite alongside the SWT TabItem
32
+ # and returns it for `#swt_widget` to allow adding widgets into it.
33
+ #
34
+ # In order to get the SWT TabItem object, one must call `#swt_tab_item`.
35
+ #
36
+ # Behind the scenes, this creates a tab item widget proxy separately from a composite that
37
+ # is set as the control of the tab item and `#swt_widget`.
38
+ #
39
+ # In order to retrieve the tab item widget proxy, one must call `#widget_proxy`
40
+ #
41
+ # Follows the Proxy Design Pattern
42
+ class CTabItemProxy < TabItemProxy
43
+ ATTRIBUTES = TabItemProxy::ATTRIBUTES + %w[foreground selection_foreground show_close font]
44
+
45
+ def attributes
46
+ ATTRIBUTES
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -78,6 +78,8 @@ module Glimmer
78
78
 
79
79
  def can_handle_observation_request?(observation_request)
80
80
  @styled_text_proxy&.can_handle_observation_request?(observation_request) || super
81
+ rescue
82
+ super
81
83
  end
82
84
 
83
85
  def handle_observation_request(observation_request, &block)
@@ -86,6 +88,8 @@ module Glimmer
86
88
  else
87
89
  super
88
90
  end
91
+ rescue
92
+ super
89
93
  end
90
94
 
91
95
  def root_block=(block)
@@ -120,21 +124,15 @@ module Glimmer
120
124
 
121
125
  @line_numbers_styled_text_proxy = styled_text(swt(swt(swt_style), :h_scroll!, :v_scroll!)) {
122
126
  layout_data(:right, :fill, false, true)
123
- top_pixel_before_read = nil
127
+
124
128
  text bind(self,
125
129
  :styled_text_proxy_text,
126
130
  read_only: true,
127
131
  on_read: lambda { |text_value|
128
- line_count = "#{text_value} ".split("\n").count
129
- line_count = 1 if line_count == 0
130
- lines_text_size = [line_count.to_s.size, @lines_width].max
131
- if lines_text_size > @lines_width
132
- @lines_width = lines_text_size
133
- end
134
- line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n") + "\n"
132
+ line_numbers_text_from(text_value)
135
133
  },
136
134
  after_read: lambda {
137
- @line_numbers_styled_text_proxy&.top_pixel = styled_text_proxy_top_pixel
135
+ @line_numbers_styled_text_proxy&.top_pixel = styled_text_proxy_top_pixel unless styled_text_proxy_top_pixel.nil?
138
136
  }
139
137
  )
140
138
  top_pixel bind(self, :styled_text_proxy_top_pixel, read_only: true)
@@ -147,6 +145,7 @@ module Glimmer
147
145
  left_margin 5
148
146
  editable false
149
147
  caret nil
148
+
150
149
  on_focus_gained {
151
150
  @styled_text_proxy&.setFocus
152
151
  }
@@ -169,6 +168,7 @@ module Glimmer
169
168
  @styled_text_proxy = styled_text(swt_style) {
170
169
  # custom_widget_property_owner # TODO implement to route properties here without declaring method_missing
171
170
  layout_data :fill, :fill, true, true if lines
171
+
172
172
  text bind(self, :styled_text_proxy_text) if lines
173
173
  top_pixel bind(self, :styled_text_proxy_top_pixel) if lines
174
174
  font name: @font_name, height: OS.mac? ? 15 : 12
@@ -287,6 +287,14 @@ module Glimmer
287
287
  new_offset = beginning_of_current_line_offset + current_line.size
288
288
  @styled_text_proxy.setSelection(new_offset, new_offset)
289
289
  end
290
+
291
+ def line_numbers_text_from(text_value)
292
+ line_count = "#{text_value} ".split("\n").count
293
+ line_count = 1 if line_count == 0
294
+ lines_text_size = [line_count.to_s.size, @lines_width].max
295
+ @lines_width = lines_text_size if lines_text_size > @lines_width
296
+ line_count.times.map {|n| (' ' * (lines_text_size - (n+1).to_s.size)) + (n+1).to_s }.join("\n") + "\n"
297
+ end
290
298
  end
291
299
  end
292
300
  end
@@ -572,7 +572,7 @@ module Glimmer
572
572
  end
573
573
 
574
574
  def dispose(dispose_images: true, dispose_patterns: true, redraw: true)
575
- shapes.each { |shape| shape.is_a?(Shape::Path) && shape.dispose }
575
+ shapes.each { |shape| shape.is_a?(Shape::Path) && shape.dispose } # TODO look into why I'm only disposing paths
576
576
  if dispose_patterns
577
577
  @background_pattern&.dispose
578
578
  @background_pattern = nil
@@ -587,6 +587,20 @@ module Glimmer
587
587
  drawable.redraw if redraw && !drawable.is_a?(ImageProxy)
588
588
  end
589
589
 
590
+ # clear all shapes
591
+ # indicate whether to dispose images, dispose patterns, and redraw after clearing shapes.
592
+ # redraw can be `:all` or `true` to mean redraw after all shapes are disposed, `:each` to mean redraw after each shape is disposed, or `false` to avoid redraw altogether
593
+ def clear_shapes(dispose_images: true, dispose_patterns: true, redraw: :all)
594
+ if redraw == true || redraw == :all
595
+ shapes.dup.each {|shape| shape.dispose(dispose_images: dispose_images, dispose_patterns: dispose_patterns, redraw: false) }
596
+ drawable.redraw if redraw && !drawable.is_a?(ImageProxy)
597
+ elsif redraw == :each
598
+ shapes.dup.each {|shape| shape.dispose(dispose_images: dispose_images, dispose_patterns: dispose_patterns, redraw: true) }
599
+ else
600
+ shapes.dup.each {|shape| shape.dispose(dispose_images: dispose_images, dispose_patterns: dispose_patterns, redraw: false) }
601
+ end
602
+ end
603
+
590
604
  # Indicate if this is a container shape (meaning a shape bag that is just there to contain nested shapes, but doesn't render anything of its own)
591
605
  def container?
592
606
  @name == 'shape'
@@ -20,6 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/swt/widget_proxy'
23
+ require 'glimmer/swt/color_proxy'
23
24
 
24
25
  module Glimmer
25
26
  module SWT
@@ -27,6 +28,11 @@ module Glimmer
27
28
  #
28
29
  # Follows the Proxy Design Pattern
29
30
  class SashFormProxy < WidgetProxy
31
+ def initialize(*args, &block)
32
+ super
33
+ self.background = ColorProxy.new(230, 230, 230).swt_color
34
+ end
35
+
30
36
  def post_add_content
31
37
  self.weights = @weights unless @weights.nil?
32
38
  end
@@ -74,7 +74,9 @@ module Glimmer
74
74
  # TODO make this an option not the default
75
75
  shell_swt_display = Glimmer::SWT::DisplayProxy.instance.swt_display
76
76
  on_swt_show do
77
- @swt_widget.set_size(@display.bounds.width, @display.bounds.height) if fill_screen
77
+ if @filled_screen.nil? && fill_screen # only the first time
78
+ @swt_widget.set_size(@display.bounds.width, @display.bounds.height)
79
+ end
78
80
  Thread.new do
79
81
  sleep(0.25)
80
82
  shell_swt_display.async_exec do
@@ -48,5 +48,6 @@ module Glimmer
48
48
  end
49
49
  end
50
50
  end
51
+ CTabFolderProxy = TabFolderProxy
51
52
  end
52
53
  end
@@ -39,44 +39,40 @@ module Glimmer
39
39
  #
40
40
  # Follows the Proxy Design Pattern
41
41
  class TabItemProxy < WidgetProxy
42
- ATTRIBUTES = %w[text image]
42
+ ATTRIBUTES = %w[text image tool_tip_text]
43
43
  include_package 'org.eclipse.swt.widgets'
44
44
 
45
45
  attr_reader :widget_proxy, :swt_tab_item
46
46
 
47
47
  def initialize(parent, style, &contents)
48
48
  super("composite", parent, style, &contents)
49
- @widget_proxy = SWT::WidgetProxy.new('tab_item', parent, style)
49
+ keyword = self.class.name.split('::').last.underscore.sub('_proxy', '')
50
+ @widget_proxy = SWT::WidgetProxy.new(keyword, parent, style)
50
51
  @swt_tab_item = @widget_proxy.swt_widget
51
52
  @swt_tab_item.control = swt_widget
52
- # parent.pack # TODO auto fix the tab folder to avoid having to do this manually (including maintaining bounds and minimum size of shell)
53
+ end
54
+
55
+ def attributes
56
+ ATTRIBUTES
53
57
  end
54
58
 
55
59
  def has_attribute?(attribute_name, *args)
56
- if ATTRIBUTES.include?(attribute_name.to_s)
57
- true
58
- else
59
- super(attribute_name, *args)
60
- end
60
+ attributes.include?(attribute_name.to_s) || super(attribute_name, *args)
61
61
  end
62
62
 
63
63
  def set_attribute(attribute_name, *args)
64
- attribute_name
65
- if attribute_name.to_s == "text"
66
- text_value = args[0]
67
- @swt_tab_item.setText text_value
68
- elsif attribute_name.to_s == "image"
69
- widget_proxy.set_attribute('image', *args)
64
+ attribute_name = attribute_name.to_s
65
+ if attributes.include?(attribute_name)
66
+ widget_proxy.set_attribute(attribute_name, *args)
70
67
  else
71
68
  super(attribute_name, *args)
72
69
  end
73
70
  end
74
71
 
75
72
  def get_attribute(attribute_name)
76
- if attribute_name.to_s == "text"
77
- @swt_tab_item.getText
78
- elsif attribute_name.to_s == "image"
79
- widget_proxy.get_attribute('image')
73
+ attribute_name = attribute_name.to_s
74
+ if attributes.include?(attribute_name)
75
+ widget_proxy.get_attribute(attribute_name)
80
76
  else
81
77
  super(attribute_name)
82
78
  end
@@ -89,6 +85,9 @@ module Glimmer
89
85
  swt_tab_item.dispose
90
86
  end
91
87
  end
88
+
92
89
  end
90
+
93
91
  end
92
+
94
93
  end
@@ -51,6 +51,7 @@ module Glimmer
51
51
  'arrow' => [:arrow],
52
52
  'button' => [:push],
53
53
  'canvas' => ([:double_buffered] unless OS.mac?),
54
+ 'ccombo' => [:border],
54
55
  'checkbox' => [:check],
55
56
  'check' => [:check],
56
57
  'drag_source' => [:drop_copy],
@@ -339,6 +340,13 @@ module Glimmer
339
340
  }
340
341
  end,
341
342
  },
343
+ Java::OrgEclipseSwtCustom::CCombo => {
344
+ :text => lambda do |observer|
345
+ on_modify_text { |modify_event|
346
+ observer.call(@swt_widget.getText)
347
+ }
348
+ end,
349
+ },
342
350
  Java::OrgEclipseSwtWidgets::Table => {
343
351
  :selection => lambda do |observer|
344
352
  on_widget_selected { |selection_event|
@@ -985,6 +993,7 @@ module Glimmer
985
993
  !!value
986
994
  end,
987
995
  foreground: color_converter,
996
+ selection_foreground: color_converter,
988
997
  link_foreground: color_converter,
989
998
  font: lambda do |value|
990
999
  if value.is_a?(Hash) || value.is_a?(FontData)
@@ -51,7 +51,7 @@ class ContactManager
51
51
  }
52
52
  text {
53
53
  layout_data :fill, :center, true, false
54
- text bind(@contact_manager_presenter, :first_name)
54
+ text <=> [@contact_manager_presenter, :first_name]
55
55
  on_key_pressed {|key_event|
56
56
  @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
57
57
  }
@@ -64,7 +64,7 @@ class ContactManager
64
64
  }
65
65
  text {
66
66
  layout_data :fill, :center, true, false
67
- text bind(@contact_manager_presenter, :last_name)
67
+ text <=> [@contact_manager_presenter, :last_name]
68
68
  on_key_pressed {|key_event|
69
69
  @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
70
70
  }
@@ -77,7 +77,7 @@ class ContactManager
77
77
  }
78
78
  text {
79
79
  layout_data :fill, :center, true, false
80
- text bind(@contact_manager_presenter, :email)
80
+ text <=> [@contact_manager_presenter, :email]
81
81
  on_key_pressed {|key_event|
82
82
  @contact_manager_presenter.find if key_event.keyCode == swt(:cr)
83
83
  }
@@ -118,6 +118,7 @@ class ContactManager
118
118
  grab_excess_vertical_space true
119
119
  height_hint 200
120
120
  }
121
+
121
122
  table_column {
122
123
  text "First Name"
123
124
  width 80
@@ -130,8 +131,9 @@ class ContactManager
130
131
  text "Email"
131
132
  width 200
132
133
  }
133
- items bind(@contact_manager_presenter, :results),
134
- column_properties(:first_name, :last_name, :email)
134
+
135
+ items bind(@contact_manager_presenter, :results), column_properties(:first_name, :last_name, :email)
136
+
135
137
  on_mouse_up { |event|
136
138
  table_proxy.edit_table_item(event.table_item, event.column_index)
137
139
  }
@@ -82,8 +82,8 @@ class Login
82
82
 
83
83
  label { text "Username:" } # goes in column 1
84
84
  @user_name_text = text { # goes in column 2
85
- text bind(@presenter, :user_name)
86
- enabled bind(@presenter, :logged_out)
85
+ text <=> [@presenter, :user_name]
86
+ enabled <= [@presenter, :logged_out]
87
87
  on_key_pressed { |event|
88
88
  @password_text.set_focus if event.keyCode == swt(:cr)
89
89
  }
@@ -91,19 +91,19 @@ class Login
91
91
 
92
92
  label { text "Password:" }
93
93
  @password_text = text(:password, :border) {
94
- text bind(@presenter, :password)
95
- enabled bind(@presenter, :logged_out)
94
+ text <=> [@presenter, :password]
95
+ enabled <= [@presenter, :logged_out]
96
96
  on_key_pressed { |event|
97
97
  @presenter.login! if event.keyCode == swt(:cr)
98
98
  }
99
99
  }
100
100
 
101
101
  label { text "Status:" }
102
- label { text bind(@presenter, :status) }
102
+ label { text <= [@presenter, :status] }
103
103
 
104
104
  button {
105
105
  text "Login"
106
- enabled bind(@presenter, :logged_out)
106
+ enabled <= [@presenter, :logged_out]
107
107
  on_widget_selected { @presenter.login! }
108
108
  on_key_pressed { |event|
109
109
  @presenter.login! if event.keyCode == swt(:cr)
@@ -112,7 +112,7 @@ class Login
112
112
 
113
113
  button {
114
114
  text "Logout"
115
- enabled bind(@presenter, :logged_in)
115
+ enabled <= [@presenter, :logged_in]
116
116
  on_widget_selected { @presenter.logout! }
117
117
  on_key_pressed { |event|
118
118
  if event.keyCode == swt(:cr)
@@ -56,7 +56,7 @@ class Mandelbrot
56
56
  end
57
57
 
58
58
  def processor_count
59
- @processor_count ||= Concurrent.physical_processor_count
59
+ @processor_count ||= Concurrent.processor_count
60
60
  end
61
61
  end
62
62
 
@@ -103,7 +103,7 @@ class Mandelbrot
103
103
  puts "Points calculated already. Returning previously calculated points..."
104
104
  return @points
105
105
  end
106
- thread_pool = Concurrent::FixedThreadPool.new(Mandelbrot.processor_count, fallback_policy: :discard)
106
+ @thread_pool = Concurrent::FixedThreadPool.new(Mandelbrot.processor_count, fallback_policy: :discard)
107
107
  @points = Concurrent::Array.new(height)
108
108
  Mandelbrot.work_in_progress = "Calculating Mandelbrot Points for Zoom #{zoom}x"
109
109
  Mandelbrot.progress = 0
@@ -112,15 +112,15 @@ class Mandelbrot
112
112
  height.times do |y|
113
113
  @points[y] ||= Concurrent::Array.new(width)
114
114
  width.times do |x|
115
- thread_pool.post do
115
+ @thread_pool.post do
116
116
  @points[y][x] = calculate(x_array[x], y_array[y]).last
117
117
  point_index += 1
118
118
  Mandelbrot.progress += 1 if (point_index.to_f / point_count.to_f)*PROGRESS_MAX >= Mandelbrot.progress
119
119
  end
120
120
  end
121
121
  end
122
- thread_pool.shutdown
123
- thread_pool.wait_for_termination
122
+ @thread_pool.shutdown
123
+ @thread_pool.wait_for_termination
124
124
  Mandelbrot.progress = PROGRESS_MAX
125
125
  @points_calculated = true
126
126
  @points
@@ -164,7 +164,7 @@ class MandelbrotFractal
164
164
  }
165
165
  # pre-calculate zoomed mandelbrot images even before the user zooms in
166
166
  puts 'Starting background calculation thread...'
167
- Thread.new {
167
+ @thread = Thread.new {
168
168
  future_zoom = 1.5
169
169
  loop {
170
170
  puts "Creating mandelbrot for background calculation at zoom: #{future_zoom}"
@@ -180,16 +180,21 @@ class MandelbrotFractal
180
180
  body {
181
181
  shell(:no_resize) {
182
182
  grid_layout
183
- text bind(self, :mandelbrot_shell_title)
183
+ text <= [self, :mandelbrot_shell_title]
184
184
  minimum_size mandelbrot.width + 29, mandelbrot.height + 77
185
185
  image @mandelbrot_image
186
+
187
+ on_shell_closed {
188
+ @thread.kill # should not be dangerous in this case
189
+ puts "Mandelbrot background calculation stopped!"
190
+ }
186
191
 
187
192
  progress_bar {
188
193
  layout_data :fill, :center, true, false
189
194
 
190
195
  minimum 0
191
196
  maximum Mandelbrot::PROGRESS_MAX
192
- selection bind(Mandelbrot, :progress)
197
+ selection <= [Mandelbrot, :progress]
193
198
  }
194
199
 
195
200
  @scrolled_composite = scrolled_composite {