glimmer-dsl-libui 0.4.2 → 0.4.6

Sign up to get free protection for your applications and to get access to all the features.
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