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
data/examples/form.rb CHANGED
@@ -2,36 +2,48 @@
2
2
 
3
3
  require 'glimmer-dsl-libui'
4
4
 
5
- include Glimmer
6
-
7
- window('Form') {
8
- margined true
5
+ class Form
6
+ include Glimmer
9
7
 
10
- vertical_box {
11
- form {
12
- @first_name_entry = entry {
13
- label 'First Name' # label property is available when control is nested under form
14
- }
15
-
16
- @last_name_entry = entry {
17
- label 'Last Name' # label property is available when control is nested under form
18
- }
19
-
20
- @phone_entry = entry {
21
- label 'Phone' # label property is available when control is nested under form
22
- }
8
+ attr_accessor :first_name, :last_name, :phone, :email
9
+
10
+ def launch
11
+ window('Form') {
12
+ margined true
23
13
 
24
- @email_entry = entry {
25
- label 'Email' # label property is available when control is nested under form
14
+ vertical_box {
15
+ form {
16
+ entry {
17
+ label 'First Name' # label property is available when control is nested under form
18
+ text <=> [self, :first_name] # bidirectional data-binding of entry text property to self first_name attribute
19
+ }
20
+
21
+ entry {
22
+ label 'Last Name' # label property is available when control is nested under form
23
+ text <=> [self, :last_name]
24
+ }
25
+
26
+ entry {
27
+ label 'Phone' # label property is available when control is nested under form
28
+ text <=> [self, :phone]
29
+ }
30
+
31
+ entry {
32
+ label 'Email' # label property is available when control is nested under form
33
+ text <=> [self, :email]
34
+ }
35
+ }
36
+
37
+ button('Display Info') {
38
+ stretchy false
39
+
40
+ on_clicked do
41
+ msg_box('Info', "#{first_name} #{last_name} has phone #{phone} and email #{email}")
42
+ end
43
+ }
26
44
  }
27
- }
28
-
29
- button('Display Info') {
30
- stretchy false
31
-
32
- on_clicked do
33
- msg_box('Info', "#{@first_name_entry.text} #{@last_name_entry.text} has phone #{@phone_entry.text} and email #{@email_entry.text}")
34
- end
35
- }
36
- }
37
- }.show
45
+ }.show
46
+ end
47
+ end
48
+
49
+ Form.new.launch
data/examples/form2.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'glimmer-dsl-libui'
4
+
5
+ include Glimmer
6
+
7
+ window('Form') {
8
+ margined true
9
+
10
+ vertical_box {
11
+ form {
12
+ @first_name_entry = entry {
13
+ label 'First Name' # label property is available when control is nested under form
14
+ }
15
+
16
+ @last_name_entry = entry {
17
+ label 'Last Name' # label property is available when control is nested under form
18
+ }
19
+
20
+ @phone_entry = entry {
21
+ label 'Phone' # label property is available when control is nested under form
22
+ }
23
+
24
+ @email_entry = entry {
25
+ label 'Email' # label property is available when control is nested under form
26
+ }
27
+ }
28
+
29
+ button('Display Info') {
30
+ stretchy false
31
+
32
+ on_clicked do
33
+ msg_box('Info', "#{@first_name_entry.text} #{@last_name_entry.text} has phone #{@phone_entry.text} and email #{@email_entry.text}")
34
+ end
35
+ }
36
+ }
37
+ }.show
@@ -1,95 +1,108 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'glimmer-dsl-libui'
4
2
 
5
- include Glimmer
6
-
7
- data = [
8
- ['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO', '80014'],
9
- ['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA', '02101'],
10
- ['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL', '60007'],
11
- ['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA', '98101'],
12
- ['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA', '90001'],
13
- ]
14
-
15
- window('Contacts', 600, 600) { |w|
16
- margined true
3
+ class FormTable
4
+ include Glimmer
17
5
 
18
- vertical_box {
19
- form {
20
- stretchy false
21
-
22
- @name_entry = entry {
23
- label 'Name'
24
- }
25
-
26
- @email_entry = entry {
27
- label 'Email'
28
- }
29
-
30
- @phone_entry = entry {
31
- label 'Phone'
32
- }
33
-
34
- @city_entry = entry {
35
- label 'City'
36
- }
37
-
38
- @state_entry = entry {
39
- label 'State'
40
- }
41
- }
42
-
43
- button('Save Contact') {
44
- stretchy false
45
-
46
- on_clicked do
47
- new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
48
- if new_row.include?('')
49
- msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
50
- else
51
- data << new_row # automatically inserts a row into the table due to implicit data-binding
52
- @unfiltered_data = data.dup
53
- @name_entry.text = ''
54
- @email_entry.text = ''
55
- @phone_entry.text = ''
56
- @city_entry.text = ''
57
- @state_entry.text = ''
58
- end
59
- end
60
- }
61
-
62
- search_entry { |se|
63
- stretchy false
6
+ attr_accessor :name, :email, :phone, :city, :state, :filter_value
7
+
8
+ def initialize
9
+ @data = [
10
+ ['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO', '80014'],
11
+ ['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA', '02101'],
12
+ ['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL', '60007'],
13
+ ['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA', '98101'],
14
+ ['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA', '90001'],
15
+ ]
16
+ end
17
+
18
+ def launch
19
+ window('Contacts', 600, 600) { |w|
20
+ margined true
64
21
 
65
- on_changed do
66
- filter_value = se.text
67
- @unfiltered_data ||= data.dup
68
- # Unfilter first to remove any previous filters
69
- data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
70
- # Now, apply filter if entered
71
- unless filter_value.empty?
72
- data.filter! do |row_data| # affects table indirectly through implicit data-binding
73
- row_data.any? do |cell|
74
- cell.to_s.downcase.include?(filter_value.downcase)
22
+ vertical_box {
23
+ form {
24
+ stretchy false
25
+
26
+ entry {
27
+ label 'Name'
28
+ text <=> [self, :name]
29
+ }
30
+
31
+ entry {
32
+ label 'Email'
33
+ text <=> [self, :email]
34
+ }
35
+
36
+ entry {
37
+ label 'Phone'
38
+ text <=> [self, :phone]
39
+ }
40
+
41
+ entry {
42
+ label 'City'
43
+ text <=> [self, :city]
44
+ }
45
+
46
+ entry {
47
+ label 'State'
48
+ text <=> [self, :state]
49
+ }
50
+ }
51
+
52
+ button('Save Contact') {
53
+ stretchy false
54
+
55
+ on_clicked do
56
+ new_row = [name, email, phone, city, state]
57
+ if new_row.include?('')
58
+ msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
59
+ else
60
+ @data << new_row # automatically inserts a row into the table due to implicit data-binding
61
+ @unfiltered_data = @data.dup
62
+ self.name = '' # automatically clears name entry through explicit data-binding
63
+ self.email = ''
64
+ self.phone = ''
65
+ self.city = ''
66
+ self.state = ''
75
67
  end
76
68
  end
77
- end
78
- end
79
- }
69
+ }
70
+
71
+ search_entry {
72
+ stretchy false
73
+ text <=> [self, :filter_value, # bidirectional data-binding of text to self.filter_value with after_write option
74
+ after_write: ->(filter_value) { # execute after write to self.filter_value
75
+ @unfiltered_data ||= @data.dup
76
+ # Unfilter first to remove any previous filters
77
+ @data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
78
+ # Now, apply filter if entered
79
+ unless filter_value.empty?
80
+ @data.filter! do |row_data| # affects table indirectly through implicit data-binding
81
+ row_data.any? do |cell|
82
+ cell.to_s.downcase.include?(filter_value.downcase)
83
+ end
84
+ end
85
+ end
86
+ }
87
+ ]
88
+ }
89
+
90
+ table {
91
+ text_column('Name')
92
+ text_column('Email')
93
+ text_column('Phone')
94
+ text_column('City')
95
+ text_column('State')
80
96
 
81
- table {
82
- text_column('Name')
83
- text_column('Email')
84
- text_column('Phone')
85
- text_column('City')
86
- text_column('State')
97
+ cell_rows @data # implicit data-binding
98
+
99
+ on_changed do |row, type, row_data|
100
+ puts "Row #{row} #{type}: #{row_data}"
101
+ end
102
+ }
103
+ }
104
+ }.show
105
+ end
106
+ end
87
107
 
88
- cell_rows data # implicit data-binding
89
-
90
- on_changed do |row, type, row_data|
91
- puts "Row #{row} #{type}: #{row_data}"
92
- end
93
- }
94
- }
95
- }.show
108
+ FormTable.new.launch
@@ -0,0 +1,93 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ include Glimmer
4
+
5
+ data = [
6
+ ['Lisa Sky', 'lisa@sky.com', '720-523-4329', 'Denver', 'CO', '80014'],
7
+ ['Jordan Biggins', 'jordan@biggins.com', '617-528-5399', 'Boston', 'MA', '02101'],
8
+ ['Mary Glass', 'mary@glass.com', '847-589-8788', 'Elk Grove Village', 'IL', '60007'],
9
+ ['Darren McGrath', 'darren@mcgrath.com', '206-539-9283', 'Seattle', 'WA', '98101'],
10
+ ['Melody Hanheimer', 'melody@hanheimer.com', '213-493-8274', 'Los Angeles', 'CA', '90001'],
11
+ ]
12
+
13
+ window('Contacts', 600, 600) { |w|
14
+ margined true
15
+
16
+ vertical_box {
17
+ form {
18
+ stretchy false
19
+
20
+ @name_entry = entry {
21
+ label 'Name'
22
+ }
23
+
24
+ @email_entry = entry {
25
+ label 'Email'
26
+ }
27
+
28
+ @phone_entry = entry {
29
+ label 'Phone'
30
+ }
31
+
32
+ @city_entry = entry {
33
+ label 'City'
34
+ }
35
+
36
+ @state_entry = entry {
37
+ label 'State'
38
+ }
39
+ }
40
+
41
+ button('Save Contact') {
42
+ stretchy false
43
+
44
+ on_clicked do
45
+ new_row = [@name_entry.text, @email_entry.text, @phone_entry.text, @city_entry.text, @state_entry.text]
46
+ if new_row.include?('')
47
+ msg_box_error(w, 'Validation Error!', 'All fields are required! Please make sure to enter a value for all fields.')
48
+ else
49
+ data << new_row # automatically inserts a row into the table due to implicit data-binding
50
+ @unfiltered_data = data.dup
51
+ @name_entry.text = ''
52
+ @email_entry.text = ''
53
+ @phone_entry.text = ''
54
+ @city_entry.text = ''
55
+ @state_entry.text = ''
56
+ end
57
+ end
58
+ }
59
+
60
+ search_entry { |se|
61
+ stretchy false
62
+
63
+ on_changed do
64
+ filter_value = se.text
65
+ @unfiltered_data ||= data.dup
66
+ # Unfilter first to remove any previous filters
67
+ data.replace(@unfiltered_data) # affects table indirectly through implicit data-binding
68
+ # Now, apply filter if entered
69
+ unless filter_value.empty?
70
+ data.filter! do |row_data| # affects table indirectly through implicit data-binding
71
+ row_data.any? do |cell|
72
+ cell.to_s.downcase.include?(filter_value.downcase)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ }
78
+
79
+ table {
80
+ text_column('Name')
81
+ text_column('Email')
82
+ text_column('Phone')
83
+ text_column('City')
84
+ text_column('State')
85
+
86
+ cell_rows data # implicit data-binding
87
+
88
+ on_changed do |row, type, row_data|
89
+ puts "Row #{row} #{type}: #{row_data}"
90
+ end
91
+ }
92
+ }
93
+ }.show
@@ -2,106 +2,108 @@
2
2
 
3
3
  require 'glimmer-dsl-libui'
4
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 = 0x1E90FF
13
-
14
- @datapoints = 10.times.map {Random.new.rand(90)}
15
-
16
- def graph_size(area_width, area_height)
17
- graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
18
- graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
19
- [graph_width, graph_height]
20
- end
21
-
22
- def point_locations(width, height)
23
- xincr = width / 9.0 # 10 - 1 to make the last point be at the end
24
- yincr = height / 100.0
25
-
26
- @datapoints.each_with_index.map do |value, i|
27
- val = 100 - value
28
- [xincr * i, yincr * val]
5
+ class Histogram
6
+ include Glimmer
7
+
8
+ X_OFF_LEFT = 20
9
+ Y_OFF_TOP = 20
10
+ X_OFF_RIGHT = 20
11
+ Y_OFF_BOTTOM = 20
12
+ POINT_RADIUS = 5
13
+ COLOR_BLUE = Glimmer::LibUI.interpret_color(0x1E90FF)
14
+
15
+ attr_accessor :datapoints, :histogram_color
16
+
17
+ def initialize
18
+ @datapoints = 10.times.map {Random.new.rand(90)}
19
+ @histogram_color = COLOR_BLUE
29
20
  end
30
- end
31
-
32
- # method-based custom control representing a graph path
33
- def graph_path(width, height, should_extend, &block)
34
- locations = point_locations(width, height).flatten
35
- path {
36
- if should_extend
37
- polygon(locations + [width, height, 0, height])
38
- else
39
- polyline(locations)
21
+
22
+ def graph_size(area_width, area_height)
23
+ graph_width = area_width - X_OFF_LEFT - X_OFF_RIGHT
24
+ graph_height = area_height - Y_OFF_TOP - Y_OFF_BOTTOM
25
+ [graph_width, graph_height]
26
+ end
27
+
28
+ def point_locations(width, height)
29
+ xincr = width / 9.0 # 10 - 1 to make the last point be at the end
30
+ yincr = height / 100.0
31
+
32
+ @datapoints.each_with_index.map do |value, i|
33
+ val = 100 - value
34
+ [xincr * i, yincr * val]
40
35
  end
41
-
42
- # apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
43
- transform {
44
- translate X_OFF_LEFT, Y_OFF_TOP
45
- }
46
-
47
- block.call
48
- }
49
- end
50
-
51
- window('histogram example', 640, 480) {
52
- margined true
36
+ end
53
37
 
54
- horizontal_box {
55
- vertical_box {
56
- stretchy false
57
-
58
- 10.times do |i|
59
- spinbox(0, 100) { |sb|
60
- stretchy false
61
- value @datapoints[i]
62
-
63
- on_changed do
64
- @datapoints[i] = sb.value
65
- @area.queue_redraw_all
66
- end
67
- }
38
+ # method-based custom control representing a graph path
39
+ def graph_path(width, height, should_extend, &block)
40
+ locations = point_locations(width, height).flatten
41
+ path {
42
+ if should_extend
43
+ polygon(locations + [width, height, 0, height])
44
+ else
45
+ polyline(locations)
68
46
  end
69
47
 
70
- @color_button = color_button {
71
- stretchy false
72
- color COLOR_BLUE
73
-
74
- on_changed do
75
- @area.queue_redraw_all
76
- end
48
+ # apply a transform to the coordinate space for this path so (0, 0) is the top-left corner of the graph
49
+ transform {
50
+ translate X_OFF_LEFT, Y_OFF_TOP
77
51
  }
52
+
53
+ block.call
78
54
  }
79
-
80
- @area = area {
81
- on_draw do |area_draw_params|
82
- rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height]) {
83
- fill 0xFFFFFF
84
- }
85
-
86
- graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
55
+ end
56
+
57
+ def launch
58
+ window('histogram example', 640, 480) {
59
+ margined true
87
60
 
88
- figure(X_OFF_LEFT, Y_OFF_TOP) {
89
- line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
90
- line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
61
+ horizontal_box {
62
+ vertical_box {
63
+ stretchy false
91
64
 
92
- stroke 0x000000, thickness: 2, miter_limit: 10
93
- }
94
-
95
- # now create the fill for the graph below the graph line
96
- graph_path(graph_width, graph_height, true) {
97
- fill @color_button.color.merge(a: 0.5)
65
+ 10.times do |i|
66
+ spinbox(0, 100) { |sb|
67
+ stretchy false
68
+ value <=> [self, "datapoints[#{i}]", after_write: -> { @area.queue_redraw_all }]
69
+ }
70
+ end
71
+
72
+ color_button { |cb|
73
+ stretchy false
74
+ color <=> [self, :histogram_color, after_write: -> { @area.queue_redraw_all }]
75
+ }
98
76
  }
99
77
 
100
- # now draw the histogram line
101
- graph_path(graph_width, graph_height, false) {
102
- stroke @color_button.color.merge(thickness: 2, miter_limit: 10)
78
+ @area = area {
79
+ on_draw do |area_draw_params|
80
+ rectangle(0, 0, area_draw_params[:area_width], area_draw_params[:area_height]) {
81
+ fill 0xFFFFFF
82
+ }
83
+
84
+ graph_width, graph_height = *graph_size(area_draw_params[:area_width], area_draw_params[:area_height])
85
+
86
+ figure(X_OFF_LEFT, Y_OFF_TOP) {
87
+ line(X_OFF_LEFT, Y_OFF_TOP + graph_height)
88
+ line(X_OFF_LEFT + graph_width, Y_OFF_TOP + graph_height)
89
+
90
+ stroke 0x000000, thickness: 2, miter_limit: 10
91
+ }
92
+
93
+ # now create the fill for the graph below the graph line
94
+ graph_path(graph_width, graph_height, true) {
95
+ fill @histogram_color.merge(a: 0.5)
96
+ }
97
+
98
+ # now draw the histogram line
99
+ graph_path(graph_width, graph_height, false) {
100
+ stroke @histogram_color.merge(thickness: 2, miter_limit: 10)
101
+ }
102
+ end
103
103
  }
104
- end
105
- }
106
- }
107
- }.show
104
+ }
105
+ }.show
106
+ end
107
+ end
108
+
109
+ Histogram.new.launch