glimmer-dsl-swt 4.17.5.0 → 4.17.8.2

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -2
  3. data/README.md +250 -83
  4. data/VERSION +1 -1
  5. data/glimmer-dsl-swt.gemspec +20 -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/file_dialog_expression.rb +48 -0
  13. data/lib/glimmer/dsl/swt/radio_group_selection_data_binding_expression.rb +61 -0
  14. data/lib/glimmer/dsl/swt/shell_expression.rb +3 -3
  15. data/lib/glimmer/dsl/swt/widget_expression.rb +8 -8
  16. data/lib/glimmer/swt/custom/checkbox_group.rb +181 -0
  17. data/lib/glimmer/swt/custom/code_text.rb +39 -31
  18. data/lib/glimmer/swt/custom/radio_group.rb +176 -0
  19. data/lib/glimmer/swt/directory_dialog_proxy.rb +65 -0
  20. data/lib/glimmer/swt/expand_item_proxy.rb +0 -1
  21. data/lib/glimmer/swt/file_dialog_proxy.rb +66 -0
  22. data/lib/glimmer/swt/menu_proxy.rb +4 -4
  23. data/lib/glimmer/swt/shell_proxy.rb +5 -5
  24. data/lib/glimmer/swt/tab_item_proxy.rb +3 -3
  25. data/lib/glimmer/swt/widget_proxy.rb +27 -27
  26. data/lib/glimmer/ui/custom_shell.rb +3 -3
  27. data/lib/glimmer/ui/custom_widget.rb +3 -0
  28. data/samples/elaborate/meta_sample.rb +24 -19
  29. data/samples/hello/hello_checkbox.rb +85 -0
  30. data/samples/hello/hello_checkbox_group.rb +68 -0
  31. data/samples/hello/hello_combo.rb +12 -12
  32. data/samples/hello/hello_directory_dialog.rb +60 -0
  33. data/samples/hello/hello_expand_bar.rb +3 -1
  34. data/samples/hello/hello_file_dialog.rb +60 -0
  35. data/samples/hello/hello_group.rb +104 -0
  36. data/samples/hello/hello_list_multi_selection.rb +23 -23
  37. data/samples/hello/hello_list_single_selection.rb +18 -17
  38. data/samples/hello/hello_radio.rb +108 -0
  39. data/samples/hello/hello_radio_group.rb +84 -0
  40. data/samples/hello/hello_world.rb +3 -3
  41. metadata +19 -4
@@ -0,0 +1,181 @@
1
+ # Copyright (c) 2007-2020 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/ui/custom_widget'
23
+
24
+ module Glimmer
25
+ module SWT
26
+ module Custom
27
+ # A custom widget rendering a group of checkboxes generated via data-binding
28
+ class CheckboxGroup
29
+ include Glimmer::UI::CustomWidget
30
+
31
+ body {
32
+ composite # just an empty composite to hold checkboxs upon data-binding `selection`
33
+ }
34
+
35
+ def items=(text_array)
36
+ selection_value = selection
37
+ @items = Array[*text_array]
38
+ build_checkboxes
39
+ end
40
+
41
+ def items
42
+ @items || []
43
+ end
44
+
45
+ def selection=(selection_texts)
46
+ items.count.times do |index|
47
+ checkbox = checkboxes[index]
48
+ item = items[index]
49
+ label_text = labels[index]&.text
50
+ checkbox.selection = selection_texts.to_a.include?(label_text)
51
+ end
52
+ selection_texts
53
+ end
54
+
55
+ def selection
56
+ selection_indices.map do |selection_index|
57
+ labels[selection_index]&.text
58
+ end
59
+ end
60
+
61
+ def selection_indices=(indices)
62
+ self.selection=(indices.to_a.map {|index| items[index]})
63
+ end
64
+ alias select selection_indices=
65
+
66
+ def selection_indices
67
+ checkboxes.each_with_index.map do |checkbox, index|
68
+ index if checkbox.selection
69
+ end.to_a.compact
70
+ end
71
+
72
+ def checkboxes
73
+ @checkboxes ||= []
74
+ end
75
+ alias checks checkboxes
76
+
77
+ def labels
78
+ @labels ||= []
79
+ end
80
+
81
+ def can_handle_observation_request?(observation_request)
82
+ checkboxes.first&.can_handle_observation_request?(observation_request) || super(observation_request)
83
+ end
84
+
85
+ def handle_observation_request(observation_request, &block)
86
+ observation_requests << [observation_request, block]
87
+ delegate_observation_request_to_checkboxes(observation_request, &block)
88
+ super
89
+ end
90
+
91
+ def delegate_observation_request_to_checkboxes(observation_request, &block)
92
+ if observation_request != 'on_widget_disposed'
93
+ checkboxes.count.times do |index|
94
+ checkbox = checkboxes[index]
95
+ label = labels[index]
96
+ listener_block = lambda do |event|
97
+ event.widget = self.swt_widget
98
+ block.call(event)
99
+ end
100
+ if observation_request == 'on_widget_selected'
101
+ checkbox.handle_observation_request(observation_request, &listener_block) if checkbox.can_handle_observation_request?(observation_request)
102
+ label.handle_observation_request('on_mouse_up', &listener_block)
103
+ else
104
+ checkbox.handle_observation_request(observation_request, &listener_block) if checkbox.can_handle_observation_request?(observation_request)
105
+ label.handle_observation_request(observation_request, &listener_block) if label.can_handle_observation_request?(observation_request)
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ def observation_requests
112
+ @observation_requests ||= Set.new
113
+ end
114
+
115
+ def has_attribute?(attribute_name, *args)
116
+ (@composites.to_a + @checkboxes.to_a + @labels.to_a).map do |widget_proxy|
117
+ return true if widget_proxy.has_attribute?(attribute_name, *args)
118
+ end
119
+ super
120
+ end
121
+
122
+ def set_attribute(attribute_name, *args)
123
+ excluded_attributes = ['selection']
124
+ unless excluded_attributes.include?(attribute_name.to_s)
125
+ (@composites.to_a + @checkboxes.to_a + @labels.to_a).each do |widget_proxy|
126
+ widget_proxy.set_attribute(attribute_name, *args) if widget_proxy.has_attribute?(attribute_name, *args)
127
+ end
128
+ end
129
+ super
130
+ end
131
+
132
+ private
133
+
134
+ def build_checkboxes
135
+ current_selection = selection
136
+ @composites.to_a.each(&:dispose)
137
+ @checkboxes = []
138
+ @labels = []
139
+ @composites = []
140
+ items.each do |item|
141
+ body_root.content {
142
+ @composites << composite {
143
+ grid_layout(2, false) {
144
+ margin_width 0
145
+ margin_height 0
146
+ horizontal_spacing 0
147
+ vertical_spacing 0
148
+ }
149
+ checkboxes << checkbox { |checkbox_proxy|
150
+ on_widget_selected {
151
+ self.selection_indices = checkboxes.each_with_index.map {|cb, i| i if cb.selection}.to_a.compact
152
+ }
153
+ }
154
+ labels << label { |label_proxy|
155
+ layout_data :fill, :center, true, false
156
+ text item
157
+ on_mouse_up { |event|
158
+ found_text = labels.each_with_index.detect {|l, i| event.widget == l.swt_widget}[0]&.text
159
+ selection_values = self.selection
160
+ if selection_values.include?(found_text)
161
+ selection_values.delete(found_text)
162
+ else
163
+ selection_values << found_text
164
+ end
165
+ self.selection = selection_values
166
+ }
167
+ }
168
+ }
169
+ }
170
+ end
171
+ observation_requests.to_a.each do |observation_request, block|
172
+ delegate_observation_request_to_checkboxes(observation_request, &block)
173
+ end
174
+ self.selection = current_selection
175
+ end
176
+ end
177
+
178
+ CheckGroup = CheckboxGroup
179
+ end
180
+ end
181
+ end
@@ -8,20 +8,20 @@ module Glimmer
8
8
  include Glimmer::UI::CustomWidget
9
9
 
10
10
  SYNTAX_COLOR_MAP = {
11
- Builtin: [215,58,73],
12
- Class: [3,47,98],
13
- Constant: [0,92,197],
11
+ Builtin: [215,58,73],
12
+ Class: [3,47,98],
13
+ Constant: [0,92,197],
14
14
  Double: [0,92,197],
15
15
  Escape: [:red],
16
- Function: [:blue],
17
- Instance: [227,98,9],
18
- Integer: [:blue],
16
+ Function: [:blue],
17
+ Instance: [227,98,9],
18
+ Integer: [:blue],
19
19
  Interpol: [:blue],
20
- Keyword: [:blue],
20
+ Keyword: [:blue],
21
21
  Name: [111,66,193], #purple
22
- Operator: [:red],
22
+ Operator: [:red],
23
23
  Pseudo: [:dark_red],
24
- Punctuation: [:blue],
24
+ Punctuation: [:blue],
25
25
  Single: [106,115,125], # Also, Comments
26
26
  Symbol: [:dark_green],
27
27
  Text: [75, 75, 75],
@@ -38,29 +38,32 @@ module Glimmer
38
38
  swt_widget&.text
39
39
  end
40
40
 
41
- def syntax_highlighting
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
61
60
  line_index += line.size + 1
62
- end
63
- end
61
+ end
62
+ end
63
+ end
64
+
65
+ def already_syntax_highlighted?
66
+ @last_text == text
64
67
  end
65
68
 
66
69
  before_body {
@@ -77,16 +80,21 @@ 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 ||= {}
84
+ @styles = {} unless already_syntax_highlighted?
85
+ if @styles[line_style_event.lineOffset].nil?
86
+ styles = []
87
+ syntax_highlighting[line_style_event.lineOffset].to_a.each do |token_hash|
88
+ start_index = token_hash[:token_index]
89
+ size = token_hash[:token_text].size
90
+ token_color = SYNTAX_COLOR_MAP[token_hash[:token_type].name] || [:black]
91
+ token_color = color(*token_color).swt_color
92
+ styles << StyleRange.new(start_index, size, token_color, nil)
93
+ end
94
+ @styles[line_style_event.lineOffset] = styles.to_java(StyleRange)
87
95
  end
88
- line_style_event.styles = styles.to_java(StyleRange) unless styles.empty?
89
- }
96
+ line_style_event.styles = @styles[line_style_event.lineOffset] unless @styles[line_style_event.lineOffset].empty?
97
+ }
90
98
  }
91
99
  }
92
100
  end
@@ -0,0 +1,176 @@
1
+ # Copyright (c) 2007-2020 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/ui/custom_widget'
23
+
24
+ module Glimmer
25
+ module SWT
26
+ module Custom
27
+ # A custom widget rendering a group of radios generated via data-binding
28
+ class RadioGroup
29
+ include Glimmer::UI::CustomWidget
30
+
31
+ body {
32
+ composite # just an empty composite to hold radios upon data-binding `selection`
33
+ }
34
+
35
+ def items=(text_array)
36
+ selection_value = selection
37
+ @items = Array[*text_array]
38
+ build_radios
39
+ end
40
+
41
+ def items
42
+ @items || []
43
+ end
44
+
45
+ def selection=(text)
46
+ radios.count.times do |index|
47
+ radio = radios[index]
48
+ item = items[index]
49
+ radio.selection = item == text
50
+ end
51
+ end
52
+
53
+ def selection
54
+ selection_value = labels[selection_index]&.text unless selection_index == -1
55
+ selection_value.to_s
56
+ end
57
+
58
+ def selection_index=(index)
59
+ self.selection=(items[index])
60
+ end
61
+ alias select selection_index=
62
+
63
+ def selection_index
64
+ radios.index(radios.detect(&:selection)) || -1
65
+ end
66
+
67
+ def radios
68
+ @radios ||= []
69
+ end
70
+
71
+ def labels
72
+ @labels ||= []
73
+ end
74
+
75
+ def can_handle_observation_request?(observation_request)
76
+ radios.first&.can_handle_observation_request?(observation_request) || super(observation_request)
77
+ end
78
+
79
+ def handle_observation_request(observation_request, &block)
80
+ observation_requests << [observation_request, block]
81
+ delegate_observation_request_to_radios(observation_request, &block)
82
+ super
83
+ end
84
+
85
+ def delegate_observation_request_to_radios(observation_request, &block)
86
+ if observation_request != 'on_widget_disposed'
87
+ radios.count.times do |index|
88
+ radio = radios[index]
89
+ label = labels[index]
90
+ if observation_request == 'on_widget_selected'
91
+ radio_block = lambda do |event|
92
+ if event.widget.selection || selection_index == -1
93
+ event.widget = self.swt_widget
94
+ block.call(event)
95
+ end
96
+ end
97
+ label_block = lambda do |event|
98
+ self.selection_index = index
99
+ block.call(event)
100
+ end
101
+ radio.handle_observation_request(observation_request, &radio_block) if radio.can_handle_observation_request?(observation_request)
102
+ label.handle_observation_request('on_mouse_up', &label_block)
103
+ else
104
+ listener_block = lambda do |event|
105
+ event.widget = self.swt_widget
106
+ block.call(event)
107
+ end
108
+ radio.handle_observation_request(observation_request, &listener_block) if radio.can_handle_observation_request?(observation_request)
109
+ label.handle_observation_request(observation_request, &listener_block) if label.can_handle_observation_request?(observation_request)
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ def observation_requests
116
+ @observation_requests ||= Set.new
117
+ end
118
+
119
+ def has_attribute?(attribute_name, *args)
120
+ (@composites.to_a + @radios.to_a + @labels.to_a).map do |widget_proxy|
121
+ return true if widget_proxy.has_attribute?(attribute_name, *args)
122
+ end
123
+ super
124
+ end
125
+
126
+ def set_attribute(attribute_name, *args)
127
+ excluded_attributes = ['selection']
128
+ unless excluded_attributes.include?(attribute_name.to_s)
129
+ (@composites.to_a + @radios.to_a + @labels.to_a).each do |widget_proxy|
130
+ widget_proxy.set_attribute(attribute_name, *args) if widget_proxy.has_attribute?(attribute_name, *args)
131
+ end
132
+ end
133
+ super
134
+ end
135
+
136
+ private
137
+
138
+ def build_radios
139
+ current_selection = selection
140
+ @composites.to_a.each(&:dispose)
141
+ @radios = []
142
+ @labels = []
143
+ @composites = []
144
+ items.each do |item|
145
+ body_root.content {
146
+ @composites << composite {
147
+ grid_layout(2, false) {
148
+ margin_width 0
149
+ margin_height 0
150
+ horizontal_spacing 0
151
+ vertical_spacing 0
152
+ }
153
+ radios << radio { |radio_proxy|
154
+ on_widget_selected {
155
+ self.selection = items[radios.index(radio_proxy)]
156
+ }
157
+ }
158
+ labels << label { |label_proxy|
159
+ layout_data :fill, :center, true, false
160
+ text item
161
+ on_mouse_up {
162
+ self.selection = label_proxy.text
163
+ }
164
+ }
165
+ }
166
+ }
167
+ end
168
+ observation_requests.to_a.each do |observation_request, block|
169
+ delegate_observation_request_to_radios(observation_request, &block)
170
+ end
171
+ self.selection = current_selection
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end