glimmer-dsl-swt 4.17.4.1 → 4.17.8.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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -3
  3. data/README.md +267 -107
  4. data/VERSION +1 -1
  5. data/glimmer-dsl-swt.gemspec +24 -5
  6. data/lib/glimmer/data_binding/tree_items_binding.rb +20 -2
  7. data/lib/glimmer/dsl/swt/checkbox_group_selection_data_binding_expression.rb +61 -0
  8. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +2 -0
  9. data/lib/glimmer/dsl/swt/dialog_expression.rb +1 -0
  10. data/lib/glimmer/dsl/swt/directory_dialog_expression.rb +48 -0
  11. data/lib/glimmer/dsl/swt/dsl.rb +2 -0
  12. data/lib/glimmer/dsl/swt/expand_item_expression.rb +60 -0
  13. data/lib/glimmer/dsl/swt/file_dialog_expression.rb +48 -0
  14. data/lib/glimmer/dsl/swt/radio_group_selection_data_binding_expression.rb +61 -0
  15. data/lib/glimmer/dsl/swt/shell_expression.rb +4 -4
  16. data/lib/glimmer/dsl/swt/widget_expression.rb +9 -8
  17. data/lib/glimmer/swt/custom/checkbox_group.rb +160 -0
  18. data/lib/glimmer/swt/custom/code_text.rb +25 -18
  19. data/lib/glimmer/swt/custom/radio_group.rb +155 -0
  20. data/lib/glimmer/swt/directory_dialog_proxy.rb +65 -0
  21. data/lib/glimmer/swt/expand_item_proxy.rb +97 -0
  22. data/lib/glimmer/swt/file_dialog_proxy.rb +66 -0
  23. data/lib/glimmer/swt/image_proxy.rb +5 -0
  24. data/lib/glimmer/swt/menu_proxy.rb +5 -5
  25. data/lib/glimmer/swt/sash_form_proxy.rb +1 -1
  26. data/lib/glimmer/swt/shell_proxy.rb +6 -6
  27. data/lib/glimmer/swt/styled_text_proxy.rb +43 -0
  28. data/lib/glimmer/swt/tab_item_proxy.rb +1 -1
  29. data/lib/glimmer/swt/widget_proxy.rb +86 -82
  30. data/lib/glimmer/ui/custom_shell.rb +4 -4
  31. data/lib/glimmer/ui/custom_widget.rb +3 -0
  32. data/samples/elaborate/meta_sample.rb +36 -31
  33. data/samples/hello/hello_checkbox.rb +85 -0
  34. data/samples/hello/hello_checkbox_group.rb +68 -0
  35. data/samples/hello/hello_combo.rb +12 -12
  36. data/samples/hello/hello_directory_dialog.rb +60 -0
  37. data/samples/hello/hello_expand_bar.rb +110 -0
  38. data/samples/hello/hello_file_dialog.rb +60 -0
  39. data/samples/hello/hello_list_multi_selection.rb +23 -23
  40. data/samples/hello/hello_list_single_selection.rb +18 -17
  41. data/samples/hello/hello_radio.rb +108 -0
  42. data/samples/hello/hello_radio_group.rb +84 -0
  43. data/samples/hello/hello_styled_text.rb +138 -0
  44. data/samples/hello/hello_world.rb +4 -4
  45. metadata +23 -4
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2007-2020 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
@@ -43,4 +43,4 @@ module Glimmer
43
43
  end
44
44
  end
45
45
  end
46
- end
46
+ end
@@ -1,5 +1,5 @@
1
1
  # Copyright (c) 2007-2020 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
@@ -28,24 +28,24 @@ module Glimmer
28
28
  module SWT
29
29
  class WidgetExpression < Expression
30
30
  include ParentExpression
31
-
31
+
32
32
  EXCLUDED_KEYWORDS = %w[shell display tab_item]
33
-
33
+
34
34
  def can_interpret?(parent, keyword, *args, &block)
35
35
  !EXCLUDED_KEYWORDS.include?(keyword) and
36
36
  parent.respond_to?(:swt_widget) and #TODO change to composite?(parent)
37
37
  Glimmer::SWT::WidgetProxy.widget_exists?(keyword)
38
38
  end
39
-
39
+
40
40
  def interpret(parent, keyword, *args, &block)
41
41
  Glimmer::SWT::WidgetProxy.create(keyword, parent, args)
42
42
  end
43
-
43
+
44
44
  def add_content(parent, &block)
45
45
  super
46
46
  parent.post_add_content
47
47
  end
48
-
48
+
49
49
  end
50
50
  end
51
51
  end
@@ -57,3 +57,4 @@ require 'glimmer/swt/tree_proxy'
57
57
  require 'glimmer/swt/table_proxy'
58
58
  require 'glimmer/swt/table_column_proxy'
59
59
  require 'glimmer/swt/sash_form_proxy'
60
+ require 'glimmer/swt/styled_text_proxy'
@@ -0,0 +1,160 @@
1
+ require 'glimmer/ui/custom_widget'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ module Custom
6
+ # CodeText is a customization of StyledText with support for Ruby Syntax Highlighting
7
+ class CheckboxGroup
8
+ include Glimmer::UI::CustomWidget
9
+
10
+ body {
11
+ composite # just an empty composite to hold checkboxs upon data-binding `selection`
12
+ }
13
+
14
+ def items=(text_array)
15
+ selection_value = selection
16
+ @items = Array[*text_array]
17
+ build_checkboxes
18
+ end
19
+
20
+ def items
21
+ @items || []
22
+ end
23
+
24
+ def selection=(selection_texts)
25
+ items.count.times do |index|
26
+ checkbox = checkboxes[index]
27
+ item = items[index]
28
+ label_text = labels[index]&.text
29
+ checkbox.selection = selection_texts.to_a.include?(label_text)
30
+ end
31
+ selection_texts
32
+ end
33
+
34
+ def selection
35
+ selection_indices.map do |selection_index|
36
+ labels[selection_index]&.text
37
+ end
38
+ end
39
+
40
+ def selection_indices=(indices)
41
+ self.selection=(indices.to_a.map {|index| items[index]})
42
+ end
43
+ alias select selection_indices=
44
+
45
+ def selection_indices
46
+ checkboxes.each_with_index.map do |checkbox, index|
47
+ index if checkbox.selection
48
+ end.to_a.compact
49
+ end
50
+
51
+ def checkboxes
52
+ @checkboxes ||= []
53
+ end
54
+ alias checks checkboxes
55
+
56
+ def labels
57
+ @labels ||= []
58
+ end
59
+
60
+ def can_handle_observation_request?(observation_request)
61
+ checkboxes.first&.can_handle_observation_request?(observation_request) || super(observation_request)
62
+ end
63
+
64
+ def handle_observation_request(observation_request, &block)
65
+ observation_requests << [observation_request, block]
66
+ delegate_observation_request_to_checkboxes(observation_request, &block)
67
+ super
68
+ end
69
+
70
+ def delegate_observation_request_to_checkboxes(observation_request, &block)
71
+ if observation_request != 'on_widget_disposed'
72
+ checkboxes.count.times do |index|
73
+ checkbox = checkboxes[index]
74
+ label = labels[index]
75
+ listener_block = lambda do |event|
76
+ event.widget = self.swt_widget
77
+ block.call(event)
78
+ end
79
+ if observation_request == 'on_widget_selected'
80
+ checkbox.handle_observation_request(observation_request, &listener_block) if checkbox.can_handle_observation_request?(observation_request)
81
+ label.handle_observation_request('on_mouse_up', &listener_block)
82
+ else
83
+ checkbox.handle_observation_request(observation_request, &listener_block) if checkbox.can_handle_observation_request?(observation_request)
84
+ label.handle_observation_request(observation_request, &listener_block) if label.can_handle_observation_request?(observation_request)
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ def observation_requests
91
+ @observation_requests ||= Set.new
92
+ end
93
+
94
+ def has_attribute?(attribute_name, *args)
95
+ (@composites.to_a + @checkboxes.to_a + @labels.to_a).map do |widget_proxy|
96
+ return true if widget_proxy.has_attribute?(attribute_name, *args)
97
+ end
98
+ super
99
+ end
100
+
101
+ def set_attribute(attribute_name, *args)
102
+ excluded_attributes = ['selection']
103
+ unless excluded_attributes.include?(attribute_name.to_s)
104
+ (@composites.to_a + @checkboxes.to_a + @labels.to_a).each do |widget_proxy|
105
+ widget_proxy.set_attribute(attribute_name, *args) if widget_proxy.has_attribute?(attribute_name, *args)
106
+ end
107
+ end
108
+ super
109
+ end
110
+
111
+ private
112
+
113
+ def build_checkboxes
114
+ current_selection = selection
115
+ @composites.to_a.each(&:dispose)
116
+ @checkboxes = []
117
+ @labels = []
118
+ @composites = []
119
+ items.each do |item|
120
+ body_root.content {
121
+ @composites << composite {
122
+ grid_layout(2, false) {
123
+ margin_width 0
124
+ margin_height 0
125
+ horizontal_spacing 0
126
+ vertical_spacing 0
127
+ }
128
+ checkboxes << checkbox { |checkbox_proxy|
129
+ on_widget_selected {
130
+ self.selection_indices = checkboxes.each_with_index.map {|cb, i| i if cb.selection}.to_a.compact
131
+ }
132
+ }
133
+ labels << label { |label_proxy|
134
+ layout_data :fill, :center, true, false
135
+ text item
136
+ on_mouse_up { |event|
137
+ found_text = labels.each_with_index.detect {|l, i| event.widget == l.swt_widget}[0]&.text
138
+ selection_values = self.selection
139
+ if selection_values.include?(found_text)
140
+ selection_values.delete(found_text)
141
+ else
142
+ selection_values << found_text
143
+ end
144
+ self.selection = selection_values
145
+ }
146
+ }
147
+ }
148
+ }
149
+ end
150
+ observation_requests.to_a.each do |observation_request, block|
151
+ delegate_observation_request_to_checkboxes(observation_request, &block)
152
+ end
153
+ self.selection = current_selection
154
+ end
155
+ end
156
+
157
+ CheckGroup = CheckboxGroup
158
+ end
159
+ end
160
+ end
@@ -40,21 +40,20 @@ module Glimmer
40
40
 
41
41
  def syntax_highlighting
42
42
  return [] if text.to_s.strip.empty?
43
- code = text
44
- return @syntax_highlighting if @last_code == code
45
- @last_code = code
46
- lexer = Rouge::Lexer.find_fancy('ruby', code)
47
- lex = lexer.lex(code).to_a
48
- code_size = 0
43
+ return @syntax_highlighting if already_syntax_highlighted?
44
+ @last_text = text
45
+ @lexer ||= Rouge::Lexer.find_fancy('ruby', text)
46
+ lex = @lexer.lex(text).to_a
47
+ text_size = 0
49
48
  lex_hashes = lex.map do |pair|
50
49
  {token_type: pair.first, token_text: pair.last}
51
50
  end.each do |hash|
52
- hash[:token_index] = code_size
53
- code_size += hash[:token_text].size
51
+ hash[:token_index] = text_size
52
+ text_size += hash[:token_text].size
54
53
  end
55
- code_lines = code.split("\n")
54
+ text_lines = text.split("\n")
56
55
  line_index = 0
57
- @syntax_highlighting = code_lines_map = code_lines.reduce({}) do |hash, line|
56
+ @syntax_highlighting = text_lines_map = text_lines.reduce({}) do |hash, line|
58
57
  line_hashes = []
59
58
  line_hashes << lex_hashes.shift while lex_hashes.any? && lex_hashes.first[:token_index].between?(line_index, line_index + line.size)
60
59
  hash.merge(line_index => line_hashes).tap do
@@ -63,6 +62,10 @@ module Glimmer
63
62
  end
64
63
  end
65
64
 
65
+ def already_syntax_highlighted?
66
+ @last_text == text
67
+ end
68
+
66
69
  before_body {
67
70
  @swt_style = swt_style == 0 ? [:border, :multi, :v_scroll, :h_scroll] : swt_style
68
71
  }
@@ -77,15 +80,19 @@ module Glimmer
77
80
  bottom_margin 5
78
81
 
79
82
  on_line_get_style { |line_style_event|
80
- styles = []
81
- syntax_highlighting[line_style_event.lineOffset].to_a.each do |token_hash|
82
- start_index = token_hash[:token_index]
83
- size = token_hash[:token_text].size
84
- token_color = SYNTAX_COLOR_MAP[token_hash[:token_type].name] || [:black]
85
- token_color = color(*token_color).swt_color
86
- styles << StyleRange.new(start_index, size, token_color, nil)
83
+ @styles = {} unless already_syntax_highlighted?
84
+ if @styles[line_style_event.lineOffset].nil?
85
+ styles = []
86
+ syntax_highlighting[line_style_event.lineOffset].to_a.each do |token_hash|
87
+ start_index = token_hash[:token_index]
88
+ size = token_hash[:token_text].size
89
+ token_color = SYNTAX_COLOR_MAP[token_hash[:token_type].name] || [:black]
90
+ token_color = color(*token_color).swt_color
91
+ styles << StyleRange.new(start_index, size, token_color, nil)
92
+ end
93
+ @styles[line_style_event.lineOffset] = styles.to_java(StyleRange)
87
94
  end
88
- line_style_event.styles = styles.to_java(StyleRange) unless styles.empty?
95
+ line_style_event.styles = @styles[line_style_event.lineOffset] unless @styles[line_style_event.lineOffset].empty?
89
96
  }
90
97
  }
91
98
  }
@@ -0,0 +1,155 @@
1
+ require 'glimmer/ui/custom_widget'
2
+
3
+ module Glimmer
4
+ module SWT
5
+ module Custom
6
+ # CodeText is a customization of StyledText with support for Ruby Syntax Highlighting
7
+ class RadioGroup
8
+ include Glimmer::UI::CustomWidget
9
+
10
+ body {
11
+ composite # just an empty composite to hold radios upon data-binding `selection`
12
+ }
13
+
14
+ def items=(text_array)
15
+ selection_value = selection
16
+ @items = Array[*text_array]
17
+ build_radios
18
+ end
19
+
20
+ def items
21
+ @items || []
22
+ end
23
+
24
+ def selection=(text)
25
+ radios.count.times do |index|
26
+ radio = radios[index]
27
+ item = items[index]
28
+ radio.selection = item == text
29
+ end
30
+ end
31
+
32
+ def selection
33
+ selection_value = labels[selection_index]&.text unless selection_index == -1
34
+ selection_value.to_s
35
+ end
36
+
37
+ def selection_index=(index)
38
+ self.selection=(items[index])
39
+ end
40
+ alias select selection_index=
41
+
42
+ def selection_index
43
+ radios.index(radios.detect(&:selection)) || -1
44
+ end
45
+
46
+ def radios
47
+ @radios ||= []
48
+ end
49
+
50
+ def labels
51
+ @labels ||= []
52
+ end
53
+
54
+ def can_handle_observation_request?(observation_request)
55
+ radios.first&.can_handle_observation_request?(observation_request) || super(observation_request)
56
+ end
57
+
58
+ def handle_observation_request(observation_request, &block)
59
+ observation_requests << [observation_request, block]
60
+ delegate_observation_request_to_radios(observation_request, &block)
61
+ super
62
+ end
63
+
64
+ def delegate_observation_request_to_radios(observation_request, &block)
65
+ if observation_request != 'on_widget_disposed'
66
+ radios.count.times do |index|
67
+ radio = radios[index]
68
+ label = labels[index]
69
+ if observation_request == 'on_widget_selected'
70
+ radio_block = lambda do |event|
71
+ if event.widget.selection || selection_index == -1
72
+ event.widget = self.swt_widget
73
+ block.call(event)
74
+ end
75
+ end
76
+ label_block = lambda do |event|
77
+ self.selection_index = index
78
+ block.call(event)
79
+ end
80
+ radio.handle_observation_request(observation_request, &radio_block) if radio.can_handle_observation_request?(observation_request)
81
+ label.handle_observation_request('on_mouse_up', &label_block)
82
+ else
83
+ listener_block = lambda do |event|
84
+ event.widget = self.swt_widget
85
+ block.call(event)
86
+ end
87
+ radio.handle_observation_request(observation_request, &listener_block) if radio.can_handle_observation_request?(observation_request)
88
+ label.handle_observation_request(observation_request, &listener_block) if label.can_handle_observation_request?(observation_request)
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ def observation_requests
95
+ @observation_requests ||= Set.new
96
+ end
97
+
98
+ def has_attribute?(attribute_name, *args)
99
+ (@composites.to_a + @radios.to_a + @labels.to_a).map do |widget_proxy|
100
+ return true if widget_proxy.has_attribute?(attribute_name, *args)
101
+ end
102
+ super
103
+ end
104
+
105
+ def set_attribute(attribute_name, *args)
106
+ excluded_attributes = ['selection']
107
+ unless excluded_attributes.include?(attribute_name.to_s)
108
+ (@composites.to_a + @radios.to_a + @labels.to_a).each do |widget_proxy|
109
+ widget_proxy.set_attribute(attribute_name, *args) if widget_proxy.has_attribute?(attribute_name, *args)
110
+ end
111
+ end
112
+ super
113
+ end
114
+
115
+ private
116
+
117
+ def build_radios
118
+ current_selection = selection
119
+ @composites.to_a.each(&:dispose)
120
+ @radios = []
121
+ @labels = []
122
+ @composites = []
123
+ items.each do |item|
124
+ body_root.content {
125
+ @composites << composite {
126
+ grid_layout(2, false) {
127
+ margin_width 0
128
+ margin_height 0
129
+ horizontal_spacing 0
130
+ vertical_spacing 0
131
+ }
132
+ radios << radio { |radio_proxy|
133
+ on_widget_selected {
134
+ self.selection = items[radios.index(radio_proxy)]
135
+ }
136
+ }
137
+ labels << label { |label_proxy|
138
+ layout_data :fill, :center, true, false
139
+ text item
140
+ on_mouse_up {
141
+ self.selection = label_proxy.text
142
+ }
143
+ }
144
+ }
145
+ }
146
+ end
147
+ observation_requests.to_a.each do |observation_request, block|
148
+ delegate_observation_request_to_radios(observation_request, &block)
149
+ end
150
+ self.selection = current_selection
151
+ end
152
+ end
153
+ end
154
+ end
155
+ end