glimmer-dsl-libui 0.4.2 → 0.4.6

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/README.md +1359 -200
  4. data/VERSION +1 -1
  5. data/examples/basic_entry.rb +27 -24
  6. data/examples/basic_entry2.rb +31 -0
  7. data/examples/color_button.rb +18 -13
  8. data/examples/color_button2.rb +14 -0
  9. data/examples/dynamic_area.rb +77 -90
  10. data/examples/dynamic_area2.rb +14 -12
  11. data/examples/dynamic_area3.rb +90 -0
  12. data/examples/dynamic_area4.rb +95 -0
  13. data/examples/font_button.rb +17 -12
  14. data/examples/font_button2.rb +18 -0
  15. data/examples/form.rb +42 -30
  16. data/examples/form2.rb +37 -0
  17. data/examples/form_table.rb +100 -87
  18. data/examples/form_table2.rb +93 -0
  19. data/examples/histogram.rb +93 -91
  20. data/examples/histogram2.rb +109 -0
  21. data/examples/login.rb +45 -39
  22. data/examples/login2.rb +55 -0
  23. data/examples/login3.rb +65 -0
  24. data/examples/login4.rb +61 -0
  25. data/examples/login5.rb +43 -0
  26. data/examples/meta_example.rb +9 -6
  27. data/examples/method_based_custom_keyword.rb +8 -15
  28. data/examples/method_based_custom_keyword2.rb +97 -0
  29. data/examples/timer.rb +28 -31
  30. data/examples/timer2.rb +129 -0
  31. data/glimmer-dsl-libui.gemspec +0 -0
  32. data/lib/glimmer/dsl/libui/data_binding_expression.rb +4 -6
  33. data/lib/glimmer/libui/attributed_string.rb +3 -0
  34. data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +5 -0
  35. data/lib/glimmer/libui/control_proxy/entry_proxy.rb +5 -0
  36. data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +4 -0
  37. data/lib/glimmer/libui/control_proxy/multiline_entry_proxy.rb +5 -0
  38. data/lib/glimmer/libui/control_proxy/slider_proxy.rb +38 -0
  39. data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +38 -0
  40. data/lib/glimmer/libui/control_proxy.rb +4 -0
  41. data/lib/glimmer/libui/data_bindable.rb +39 -0
  42. data/lib/glimmer/libui/shape.rb +2 -0
  43. metadata +19 -2
@@ -0,0 +1,109 @@
1
+ # https://github.com/jamescook/libui-ruby/blob/master/example/histogram.rb
2
+
3
+ require 'glimmer-dsl-libui'
4
+
5
+ include Glimmer
6
+
7
+ X_OFF_LEFT = 20
8
+ Y_OFF_TOP = 20
9
+ X_OFF_RIGHT = 20
10
+ Y_OFF_BOTTOM = 20
11
+ POINT_RADIUS = 5
12
+ COLOR_BLUE = Glimmer::LibUI.interpret_color(0x1E90FF)
13
+
14
+ @datapoints = 10.times.map {Random.new.rand(90)}
15
+ @color = COLOR_BLUE
16
+
17
+ def graph_size(area_width, area_height)
18
+ graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
19
+ graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
20
+ [graph_width, graph_height]
21
+ end
22
+
23
+ def point_locations(width, height)
24
+ xincr = width / 9.0 # 10 - 1 to make the last point be at the end
25
+ yincr = height / 100.0
26
+
27
+ @datapoints.each_with_index.map do |value, i|
28
+ val = 100 - value
29
+ [xincr * i, yincr * val]
30
+ end
31
+ end
32
+
33
+ # method-based custom control representing a graph path
34
+ def graph_path(width, height, should_extend, &block)
35
+ locations = point_locations(width, height).flatten
36
+ path {
37
+ if should_extend
38
+ polygon(locations + [width, height, 0, height])
39
+ else
40
+ polyline(locations)
41
+ end
42
+
43
+ # apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
44
+ transform {
45
+ translate X_OFF_LEFT, Y_OFF_TOP
46
+ }
47
+
48
+ block.call
49
+ }
50
+ end
51
+
52
+ window('histogram example', 640, 480) {
53
+ margined true
54
+
55
+ horizontal_box {
56
+ vertical_box {
57
+ stretchy false
58
+
59
+ 10.times do |i|
60
+ spinbox(0, 100) { |sb|
61
+ stretchy false
62
+ value @datapoints[i]
63
+
64
+ on_changed do
65
+ @datapoints[i] = sb.value
66
+ @area.queue_redraw_all
67
+ end
68
+ }
69
+ end
70
+
71
+ color_button { |cb|
72
+ stretchy false
73
+ color COLOR_BLUE
74
+
75
+ on_changed do
76
+ @color = cb.color
77
+ @area.queue_redraw_all
78
+ end
79
+ }
80
+ }
81
+
82
+ @area = area {
83
+ on_draw do |area_draw_params|
84
+ rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height]) {
85
+ fill 0xFFFFFF
86
+ }
87
+
88
+ graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
89
+
90
+ figure(X_OFF_LEFT, Y_OFF_TOP) {
91
+ line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
92
+ line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
93
+
94
+ stroke 0x000000, thickness: 2, miter_limit: 10
95
+ }
96
+
97
+ # now create the fill for the graph below the graph line
98
+ graph_path(graph_width, graph_height, true) {
99
+ fill @color.merge(a: 0.5)
100
+ }
101
+
102
+ # now draw the histogram line
103
+ graph_path(graph_width, graph_height, false) {
104
+ stroke @color.merge(thickness: 2, miter_limit: 10)
105
+ }
106
+ end
107
+ }
108
+ }
109
+ }.show
data/examples/login.rb CHANGED
@@ -1,45 +1,51 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'glimmer-dsl-libui'
4
2
 
5
- include Glimmer
6
-
7
- window('Login') {
8
- margined true
3
+ class Login
4
+ include Glimmer
9
5
 
10
- vertical_box {
11
- form {
12
- @username_entry = entry {
13
- label 'Username:'
14
- }
15
-
16
- @password_entry = password_entry {
17
- label 'Password:'
18
- }
19
- }
20
-
21
- horizontal_box {
22
- @login_button = button('Login') {
23
- on_clicked do
24
- @username_entry.enabled = false
25
- @password_entry.enabled = false
26
- @login_button.enabled = false
27
- @logout_button.enabled = true
28
- end
29
- }
6
+ attr_accessor :username, :password, :logged_in
7
+
8
+ def launch
9
+ window('Login') {
10
+ margined true
30
11
 
31
- @logout_button = button('Logout') {
32
- enabled false
12
+ vertical_box {
13
+ form {
14
+ entry {
15
+ label 'Username:'
16
+ text <=> [self, :username]
17
+ enabled <= [self, :logged_in, on_read: :!] # `on_read: :!` negates read value
18
+ }
19
+
20
+ password_entry {
21
+ label 'Password:'
22
+ text <=> [self, :password]
23
+ enabled <= [self, :logged_in, on_read: :!]
24
+ }
25
+ }
33
26
 
34
- on_clicked do
35
- @username_entry.text = ''
36
- @password_entry.text = ''
37
- @username_entry.enabled = true
38
- @password_entry.enabled = true
39
- @login_button.enabled = true
40
- @logout_button.enabled = false
41
- end
27
+ horizontal_box {
28
+ button('Login') {
29
+ enabled <= [self, :logged_in, on_read: :!]
30
+
31
+ on_clicked do
32
+ self.logged_in = true
33
+ end
34
+ }
35
+
36
+ button('Logout') {
37
+ enabled <= [self, :logged_in]
38
+
39
+ on_clicked do
40
+ self.logged_in = false
41
+ self.username = ''
42
+ self.password = ''
43
+ end
44
+ }
45
+ }
42
46
  }
43
- }
44
- }
45
- }.show
47
+ }.show
48
+ end
49
+ end
50
+
51
+ Login.new.launch
@@ -0,0 +1,55 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class Login
4
+ include Glimmer
5
+
6
+ attr_accessor :username, :password, :logged_in
7
+
8
+ def logged_out
9
+ !logged_in
10
+ end
11
+
12
+ def launch
13
+ window('Login') {
14
+ margined true
15
+
16
+ vertical_box {
17
+ form {
18
+ entry {
19
+ label 'Username:'
20
+ text <=> [self, :username]
21
+ enabled <= [self, :logged_out, computed_by: :logged_in] # computed_by option ensures being notified of changes to logged_in
22
+ }
23
+
24
+ password_entry {
25
+ label 'Password:'
26
+ text <=> [self, :password]
27
+ enabled <= [self, :logged_out, computed_by: :logged_in]
28
+ }
29
+ }
30
+
31
+ horizontal_box {
32
+ button('Login') {
33
+ enabled <= [self, :logged_out, computed_by: :logged_in]
34
+
35
+ on_clicked do
36
+ self.logged_in = true
37
+ end
38
+ }
39
+
40
+ button('Logout') {
41
+ enabled <= [self, :logged_in]
42
+
43
+ on_clicked do
44
+ self.logged_in = false
45
+ self.username = ''
46
+ self.password = ''
47
+ end
48
+ }
49
+ }
50
+ }
51
+ }.show
52
+ end
53
+ end
54
+
55
+ Login.new.launch
@@ -0,0 +1,65 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class Login
4
+ include Glimmer
5
+
6
+ attr_accessor :username, :password
7
+ attr_reader :logged_in
8
+
9
+ def logged_in=(value)
10
+ @logged_in = value
11
+ self.logged_out = !value # calling logged_out= method notifies logged_out observers
12
+ end
13
+
14
+ def logged_out=(value)
15
+ self.logged_in = !value unless logged_in == !value
16
+ end
17
+
18
+ def logged_out
19
+ !logged_in
20
+ end
21
+
22
+ def launch
23
+ window('Login') {
24
+ margined true
25
+
26
+ vertical_box {
27
+ form {
28
+ entry {
29
+ label 'Username:'
30
+ text <=> [self, :username]
31
+ enabled <= [self, :logged_out]
32
+ }
33
+
34
+ password_entry {
35
+ label 'Password:'
36
+ text <=> [self, :password]
37
+ enabled <= [self, :logged_out]
38
+ }
39
+ }
40
+
41
+ horizontal_box {
42
+ button('Login') {
43
+ enabled <= [self, :logged_out]
44
+
45
+ on_clicked do
46
+ self.logged_in = true
47
+ end
48
+ }
49
+
50
+ button('Logout') {
51
+ enabled <= [self, :logged_in]
52
+
53
+ on_clicked do
54
+ self.logged_in = false
55
+ self.username = ''
56
+ self.password = ''
57
+ end
58
+ }
59
+ }
60
+ }
61
+ }.show
62
+ end
63
+ end
64
+
65
+ Login.new.launch
@@ -0,0 +1,61 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class Login
4
+ include Glimmer
5
+
6
+ attr_accessor :username, :password
7
+ attr_reader :logged_in
8
+
9
+ def logged_in=(value)
10
+ @logged_in = value
11
+ notify_observers(:logged_out) # manually notify observers of logged_out upon logged_in changes; this method comes automatically from enhancement as Glimmer::DataBinding::ObservableModel via data-binding
12
+ end
13
+
14
+ def logged_out
15
+ !logged_in
16
+ end
17
+
18
+ def launch
19
+ window('Login') {
20
+ margined true
21
+
22
+ vertical_box {
23
+ form {
24
+ entry {
25
+ label 'Username:'
26
+ text <=> [self, :username]
27
+ enabled <= [self, :logged_out]
28
+ }
29
+
30
+ password_entry {
31
+ label 'Password:'
32
+ text <=> [self, :password]
33
+ enabled <= [self, :logged_out]
34
+ }
35
+ }
36
+
37
+ horizontal_box {
38
+ button('Login') {
39
+ enabled <= [self, :logged_out]
40
+
41
+ on_clicked do
42
+ self.logged_in = true
43
+ end
44
+ }
45
+
46
+ button('Logout') {
47
+ enabled <= [self, :logged_in]
48
+
49
+ on_clicked do
50
+ self.logged_in = false
51
+ self.username = ''
52
+ self.password = ''
53
+ end
54
+ }
55
+ }
56
+ }
57
+ }.show
58
+ end
59
+ end
60
+
61
+ Login.new.launch
@@ -0,0 +1,43 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ include Glimmer
4
+
5
+ window('Login') {
6
+ margined true
7
+
8
+ vertical_box {
9
+ form {
10
+ @username_entry = entry {
11
+ label 'Username:'
12
+ }
13
+
14
+ @password_entry = password_entry {
15
+ label 'Password:'
16
+ }
17
+ }
18
+
19
+ horizontal_box {
20
+ @login_button = button('Login') {
21
+ on_clicked do
22
+ @username_entry.enabled = false
23
+ @password_entry.enabled = false
24
+ @login_button.enabled = false
25
+ @logout_button.enabled = true
26
+ end
27
+ }
28
+
29
+ @logout_button = button('Logout') {
30
+ enabled false
31
+
32
+ on_clicked do
33
+ @username_entry.text = ''
34
+ @password_entry.text = ''
35
+ @username_entry.enabled = true
36
+ @password_entry.enabled = true
37
+ @login_button.enabled = true
38
+ @logout_button.enabled = false
39
+ end
40
+ }
41
+ }
42
+ }
43
+ }.show
@@ -7,8 +7,11 @@ class MetaExample
7
7
 
8
8
  ADDITIONAL_BASIC_EXAMPLES = ['Color Button', 'Font Button', 'Form', 'Date Time Picker', 'Simple Notepad']
9
9
 
10
+ attr_accessor :code_text
11
+
10
12
  def initialize
11
13
  @selected_example_index = examples_with_versions.index(basic_examples_with_versions.first)
14
+ @code_text = File.read(file_path_for(selected_example))
12
15
  end
13
16
 
14
17
  def examples
@@ -89,7 +92,7 @@ class MetaExample
89
92
  on_selected do
90
93
  @selected_example_index = examples_with_versions.index(basic_examples_with_versions[@basic_example_radio_buttons.selected])
91
94
  example = selected_example
92
- @code_entry.text = File.read(file_path_for(example))
95
+ self.code_text = File.read(file_path_for(example))
93
96
  @version_spinbox.value = 1
94
97
  end
95
98
  }
@@ -108,7 +111,7 @@ class MetaExample
108
111
  on_selected do
109
112
  @selected_example_index = examples_with_versions.index(advanced_examples_with_versions[@advanced_example_radio_buttons.selected])
110
113
  example = selected_example
111
- @code_entry.text = File.read(file_path_for(example))
114
+ self.code_text = File.read(file_path_for(example))
112
115
  @version_spinbox.value = 1
113
116
  end
114
117
  }
@@ -134,7 +137,7 @@ class MetaExample
134
137
  else
135
138
  version_number = @version_spinbox.value == 1 ? '' : @version_spinbox.value
136
139
  example = "#{selected_example}#{version_number}"
137
- @code_entry.text = File.read(file_path_for(example))
140
+ self.code_text = File.read(file_path_for(example))
138
141
  end
139
142
  end
140
143
  }
@@ -149,7 +152,7 @@ class MetaExample
149
152
  parent_dir = File.join(Dir.home, '.glimmer-dsl-libui', 'examples')
150
153
  FileUtils.mkdir_p(parent_dir)
151
154
  example_file = File.join(parent_dir, "#{selected_example.underscore}.rb")
152
- File.write(example_file, @code_entry.text)
155
+ File.write(example_file, code_text)
153
156
  example_supporting_directory = File.expand_path(selected_example.underscore, __dir__)
154
157
  FileUtils.cp_r(example_supporting_directory, parent_dir) if Dir.exist?(example_supporting_directory)
155
158
  FileUtils.cp_r(File.expand_path('../icons', __dir__), File.dirname(parent_dir))
@@ -164,14 +167,14 @@ class MetaExample
164
167
  }
165
168
  button('Reset') {
166
169
  on_clicked do
167
- @code_entry.text = File.read(file_path_for(selected_example))
170
+ self.code_text = File.read(file_path_for(selected_example))
168
171
  end
169
172
  }
170
173
  }
171
174
  }
172
175
 
173
176
  @code_entry = non_wrapping_multiline_entry {
174
- text File.read(file_path_for(selected_example))
177
+ text <=> [self, :code_text]
175
178
  }
176
179
  }
177
180
  }.show
@@ -5,15 +5,11 @@ include Glimmer
5
5
 
6
6
  Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
7
7
 
8
- def form_field(model, property)
9
- property = property.to_s
8
+ def form_field(model, attribute)
9
+ attribute = attribute.to_s
10
10
  entry { |e|
11
- label property.underscore.split('_').map(&:capitalize).join(' ')
12
- text model.send(property).to_s
13
-
14
- on_changed do
15
- model.send("#{property}=", e.text)
16
- end
11
+ label attribute.underscore.split('_').map(&:capitalize).join(' ')
12
+ text <=> [model, attribute]
17
13
  }
18
14
  end
19
15
 
@@ -28,15 +24,12 @@ def address_form(address)
28
24
  end
29
25
 
30
26
  def label_pair(model, attribute, value)
31
- name_label = nil
32
- value_label = nil
33
27
  horizontal_box {
34
- name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
35
- value_label = label(value.to_s)
28
+ label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
29
+ label(value.to_s) {
30
+ text <= [model, attribute]
31
+ }
36
32
  }
37
- observe(model, attribute) do
38
- value_label.text = model.send(attribute)
39
- end
40
33
  end
41
34
 
42
35
  def address(address)
@@ -0,0 +1,97 @@
1
+ require 'glimmer-dsl-libui'
2
+ require 'facets'
3
+
4
+ include Glimmer
5
+
6
+ Address = Struct.new(:street, :p_o_box, :city, :state, :zip_code)
7
+
8
+ def form_field(model, property)
9
+ property = property.to_s
10
+ entry { |e|
11
+ label property.underscore.split('_').map(&:capitalize).join(' ')
12
+ text model.send(property).to_s
13
+
14
+ on_changed do
15
+ model.send("#{property}=", e.text)
16
+ end
17
+ }
18
+ end
19
+
20
+ def address_form(address)
21
+ form {
22
+ form_field(address, :street)
23
+ form_field(address, :p_o_box)
24
+ form_field(address, :city)
25
+ form_field(address, :state)
26
+ form_field(address, :zip_code)
27
+ }
28
+ end
29
+
30
+ def label_pair(model, attribute, value)
31
+ name_label = nil
32
+ value_label = nil
33
+ horizontal_box {
34
+ name_label = label(attribute.to_s.underscore.split('_').map(&:capitalize).join(' '))
35
+ value_label = label(value.to_s)
36
+ }
37
+ observe(model, attribute) do
38
+ value_label.text = model.send(attribute)
39
+ end
40
+ end
41
+
42
+ def address(address)
43
+ vertical_box {
44
+ address.each_pair do |attribute, value|
45
+ label_pair(address, attribute, value)
46
+ end
47
+ }
48
+ end
49
+
50
+ address1 = Address.new('123 Main St', '23923', 'Denver', 'Colorado', '80014')
51
+ address2 = Address.new('2038 Park Ave', '83272', 'Boston', 'Massachusetts', '02101')
52
+
53
+ window('Method-Based Custom Keyword') {
54
+ margined true
55
+
56
+ horizontal_box {
57
+ vertical_box {
58
+ label('Address 1') {
59
+ stretchy false
60
+ }
61
+
62
+ address_form(address1)
63
+
64
+ horizontal_separator {
65
+ stretchy false
66
+ }
67
+
68
+ label('Address 1 (Saved)') {
69
+ stretchy false
70
+ }
71
+
72
+ address(address1)
73
+ }
74
+
75
+ vertical_separator {
76
+ stretchy false
77
+ }
78
+
79
+ vertical_box {
80
+ label('Address 2') {
81
+ stretchy false
82
+ }
83
+
84
+ address_form(address2)
85
+
86
+ horizontal_separator {
87
+ stretchy false
88
+ }
89
+
90
+ label('Address 2 (Saved)') {
91
+ stretchy false
92
+ }
93
+
94
+ address(address2)
95
+ }
96
+ }
97
+ }.show