glimmer-dsl-swt 4.18.7.3 → 4.19.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +44 -0
  3. data/README.md +126 -20
  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 +98 -32
  12. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +9 -7
  13. data/docs/reference/GLIMMER_PACKAGING_AND_DISTRIBUTION.md +7 -1
  14. data/docs/reference/GLIMMER_SAMPLES.md +25 -0
  15. data/glimmer-dsl-swt.gemspec +0 -0
  16. data/lib/glimmer-dsl-swt.rb +8 -0
  17. data/lib/glimmer/data_binding/widget_binding.rb +1 -1
  18. data/lib/glimmer/dsl/swt/c_tab_item_expression.rb +58 -0
  19. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +2 -1
  20. data/lib/glimmer/dsl/swt/tab_item_expression.rb +7 -3
  21. data/lib/glimmer/dsl/swt/widget_expression.rb +1 -1
  22. data/lib/glimmer/launcher.rb +27 -51
  23. data/lib/glimmer/rake_task.rb +37 -7
  24. data/lib/glimmer/rake_task/list.rb +8 -0
  25. data/lib/glimmer/rake_task/package.rb +7 -2
  26. data/lib/glimmer/rake_task/scaffold.rb +283 -207
  27. data/lib/glimmer/swt/c_tab_item_proxy.rb +53 -0
  28. data/lib/glimmer/swt/custom/code_text.rb +19 -3
  29. data/lib/glimmer/swt/custom/shape.rb +22 -4
  30. data/lib/glimmer/swt/image_proxy.rb +5 -1
  31. data/lib/glimmer/swt/sash_form_proxy.rb +6 -0
  32. data/lib/glimmer/swt/shell_proxy.rb +3 -1
  33. data/lib/glimmer/swt/tab_folder_proxy.rb +1 -0
  34. data/lib/glimmer/swt/tab_item_proxy.rb +17 -18
  35. data/lib/glimmer/swt/widget_proxy.rb +9 -0
  36. data/samples/elaborate/mandelbrot_fractal.rb +1 -1
  37. data/samples/elaborate/tetris.rb +1 -4
  38. data/samples/elaborate/tetris/view/bevel.rb +4 -1
  39. data/samples/elaborate/tetris/view/block.rb +1 -3
  40. data/samples/hello/hello_c_combo.rb +68 -0
  41. data/samples/hello/hello_c_tab.rb +271 -0
  42. data/samples/hello/hello_code_text.rb +141 -73
  43. data/samples/hello/hello_tab.rb +2 -0
  44. data/vendor/swt/linux/swt.jar +0 -0
  45. data/vendor/swt/mac/swt.jar +0 -0
  46. data/vendor/swt/windows/swt.jar +0 -0
  47. metadata +45 -15
@@ -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
@@ -64,14 +64,30 @@ module Glimmer
64
64
  respond_to?(method_name)
65
65
  end
66
66
 
67
+ def can_add_observer?(attribute_name)
68
+ @styled_text_proxy&.can_add_observer?(attribute_name) || super
69
+ end
70
+
71
+ def add_observer(observer, attribute_name)
72
+ if @styled_text_proxy&.can_add_observer?(attribute_name)
73
+ @styled_text_proxy.add_observer(observer, attribute_name)
74
+ else
75
+ super
76
+ end
77
+ end
78
+
67
79
  def can_handle_observation_request?(observation_request)
68
- @styled_text_proxy.can_handle_observation_request?(observation_request)
80
+ @styled_text_proxy&.can_handle_observation_request?(observation_request) || super
69
81
  rescue
70
82
  super
71
83
  end
72
-
84
+
73
85
  def handle_observation_request(observation_request, &block)
74
- @styled_text_proxy.handle_observation_request(observation_request, &block)
86
+ if @styled_text_proxy&.can_handle_observation_request?(observation_request)
87
+ @styled_text_proxy.handle_observation_request(observation_request, &block)
88
+ else
89
+ super
90
+ end
75
91
  rescue
76
92
  super
77
93
  end
@@ -94,8 +94,10 @@ module Glimmer
94
94
 
95
95
  def arg_options(args, extract: false)
96
96
  arg_options_method = extract ? :pop : :last
97
- options = args.send(arg_options_method) if args.last.is_a?(Hash)
98
- options.nil? ? {} : options.symbolize_keys
97
+ options = args.send(arg_options_method).symbolize_keys if args.last.is_a?(Hash)
98
+ # normalize :filled option as an alias to :fill
99
+ # options[:fill] = options.delete(:filled) if options&.keys&.include?(:filled)
100
+ options.nil? ? {} : options
99
101
  end
100
102
 
101
103
  def method_name(keyword, method_arg_options)
@@ -400,7 +402,7 @@ module Glimmer
400
402
  def amend_method_name_options_based_on_properties!
401
403
  @original_method_name = @method_name
402
404
  return if @name == 'point'
403
- if @name != 'text' && @name != 'string' && has_some_background? && !has_some_foreground?
405
+ if (@name != 'text' && @name != 'string' && has_some_background? && !has_some_foreground?) || (@name == 'path' && has_some_background?)
404
406
  @options[:fill] = true
405
407
  elsif !has_some_background? && has_some_foreground?
406
408
  @options[:fill] = false
@@ -474,7 +476,9 @@ module Glimmer
474
476
  # TODO consider this optimization of preconverting args (removing conversion from other methods) to reject equal args
475
477
  args = apply_property_arg_conversions(ruby_attribute_getter_name, args)
476
478
  return if @properties[ruby_attribute_getter_name] == args
479
+ new_property = !@properties.keys.include?(ruby_attribute_getter_name)
477
480
  @properties[ruby_attribute_getter_name] = args
481
+ amend_method_name_options_based_on_properties! if @content_added && new_property
478
482
  property_change = true
479
483
  end
480
484
  if @content_added && perform_redraw && !drawable.is_disposed
@@ -568,7 +572,7 @@ module Glimmer
568
572
  end
569
573
 
570
574
  def dispose(dispose_images: true, dispose_patterns: true, redraw: true)
571
- 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
572
576
  if dispose_patterns
573
577
  @background_pattern&.dispose
574
578
  @background_pattern = nil
@@ -583,6 +587,20 @@ module Glimmer
583
587
  drawable.redraw if redraw && !drawable.is_a?(ImageProxy)
584
588
  end
585
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
+
586
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)
587
605
  def container?
588
606
  @name == 'shape'
@@ -57,7 +57,7 @@ module Glimmer
57
57
  include_package 'org.eclipse.swt.widgets'
58
58
  include_package 'org.eclipse.swt.graphics'
59
59
 
60
- attr_reader :file_path, :jar_file_path, :image_data, :swt_image
60
+ attr_reader :file_path, :jar_file_path, :image_data, :swt_image, :parent_proxy, :parent
61
61
 
62
62
  # Initializes a proxy for an SWT Image object
63
63
  #
@@ -141,6 +141,10 @@ module Glimmer
141
141
  self
142
142
  end
143
143
 
144
+ def size
145
+ org.eclipse.swt.graphics.Point.new(bounds.width, bounds.height)
146
+ end
147
+
144
148
  def gc
145
149
  @gc ||= reset_gc
146
150
  end
@@ -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)
@@ -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
 
@@ -156,10 +156,7 @@ class Tetris
156
156
  color = colored ? color(([:white] + Model::Tetromino::LETTER_COLORS.values).sample) : color(:white)
157
157
  x = column * icon_block_size
158
158
  y = row * icon_block_size
159
- rectangle(x, y, icon_block_size, icon_block_size) {
160
- background color
161
- bevel(base_color: color, size: icon_block_size)
162
- }
159
+ bevel(x: x, y: y, base_color: color, size: icon_block_size)
163
160
  }
164
161
  }
165
162
  }
@@ -26,13 +26,16 @@ class Tetris
26
26
  include Glimmer::UI::CustomShape
27
27
 
28
28
  options :base_color, :size, :bevel_pixel_size
29
+ option :x, default: 0
30
+ option :y, default: 0
29
31
 
30
32
  before_body {
31
33
  self.bevel_pixel_size = 0.16*size.to_f if bevel_pixel_size.nil?
32
34
  }
33
35
 
34
36
  body {
35
- shape(0, 0, size, size) {
37
+ rectangle(x, y, size, size) {
38
+ background bind(self, :base_color)
36
39
  polygon(0, 0, size, 0, size - bevel_pixel_size, bevel_pixel_size, bevel_pixel_size, bevel_pixel_size) {
37
40
  background bind(self, :base_color) { |color_value|
38
41
  unless color_value.nil?
@@ -30,9 +30,7 @@ class Tetris
30
30
 
31
31
  body {
32
32
  canvas { |canvas_proxy|
33
- background bind(game_playfield[row][column], :color)
34
-
35
- bevel(base_color: game_playfield[row][column].color, size: block_size) {
33
+ bevel(size: block_size) {
36
34
  base_color bind(game_playfield[row][column], :color)
37
35
  }
38
36
  }
@@ -0,0 +1,68 @@
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-swt'
23
+
24
+ class HelloCCombo
25
+ class Person
26
+ attr_accessor :country, :country_options
27
+
28
+ def initialize
29
+ self.country_options = ['', 'Canada', 'US', 'Mexico']
30
+ reset_country!
31
+ end
32
+
33
+ def reset_country!
34
+ self.country = 'Canada'
35
+ end
36
+ end
37
+
38
+ include Glimmer::UI::CustomShell
39
+
40
+ before_body {
41
+ @person = Person.new
42
+ }
43
+
44
+ body {
45
+ shell {
46
+ row_layout(:vertical) {
47
+ fill true
48
+ }
49
+
50
+ text 'Hello, CCombo!'
51
+
52
+ c_combo(:read_only) {
53
+ selection bind(@person, :country) # also binds to country_options by convention
54
+ font height: 45 # unlike `combo`, `c_combo` changes height when setting the font height
55
+ }
56
+
57
+ button {
58
+ text 'Reset Selection'
59
+
60
+ on_widget_selected do
61
+ @person.reset_country!
62
+ end
63
+ }
64
+ }
65
+ }
66
+ end
67
+
68
+ HelloCCombo.launch
@@ -0,0 +1,271 @@
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-swt'
23
+
24
+ class HelloCTab
25
+ include Glimmer::UI::CustomShell
26
+
27
+ body {
28
+ shell {
29
+ row_layout
30
+ text 'Hello, C Tab!'
31
+ minimum_size 200, 200
32
+
33
+ c_tab_folder { # accepts styles: :close, :top, :bottom, :flat, :border, :single, :multi
34
+ layout_data {
35
+ width 1024
36
+ height 200
37
+ }
38
+ c_tab_item(:close) {
39
+ text 'English'
40
+ tool_tip_text 'English Greeting'
41
+ foreground :blue
42
+ selection_foreground :dark_blue
43
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
44
+ image image(30, 30) {
45
+ ### building image on the fly with Canvas Shape DSL text shape flag emoji
46
+ text('🇺🇸', 0, 0) {
47
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
48
+ }
49
+ }
50
+
51
+ label {
52
+ text 'Hello, World!'
53
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
54
+ }
55
+ }
56
+
57
+ c_tab_item(:close) {
58
+ text 'French'
59
+ tool_tip_text 'French Greeting'
60
+ foreground :blue
61
+ selection_foreground :dark_blue
62
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
63
+ image image(30, 30) {
64
+ ### building image on the fly with Canvas Shape DSL text shape flag emoji
65
+ text('🇫🇷', 0, 0) {
66
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
67
+ }
68
+ }
69
+
70
+ label {
71
+ text 'Bonjour, Univers!'
72
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
73
+ }
74
+ }
75
+
76
+ c_tab_item(:close) {
77
+ text 'Spanish'
78
+ tool_tip_text 'Spanish Greeting'
79
+ foreground :blue
80
+ selection_foreground :dark_blue
81
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
82
+ image image(30, 30) {
83
+ ### building image on the fly with Canvas Shape DSL text shape flag emoji
84
+ text('🇪🇸', 0, 0) {
85
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
86
+ }
87
+ }
88
+
89
+ label {
90
+ text 'Hola, Mundo!'
91
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
92
+ }
93
+ }
94
+
95
+ c_tab_item(:close) {
96
+ text 'German'
97
+ tool_tip_text 'German Greeting'
98
+ foreground :blue
99
+ selection_foreground :dark_blue
100
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
101
+ image image(30, 30) {
102
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
103
+ text('🇩🇪', 0, 0) {
104
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
105
+ }
106
+ }
107
+
108
+ label {
109
+ text 'Hallo, Welt!'
110
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
111
+ }
112
+ }
113
+
114
+ c_tab_item(:close) {
115
+ text 'Italian'
116
+ tool_tip_text 'Italian Greeting'
117
+ foreground :blue
118
+ selection_foreground :dark_blue
119
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
120
+ image image(30, 30) {
121
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
122
+ text('🇮🇹', 0, 0) {
123
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
124
+ }
125
+ }
126
+
127
+ label {
128
+ text 'Ciao, Mondo!'
129
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
130
+ }
131
+ }
132
+
133
+ c_tab_item(:close) {
134
+ text 'Dutch'
135
+ tool_tip_text 'Dutch Greeting'
136
+ foreground :blue
137
+ selection_foreground :dark_blue
138
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
139
+ image image(30, 30) {
140
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
141
+ text('🇳🇱', 0, 0) {
142
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
143
+ }
144
+ }
145
+
146
+ label {
147
+ text 'Hallo, Wereld!'
148
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
149
+ }
150
+ }
151
+
152
+ c_tab_item(:close) {
153
+ text 'Portuguese'
154
+ tool_tip_text 'Portuguese Greeting'
155
+ foreground :blue
156
+ selection_foreground :dark_blue
157
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
158
+ image image(30, 30) {
159
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
160
+ text('🇧🇷', 0, 0) {
161
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
162
+ }
163
+ }
164
+
165
+ label {
166
+ text 'Olá, Mundo!'
167
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
168
+ }
169
+ }
170
+
171
+ c_tab_item(:close) {
172
+ text 'Danish'
173
+ tool_tip_text 'Danish Greeting'
174
+ foreground :blue
175
+ selection_foreground :dark_blue
176
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
177
+ image image(30, 30) {
178
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
179
+ text('🇩🇰', 0, 0) {
180
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
181
+ }
182
+ }
183
+
184
+ label {
185
+ text 'Hej, Verden!'
186
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
187
+ }
188
+ }
189
+
190
+ c_tab_item(:close) {
191
+ text 'Finnish'
192
+ tool_tip_text 'Finnish Greeting'
193
+ foreground :blue
194
+ selection_foreground :dark_blue
195
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
196
+ image image(30, 30) {
197
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
198
+ text('🇫🇮', 0, 0) {
199
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
200
+ }
201
+ }
202
+
203
+ label {
204
+ text 'Hei, Maailma!'
205
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
206
+ }
207
+ }
208
+
209
+ c_tab_item(:close) {
210
+ text 'Swedish'
211
+ tool_tip_text 'Swedish Greeting'
212
+ foreground :blue
213
+ selection_foreground :dark_blue
214
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
215
+ image image(30, 30) {
216
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
217
+ text('🇸🇪', 0, 0) {
218
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
219
+ }
220
+ }
221
+
222
+ label {
223
+ text 'Hej, Världen!'
224
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
225
+ }
226
+ }
227
+
228
+ c_tab_item(:close) {
229
+ text 'Norwegian'
230
+ tool_tip_text 'Norwegian Greeting'
231
+ foreground :blue
232
+ selection_foreground :dark_blue
233
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
234
+ image image(30, 30) {
235
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
236
+ text('🇳🇴', 0, 0) {
237
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
238
+ }
239
+ }
240
+
241
+ label {
242
+ text 'Hei, Verden!'
243
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
244
+ }
245
+ }
246
+
247
+ c_tab_item(:close) {
248
+ text 'Russian'
249
+ tool_tip_text 'Russian Greeting'
250
+ foreground :blue
251
+ selection_foreground :dark_blue
252
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
253
+ image image(30, 30) {
254
+ # building image on the fly with Canvas Shape DSL text shape flag emoji
255
+ text('🇷🇺', 0, 0) {
256
+ font name: 'Times New Roman', height: 30, style: [:bold, :italic]
257
+ }
258
+ }
259
+
260
+ label {
261
+ text 'Привет, мир!'
262
+ font name: 'Times New Roman', height: 90, style: [:bold, :italic]
263
+ }
264
+ }
265
+
266
+ }
267
+ }
268
+ }
269
+ end
270
+
271
+ HelloCTab.launch