glimmer-dsl-swt 4.18.4.8 → 4.18.5.1

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +70 -0
  3. data/README.md +24 -11
  4. data/VERSION +1 -1
  5. data/bin/glimmer +3 -3
  6. data/docs/reference/GLIMMER_CONFIGURATION.md +7 -3
  7. data/docs/reference/GLIMMER_GUI_DSL_SYNTAX.md +353 -145
  8. data/docs/reference/GLIMMER_SAMPLES.md +207 -41
  9. data/glimmer-dsl-swt.gemspec +33 -15
  10. data/lib/ext/glimmer/config.rb +3 -7
  11. data/lib/glimmer/data_binding/list_selection_binding.rb +13 -7
  12. data/lib/glimmer/data_binding/table_items_binding.rb +22 -17
  13. data/lib/glimmer/data_binding/tree_items_binding.rb +19 -15
  14. data/lib/glimmer/data_binding/widget_binding.rb +13 -15
  15. data/lib/glimmer/dsl/swt/{file_dialog_expression.rb → auto_exec_expression.rb} +6 -18
  16. data/lib/glimmer/dsl/swt/checkbox_group_selection_data_binding_expression.rb +9 -6
  17. data/lib/glimmer/dsl/swt/color_expression.rb +1 -1
  18. data/lib/glimmer/dsl/swt/combo_selection_data_binding_expression.rb +16 -14
  19. data/lib/glimmer/dsl/swt/custom_widget_expression.rb +4 -1
  20. data/lib/glimmer/dsl/swt/data_binding_expression.rb +2 -2
  21. data/lib/glimmer/dsl/swt/dialog_expression.rb +18 -9
  22. data/lib/glimmer/dsl/swt/dsl.rb +1 -0
  23. data/lib/glimmer/dsl/swt/exec_expression.rb +1 -1
  24. data/lib/glimmer/dsl/swt/font_expression.rb +1 -1
  25. data/lib/glimmer/dsl/swt/image_expression.rb +18 -3
  26. data/lib/glimmer/dsl/swt/list_selection_data_binding_expression.rb +11 -8
  27. data/lib/glimmer/dsl/swt/pixel_expression.rb +1 -1
  28. data/lib/glimmer/dsl/swt/radio_group_selection_data_binding_expression.rb +9 -5
  29. data/lib/glimmer/dsl/swt/shape_expression.rb +1 -1
  30. data/lib/glimmer/dsl/swt/shell_expression.rb +5 -2
  31. data/lib/glimmer/dsl/swt/widget_expression.rb +8 -4
  32. data/lib/glimmer/launcher.rb +3 -0
  33. data/lib/glimmer/rake_task/scaffold.rb +3 -0
  34. data/lib/glimmer/swt/color_proxy.rb +1 -1
  35. data/lib/glimmer/swt/custom/code_text.rb +33 -11
  36. data/lib/glimmer/swt/custom/drawable.rb +50 -2
  37. data/lib/glimmer/swt/custom/radio_group.rb +2 -1
  38. data/lib/glimmer/swt/custom/shape.rb +166 -34
  39. data/lib/glimmer/{dsl/swt/directory_dialog_expression.rb → swt/custom/shape/arc.rb} +15 -20
  40. data/lib/glimmer/swt/custom/shape/focus.rb +43 -0
  41. data/lib/glimmer/swt/custom/shape/image.rb +86 -0
  42. data/lib/glimmer/swt/custom/shape/line.rb +58 -0
  43. data/lib/glimmer/swt/custom/shape/oval.rb +43 -0
  44. data/lib/glimmer/swt/custom/shape/point.rb +52 -0
  45. data/lib/glimmer/swt/custom/shape/polygon.rb +73 -0
  46. data/lib/glimmer/swt/custom/shape/polyline.rb +73 -0
  47. data/lib/glimmer/swt/custom/shape/rectangle.rb +87 -0
  48. data/lib/glimmer/swt/custom/shape/text.rb +73 -0
  49. data/lib/glimmer/swt/date_time_proxy.rb +9 -3
  50. data/lib/glimmer/swt/dialog_proxy.rb +92 -0
  51. data/lib/glimmer/swt/display_proxy.rb +62 -2
  52. data/lib/glimmer/swt/expand_item_proxy.rb +18 -12
  53. data/lib/glimmer/swt/font_proxy.rb +13 -7
  54. data/lib/glimmer/swt/image_proxy.rb +16 -5
  55. data/lib/glimmer/swt/layout_data_proxy.rb +21 -15
  56. data/lib/glimmer/swt/layout_proxy.rb +19 -15
  57. data/lib/glimmer/swt/menu_proxy.rb +2 -2
  58. data/lib/glimmer/swt/message_box_proxy.rb +21 -7
  59. data/lib/glimmer/swt/properties.rb +3 -0
  60. data/lib/glimmer/swt/proxy_properties.rb +145 -0
  61. data/lib/glimmer/swt/scrolled_composite_proxy.rb +20 -7
  62. data/lib/glimmer/swt/shell_proxy.rb +96 -80
  63. data/lib/glimmer/swt/swt_proxy.rb +17 -0
  64. data/lib/glimmer/swt/tab_item_proxy.rb +6 -3
  65. data/lib/glimmer/swt/table_proxy.rb +32 -11
  66. data/lib/glimmer/swt/transform_proxy.rb +26 -38
  67. data/lib/glimmer/swt/tree_proxy.rb +11 -16
  68. data/lib/glimmer/swt/widget_listener_proxy.rb +6 -2
  69. data/lib/glimmer/swt/widget_proxy.rb +194 -137
  70. data/lib/glimmer/ui.rb +5 -0
  71. data/lib/glimmer/ui/custom_shell.rb +13 -7
  72. data/lib/glimmer/ui/custom_widget.rb +4 -5
  73. data/samples/elaborate/contact_manager.rb +7 -7
  74. data/samples/elaborate/login.rb +25 -21
  75. data/samples/elaborate/mandelbrot_fractal.rb +346 -39
  76. data/samples/elaborate/meta_sample.rb +1 -1
  77. data/samples/elaborate/tetris.rb +1 -0
  78. data/samples/elaborate/tic_tac_toe.rb +16 -14
  79. data/samples/elaborate/tic_tac_toe/board.rb +5 -5
  80. data/samples/elaborate/tic_tac_toe/cell.rb +5 -5
  81. data/samples/hello/hello_button.rb +7 -7
  82. data/samples/hello/hello_canvas.rb +145 -41
  83. data/samples/hello/hello_checkbox.rb +16 -14
  84. data/samples/hello/hello_checkbox_group.rb +11 -9
  85. data/samples/hello/hello_color_dialog.rb +66 -0
  86. data/samples/hello/hello_combo.rb +14 -12
  87. data/samples/hello/hello_computed.rb +7 -7
  88. data/samples/hello/hello_cursor.rb +58 -0
  89. data/samples/hello/hello_custom_shell.rb +17 -21
  90. data/samples/hello/hello_custom_widget.rb +4 -6
  91. data/samples/hello/hello_date_time.rb +14 -12
  92. data/samples/hello/hello_directory_dialog.rb +7 -7
  93. data/samples/hello/hello_expand_bar.rb +8 -8
  94. data/samples/hello/hello_file_dialog.rb +7 -7
  95. data/samples/hello/hello_font_dialog.rb +82 -0
  96. data/samples/hello/hello_group.rb +18 -16
  97. data/samples/hello/hello_list_multi_selection.rb +13 -11
  98. data/samples/hello/hello_list_single_selection.rb +13 -11
  99. data/samples/hello/hello_progress_bar.rb +125 -0
  100. data/samples/hello/hello_radio.rb +18 -16
  101. data/samples/hello/hello_radio_group.rb +14 -12
  102. data/samples/hello/hello_spinner.rb +7 -7
  103. data/samples/hello/hello_tab.rb +5 -5
  104. data/samples/hello/hello_table.rb +10 -5
  105. data/samples/hello/hello_tree.rb +485 -0
  106. metadata +30 -23
  107. data/lib/glimmer/swt/directory_dialog_proxy.rb +0 -65
  108. data/lib/glimmer/swt/file_dialog_proxy.rb +0 -66
@@ -27,7 +27,7 @@ class HelloRadioGroup
27
27
  attr_accessor :gender, :age_group
28
28
 
29
29
  def initialize
30
- reset
30
+ reset!
31
31
  end
32
32
 
33
33
  def gender_options
@@ -38,17 +38,19 @@ class HelloRadioGroup
38
38
  ['Child', 'Teen', 'Adult', 'Senior']
39
39
  end
40
40
 
41
- def reset
41
+ def reset!
42
42
  self.gender = nil
43
43
  self.age_group = 'Adult'
44
44
  end
45
45
  end
46
46
 
47
- include Glimmer
47
+ include Glimmer::UI::CustomShell
48
48
 
49
- def launch
50
- person = Person.new
51
-
49
+ before_body {
50
+ @person = Person.new
51
+ }
52
+
53
+ body {
52
54
  shell {
53
55
  text 'Hello, Radio Group!'
54
56
  row_layout :vertical
@@ -60,7 +62,7 @@ class HelloRadioGroup
60
62
 
61
63
  radio_group {
62
64
  row_layout :horizontal
63
- selection bind(person, :gender)
65
+ selection bind(@person, :gender)
64
66
  }
65
67
 
66
68
  label {
@@ -70,18 +72,18 @@ class HelloRadioGroup
70
72
 
71
73
  radio_group {
72
74
  row_layout :horizontal
73
- selection bind(person, :age_group)
75
+ selection bind(@person, :age_group)
74
76
  }
75
77
 
76
78
  button {
77
79
  text 'Reset'
78
80
 
79
81
  on_widget_selected do
80
- person.reset
82
+ @person.reset!
81
83
  end
82
84
  }
83
- }.open
84
- end
85
+ }
86
+ }
85
87
  end
86
88
 
87
- HelloRadioGroup.new.launch
89
+ HelloRadioGroup.launch
@@ -24,14 +24,14 @@ class HelloSpinner
24
24
  attr_accessor :donation
25
25
  end
26
26
 
27
- include Glimmer
27
+ include Glimmer::UI::CustomShell
28
28
 
29
- def initialize
29
+ before_body {
30
30
  @person = Person.new
31
31
  @person.donation = 500
32
- end
32
+ }
33
33
 
34
- def launch
34
+ body {
35
35
  shell {
36
36
  grid_layout
37
37
 
@@ -62,8 +62,8 @@ class HelloSpinner
62
62
  selection bind(@person, :donation) # selection must be set last if other properties are configured to ensure value is within bounds
63
63
  }
64
64
  }
65
- }.open
66
- end
65
+ }
66
+ }
67
67
  end
68
68
 
69
- HelloSpinner.new.launch
69
+ HelloSpinner.launch
@@ -20,9 +20,9 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  class HelloTab
23
- include Glimmer
23
+ include Glimmer::UI::CustomShell
24
24
 
25
- def launch
25
+ body {
26
26
  shell {
27
27
  text 'Hello, Tab!'
28
28
 
@@ -43,8 +43,8 @@ class HelloTab
43
43
  }
44
44
  }
45
45
  }
46
- }.open
47
- end
46
+ }
47
+ }
48
48
  end
49
49
 
50
- HelloTab.new.launch
50
+ HelloTab.launch
@@ -179,14 +179,19 @@ class HelloTable
179
179
  end
180
180
  end
181
181
 
182
- include Glimmer
182
+ include Glimmer::UI::CustomShell
183
183
 
184
- def launch
184
+ before_body {
185
+ Display.app_name = 'Hello, Table!'
186
+ }
187
+
188
+ body {
185
189
  shell {
186
190
  grid_layout
187
191
 
188
192
  text 'Hello, Table!'
189
193
  background_image File.expand_path('hello_table/baseball_park.png', __dir__)
194
+ image File.expand_path('hello_table/baseball_park.png', __dir__)
190
195
 
191
196
  label {
192
197
  layout_data :center, :center, true, false
@@ -272,8 +277,8 @@ class HelloTable
272
277
  book_selected_game
273
278
  }
274
279
  }
275
- }.open
276
- end
280
+ }
281
+ }
277
282
 
278
283
  def book_selected_game
279
284
  message_box {
@@ -283,4 +288,4 @@ class HelloTable
283
288
  end
284
289
  end
285
290
 
286
- HelloTable.new.launch
291
+ HelloTable.launch
@@ -0,0 +1,485 @@
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 HelloTree
25
+ EMPLOYEE_ATTRIBUTES = [
26
+ :first_name, :last_name, :position, :salary,
27
+ :health_insurance, :desk_location,
28
+ :sales_bonus_percentage, :merit_bonus,
29
+ :work_expense, :technology_expense, :travel_expense, :client_expense, :sponsorship_expense, :food_expense, :office_expense,
30
+ ]
31
+
32
+ EmployeeStruct ||= Struct.new(*EMPLOYEE_ATTRIBUTES, keyword_init: true)
33
+
34
+ class Employee < EmployeeStruct
35
+
36
+ NAMES_FIRST = %w[
37
+ John
38
+ Noah
39
+ Bill
40
+ James
41
+ Oliver
42
+ Bob
43
+ Laura
44
+ Stephanie
45
+ Marie
46
+ Emma
47
+ Olivia
48
+ Anna
49
+ ]
50
+
51
+ NAMES_LAST = %w[
52
+ Smith
53
+ Johnson
54
+ Williams
55
+ Brown
56
+ Jones
57
+ Harvard
58
+ Miller
59
+ Davis
60
+ Wilson
61
+ Anderson
62
+ Taylor
63
+ Magnus
64
+ ]
65
+
66
+ EMPLOYMENT_TYPE_POSITIONS = {
67
+ 'Sales' => 'Sales Person',
68
+ 'HR' => 'HR Staff',
69
+ 'Engineering' => 'Engineer',
70
+ 'Finance' => 'Accountant',
71
+ }
72
+
73
+ SENIORITY_SALARIES = {
74
+ 'Senior' => 111_111,
75
+ 'Standard' => 88_888,
76
+ 'Junior' => 55_555,
77
+ }
78
+
79
+ ALL_HEALTH_INSURANCES = [
80
+ 'Family Plan',
81
+ 'Standard Plan',
82
+ 'Minimal Plan',
83
+ ]
84
+
85
+ class << self
86
+ attr_accessor :selected_employee
87
+
88
+ def available_names
89
+ @available_names ||= NAMES_FIRST.size.times.map { |n| NAMES_FIRST.rotate(n).zip(NAMES_LAST) }.flatten(1)
90
+ end
91
+
92
+ def select_name!
93
+ available_names.shift
94
+ end
95
+
96
+ def all_desk_locations
97
+ @all_desk_locations ||= 30.times.map do |n|
98
+ floor = n + 1
99
+ [
100
+ "Floor #{floor} Sales",
101
+ "Floor #{floor} Engineering",
102
+ "Floor #{floor} HR",
103
+ "Floor #{floor} Finance",
104
+ ]
105
+ end.reduce(:+)
106
+ end
107
+
108
+ def available_desk_locations
109
+ @available_desk_locations ||= all_desk_locations.clone.reverse
110
+ end
111
+
112
+ def select_desk_location!(type)
113
+ available_desk_locations.delete(available_desk_locations.detect {|desk_location| desk_location.to_s.end_with?(type)})
114
+ end
115
+
116
+ def ceo
117
+ @ceo ||= Employee.new(
118
+ position: 'CEO',
119
+ salary: 999_999,
120
+ health_insurance: ALL_HEALTH_INSURANCES[0],
121
+ desk_location: Employee.select_desk_location!('Sales'),
122
+ ).tap do |employee|
123
+ employee.subordinates << cto
124
+ employee.subordinates << cfo
125
+ employee.subordinates << cio
126
+ end
127
+ end
128
+
129
+ def cto
130
+ @cto ||= Employee.new(
131
+ position: 'CTO',
132
+ salary: 777_777,
133
+ health_insurance: ALL_HEALTH_INSURANCES[0],
134
+ desk_location: Employee.select_desk_location!('Engineering'),
135
+ ).tap do |employee|
136
+ employee.subordinates << vp('Engineering')
137
+ end
138
+ end
139
+
140
+ def cfo
141
+ @cfo ||= Employee.new(
142
+ position: 'CFO',
143
+ salary: 777_777,
144
+ health_insurance: ALL_HEALTH_INSURANCES[0],
145
+ desk_location: Employee.select_desk_location!('Finance'),
146
+ ).tap do |employee|
147
+ employee.subordinates << vp('Finance')
148
+ end
149
+ end
150
+
151
+ def cio
152
+ @cio ||= Employee.new(
153
+ position: 'CIO',
154
+ salary: 777_777,
155
+ health_insurance: ALL_HEALTH_INSURANCES[0],
156
+ desk_location: Employee.select_desk_location!('HR'),
157
+ ).tap do |employee|
158
+ employee.subordinates << vp('Sales')
159
+ employee.subordinates << vp('HR')
160
+ end
161
+ end
162
+
163
+ def vp(type)
164
+ Employee.new(
165
+ position: "VP #{type}",
166
+ salary: 555_555,
167
+ health_insurance: ALL_HEALTH_INSURANCES[0],
168
+ desk_location: Employee.select_desk_location!(type),
169
+ ).tap do |employee|
170
+ 2.times { employee.subordinates << director(type) }
171
+ end
172
+ end
173
+
174
+ def director(type)
175
+ Employee.new(
176
+ position: "Director #{type}",
177
+ salary: 333_333,
178
+ health_insurance: ALL_HEALTH_INSURANCES.sample,
179
+ desk_location: Employee.select_desk_location!(type),
180
+ ).tap do |employee|
181
+ 3.times { employee.subordinates << manager(type) }
182
+ end
183
+ end
184
+
185
+ def manager(type)
186
+ Employee.new(
187
+ position: "Manager #{type}",
188
+ salary: 222_222,
189
+ health_insurance: ALL_HEALTH_INSURANCES.sample,
190
+ desk_location: Employee.select_desk_location!(type),
191
+ ).tap do |employee|
192
+ employee.subordinates << employee(type, 'Senior')
193
+ employee.subordinates << employee(type, 'Standard')
194
+ employee.subordinates << employee(type, 'Junior')
195
+ end
196
+ end
197
+
198
+ def employee(type, seniority)
199
+ seniority_title = seniority == 'Standard' ? '' : seniority
200
+ Employee.new(
201
+ position: "#{seniority_title} #{EMPLOYMENT_TYPE_POSITIONS[type]}",
202
+ salary: SENIORITY_SALARIES[seniority],
203
+ health_insurance: ALL_HEALTH_INSURANCES.sample,
204
+ desk_location: Employee.select_desk_location!(type),
205
+ )
206
+ end
207
+ end
208
+
209
+ def initialize(*args)
210
+ super(*args)
211
+ determine_type_from_position
212
+ if first_name.nil? || last_name.nil?
213
+ name = Employee.select_name!
214
+ self.first_name = name.first
215
+ self.last_name = name.last
216
+ end
217
+ self.sales_bonus_percentage = (rand*100).to_i if @type == 'Sales'
218
+ self.merit_bonus = (rand*99_999).to_i
219
+ [:work_expense, :technology_expense, :travel_expense, :client_expense, :sponsorship_expense, :food_expense, :office_expense].each do |attribute|
220
+ self.send("#{attribute}=", rand*9_999)
221
+ end
222
+ observer = Glimmer::DataBinding::Observer.proc {
223
+ notify_observers('to_s')
224
+ }
225
+ observer.observe(self, :first_name)
226
+ observer.observe(self, :last_name)
227
+ observer.observe(self, :position)
228
+ end
229
+
230
+ def determine_type_from_position(specified_position = nil)
231
+ specified_position ||= position
232
+ @type = EMPLOYMENT_TYPE_POSITIONS.keys.detect {|key| position.include?(key)}
233
+ @type = 'Sales' if position == 'CEO'
234
+ @type = 'Finance' if position == 'CFO'
235
+ @type = 'HR' if position == 'CIO'
236
+ @type = 'Engineering' if position == 'CTO'
237
+ end
238
+
239
+ def position_options
240
+ [
241
+ 'CEO',
242
+ 'CFO',
243
+ 'CIO',
244
+ 'CTO',
245
+ 'VP Sales',
246
+ 'VP HR',
247
+ 'VP Engineering',
248
+ 'VP Finance',
249
+ 'Sales Director',
250
+ 'HR Director',
251
+ 'Engineering Director',
252
+ 'Finance Director',
253
+ 'Sales Manager',
254
+ 'HR Manager',
255
+ 'Engineering Manager',
256
+ 'Finance Manager',
257
+ 'Senior Sales Person',
258
+ 'Sales Person',
259
+ 'Junior Sales Person',
260
+ 'Senior HR Staff',
261
+ 'HR Staff',
262
+ 'Junior HR Staff',
263
+ 'Senior Engineer',
264
+ 'Engineer',
265
+ 'Junior Engineer',
266
+ 'Senior Accountant',
267
+ 'Accountant',
268
+ 'Junior Accountant',
269
+ ]
270
+ end
271
+
272
+ def health_insurance_options
273
+ ALL_HEALTH_INSURANCES
274
+ end
275
+
276
+ def desk_location_options
277
+ Employee.all_desk_locations
278
+ end
279
+
280
+ def subordinates
281
+ @subordinates ||= []
282
+ end
283
+
284
+ def to_s
285
+ "#{first_name} #{last_name} (#{position})"
286
+ end
287
+ end
288
+
289
+ include Glimmer::UI::CustomShell
290
+
291
+ before_body {
292
+ Employee.selected_employee = Employee.ceo
293
+ }
294
+
295
+ after_body {
296
+ @tree.items.first.expanded = true
297
+ }
298
+
299
+ body {
300
+ shell {
301
+ fill_layout {
302
+ margin_width 15
303
+ margin_height 15
304
+ }
305
+ text 'Hello, Tree!'
306
+ minimum_size 900, 600
307
+
308
+ sash_form {
309
+ weights 1, 2
310
+
311
+ composite {
312
+ fill_layout {
313
+ margin_width 5
314
+ margin_height 5
315
+ }
316
+ @tree = tree {
317
+ items bind(Employee, :ceo), tree_properties(children: :subordinates, text: :to_s)
318
+ selection bind(Employee, :selected_employee)
319
+ }
320
+ }
321
+
322
+ composite {
323
+ grid_layout 2, false
324
+
325
+ label {
326
+ layout_data(:fill, :center, false, false)
327
+ text 'First Name:'
328
+ font height: 16, style: :bold
329
+ }
330
+ text {
331
+ layout_data(:fill, :center, true, false)
332
+ text bind(Employee, "selected_employee.first_name")
333
+ font height: 16
334
+ }
335
+
336
+ label {
337
+ layout_data(:fill, :center, false, false)
338
+ text 'First Name:'
339
+ font height: 16, style: :bold
340
+ }
341
+ text {
342
+ layout_data(:fill, :center, true, false)
343
+ text bind(Employee, "selected_employee.last_name")
344
+ font height: 16
345
+ }
346
+
347
+ label {
348
+ layout_data(:fill, :center, false, false)
349
+ text 'Position:'
350
+ font height: 16, style: :bold
351
+ }
352
+ combo {
353
+ layout_data(:fill, :center, true, false)
354
+ selection bind(Employee, "selected_employee.position")
355
+ font height: 16
356
+ }
357
+
358
+ label {
359
+ layout_data(:fill, :center, false, false)
360
+ text 'Salary:'
361
+ font height: 16, style: :bold
362
+ }
363
+ composite {
364
+ layout_data(:fill, :center, true, false)
365
+ row_layout {
366
+ margin_width 0
367
+ margin_height 0
368
+ }
369
+ label {
370
+ text '$'
371
+ font height: 20
372
+ }
373
+ spinner {
374
+ maximum 999_999
375
+ minimum 0
376
+ selection bind(Employee, "selected_employee.salary")
377
+ font height: 16
378
+ }
379
+ }
380
+
381
+ label {
382
+ layout_data(:fill, :center, false, false)
383
+ text 'Health Insurance:'
384
+ font height: 16, style: :bold
385
+ }
386
+ combo(:read_only) {
387
+ layout_data(:fill, :center, true, false)
388
+ selection bind(Employee, "selected_employee.health_insurance")
389
+ font height: 16
390
+ }
391
+
392
+ label {
393
+ layout_data(:fill, :center, false, false)
394
+ text 'Desk Location:'
395
+ font height: 16, style: :bold
396
+ }
397
+ combo(:read_only) {
398
+ layout_data(:fill, :center, true, false)
399
+ selection bind(Employee, "selected_employee.desk_location")
400
+ font height: 16
401
+ }
402
+
403
+ label {
404
+ layout_data(:fill, :center, false, false)
405
+ text 'Sales Bonus Percentage:'
406
+ font height: 16, style: :bold
407
+ }
408
+ composite {
409
+ layout_data(:fill, :center, true, false)
410
+ row_layout {
411
+ margin_width 0
412
+ margin_height 0
413
+ }
414
+ spinner {
415
+ maximum 100
416
+ minimum 0
417
+ selection bind(Employee, "selected_employee.sales_bonus_percentage")
418
+ font height: 16
419
+ }
420
+ label {
421
+ text '%'
422
+ font height: 20
423
+ }
424
+ }
425
+
426
+ label {
427
+ layout_data(:fill, :center, false, false)
428
+ text 'Merit Bonus:'
429
+ font height: 16, style: :bold
430
+ }
431
+ composite {
432
+ layout_data(:fill, :center, true, false)
433
+ row_layout {
434
+ margin_width 0
435
+ margin_height 0
436
+ }
437
+ label {
438
+ text '$'
439
+ font height: 20
440
+ }
441
+ spinner {
442
+ maximum 999_999
443
+ minimum 0
444
+ selection bind(Employee, "selected_employee.merit_bonus")
445
+ font height: 16
446
+ }
447
+ }
448
+
449
+ [:work_expense, :technology_expense, :travel_expense, :client_expense, :sponsorship_expense, :food_expense, :office_expense].each do |attribute|
450
+ label {
451
+ layout_data(:fill, :center, false, false)
452
+ text "#{attribute.to_s.split('_').map(&:capitalize).join(' ')}:"
453
+ font height: 16, style: :bold
454
+ }
455
+ composite {
456
+ layout_data(:fill, :center, true, false)
457
+ row_layout {
458
+ margin_width 0
459
+ margin_height 0
460
+ }
461
+ label {
462
+ text '$'
463
+ font height: 20
464
+ }
465
+ spinner {
466
+ digits 2
467
+ maximum 999_999_00
468
+ minimum 0
469
+ increment 100
470
+ selection bind(Employee, "selected_employee.#{attribute}", on_read: ->(v) {v.to_f * 100}, on_write: ->(v) {v.to_f / 100})
471
+ font height: 16
472
+ }
473
+ }
474
+ end
475
+
476
+ }
477
+
478
+ }
479
+
480
+ }
481
+
482
+ }
483
+ end
484
+
485
+ HelloTree.launch