glimmer-dsl-libui 0.4.1 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -1
  3. data/README.md +1628 -204
  4. data/VERSION +1 -1
  5. data/examples/basic_entry.rb +27 -24
  6. data/examples/basic_entry2.rb +31 -0
  7. data/examples/button_counter.rb +27 -0
  8. data/examples/dynamic_area.rb +77 -90
  9. data/examples/dynamic_area2.rb +14 -12
  10. data/examples/dynamic_area3.rb +90 -0
  11. data/examples/dynamic_area4.rb +95 -0
  12. data/examples/form.rb +42 -30
  13. data/examples/form2.rb +37 -0
  14. data/examples/form_table.rb +100 -87
  15. data/examples/form_table2.rb +93 -0
  16. data/examples/histogram.rb +98 -91
  17. data/examples/histogram2.rb +109 -0
  18. data/examples/login.rb +45 -39
  19. data/examples/login2.rb +55 -0
  20. data/examples/login3.rb +65 -0
  21. data/examples/login4.rb +61 -0
  22. data/examples/login5.rb +43 -0
  23. data/examples/meta_example.rb +10 -7
  24. data/examples/method_based_custom_keyword.rb +8 -15
  25. data/examples/method_based_custom_keyword2.rb +97 -0
  26. data/examples/snake.rb +1 -1
  27. data/examples/timer.rb +28 -31
  28. data/examples/timer2.rb +129 -0
  29. data/glimmer-dsl-libui.gemspec +0 -0
  30. data/lib/glimmer/dsl/libui/data_binding_expression.rb +4 -6
  31. data/lib/glimmer/libui/attributed_string.rb +3 -0
  32. data/lib/glimmer/libui/control_proxy/area_proxy.rb +52 -46
  33. data/lib/glimmer/libui/control_proxy/entry_proxy.rb +5 -0
  34. data/lib/glimmer/libui/control_proxy/image_proxy.rb +4 -5
  35. data/lib/glimmer/libui/control_proxy/multiline_entry_proxy.rb +5 -0
  36. data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +38 -0
  37. data/lib/glimmer/libui/control_proxy/table_proxy.rb +1 -1
  38. data/lib/glimmer/libui/control_proxy.rb +8 -1
  39. data/lib/glimmer/libui/data_bindable.rb +39 -0
  40. data/lib/glimmer/libui/shape.rb +7 -2
  41. metadata +17 -2
@@ -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
@@ -40,7 +43,7 @@ class MetaExample
40
43
  end
41
44
 
42
45
  def version_count_for(example)
43
- Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(/\d\.rb$/)}.count + 1
46
+ Dir.glob(File.join(File.expand_path('.', __dir__), "#{example.underscore}*.rb")).select {|file| file.match(/#{example.underscore}\d\.rb$/)}.count + 1
44
47
  end
45
48
 
46
49
  def glimmer_dsl_libui_file
@@ -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
data/examples/snake.rb CHANGED
@@ -38,7 +38,7 @@ class Snake
38
38
  def create_gui
39
39
  @main_window = window {
40
40
  # data-bind window title to game score, converting it to a title string on read from the model
41
- title <= [@game, :score, on_read: -> (score) {"Glimmer Snake (Score: #{@game.score})"}]
41
+ title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
42
42
  content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
43
43
  resizable false
44
44
 
data/examples/timer.rb CHANGED
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require 'glimmer-dsl-libui'
4
2
 
5
3
  class Timer
@@ -9,9 +7,12 @@ class Timer
9
7
  MINUTE_MAX = 59
10
8
  HOUR_MAX = 23
11
9
 
10
+ attr_accessor :hour, :min, :sec, :started, :played
11
+
12
12
  def initialize
13
13
  @pid = nil
14
14
  @alarm_file = File.expand_path('../sounds/AlanWalker-Faded.mid', __dir__)
15
+ @hour = @min = @sec = 0
15
16
  at_exit { stop_alarm }
16
17
  setup_timer
17
18
  create_gui
@@ -41,31 +42,29 @@ class Timer
41
42
  unless @setup_timer
42
43
  Glimmer::LibUI.timer(1) do
43
44
  if @started
44
- seconds = @sec_spinbox.value
45
- minutes = @min_spinbox.value
46
- hours = @hour_spinbox.value
45
+ seconds = @sec
46
+ minutes = @min
47
+ hours = @hour
47
48
  if seconds > 0
48
- @sec_spinbox.value = seconds -= 1
49
+ self.sec = seconds -= 1
49
50
  end
50
51
  if seconds == 0
51
52
  if minutes > 0
52
- @min_spinbox.value = minutes -= 1
53
- @sec_spinbox.value = seconds = SECOND_MAX
53
+ self.min = minutes -= 1
54
+ self.sec = seconds = SECOND_MAX
54
55
  end
55
56
  if minutes == 0
56
57
  if hours > 0
57
- @hour_spinbox.value = hours -= 1
58
- @min_spinbox.value = minutes = MINUTE_MAX
59
- @sec_spinbox.value = seconds = SECOND_MAX
58
+ self.hour = hours -= 1
59
+ self.min = minutes = MINUTE_MAX
60
+ self.sec = seconds = SECOND_MAX
60
61
  end
61
62
  if hours == 0 && minutes == 0 && seconds == 0
62
- @start_button.enabled = true
63
- @stop_button.enabled = false
64
- @started = false
63
+ self.started = false
65
64
  unless @played
66
65
  play_alarm
67
66
  msg_box('Alarm', 'Countdown Is Finished!')
68
- @played = true
67
+ self.played = true
69
68
  end
70
69
  end
71
70
  end
@@ -83,42 +82,40 @@ class Timer
83
82
  group('Countdown') {
84
83
  vertical_box {
85
84
  horizontal_box {
86
- @hour_spinbox = spinbox(0, HOUR_MAX) {
85
+ spinbox(0, HOUR_MAX) {
87
86
  stretchy false
88
- value 0
87
+ value <=> [self, :hour]
89
88
  }
90
89
  label(':') {
91
90
  stretchy false
92
91
  }
93
- @min_spinbox = spinbox(0, MINUTE_MAX) {
92
+ spinbox(0, MINUTE_MAX) {
94
93
  stretchy false
95
- value 0
94
+ value <=> [self, :min]
96
95
  }
97
96
  label(':') {
98
97
  stretchy false
99
98
  }
100
- @sec_spinbox = spinbox(0, SECOND_MAX) {
99
+ spinbox(0, SECOND_MAX) {
101
100
  stretchy false
102
- value 0
101
+ value <=> [self, :sec]
103
102
  }
104
103
  }
105
104
  horizontal_box {
106
- @start_button = button('Start') {
105
+ button('Start') {
106
+ enabled <= [self, :started, on_read: :!]
107
+
107
108
  on_clicked do
108
- @start_button.enabled = false
109
- @stop_button.enabled = true
110
- @started = true
111
- @played = false
109
+ self.started = true
110
+ self.played = false
112
111
  end
113
112
  }
114
113
 
115
- @stop_button = button('Stop') {
116
- enabled false
114
+ button('Stop') {
115
+ enabled <= [self, :started]
117
116
 
118
117
  on_clicked do
119
- @start_button.enabled = true
120
- @stop_button.enabled = false
121
- @started = false
118
+ self.started = false
122
119
  end
123
120
  }
124
121
  }
@@ -0,0 +1,129 @@
1
+ require 'glimmer-dsl-libui'
2
+
3
+ class Timer
4
+ include Glimmer
5
+
6
+ SECOND_MAX = 59
7
+ MINUTE_MAX = 59
8
+ HOUR_MAX = 23
9
+
10
+ def initialize
11
+ @pid = nil
12
+ @alarm_file = File.expand_path('../sounds/AlanWalker-Faded.mid', __dir__)
13
+ at_exit { stop_alarm }
14
+ setup_timer
15
+ create_gui
16
+ end
17
+
18
+ def stop_alarm
19
+ if @pid
20
+ Process.kill(:SIGKILL, @pid) if @th.alive?
21
+ @pid = nil
22
+ end
23
+ end
24
+
25
+ def play_alarm
26
+ stop_alarm
27
+ if @pid.nil?
28
+ begin
29
+ @pid = spawn "timidity -G 0.0-10.0 #{@alarm_file}"
30
+ @th = Process.detach @pid
31
+ rescue Errno::ENOENT
32
+ warn 'Timidty++ not found. Please install Timidity++.'
33
+ warn 'https://sourceforge.net/projects/timidity/'
34
+ end
35
+ end
36
+ end
37
+
38
+ def setup_timer
39
+ unless @setup_timer
40
+ Glimmer::LibUI.timer(1) do
41
+ if @started
42
+ seconds = @sec_spinbox.value
43
+ minutes = @min_spinbox.value
44
+ hours = @hour_spinbox.value
45
+ if seconds > 0
46
+ @sec_spinbox.value = seconds -= 1
47
+ end
48
+ if seconds == 0
49
+ if minutes > 0
50
+ @min_spinbox.value = minutes -= 1
51
+ @sec_spinbox.value = seconds = SECOND_MAX
52
+ end
53
+ if minutes == 0
54
+ if hours > 0
55
+ @hour_spinbox.value = hours -= 1
56
+ @min_spinbox.value = minutes = MINUTE_MAX
57
+ @sec_spinbox.value = seconds = SECOND_MAX
58
+ end
59
+ if hours == 0 && minutes == 0 && seconds == 0
60
+ @start_button.enabled = true
61
+ @stop_button.enabled = false
62
+ @started = false
63
+ unless @played
64
+ play_alarm
65
+ msg_box('Alarm', 'Countdown Is Finished!')
66
+ @played = true
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ @setup_timer = true
74
+ end
75
+ end
76
+
77
+ def create_gui
78
+ window('Timer') {
79
+ margined true
80
+
81
+ group('Countdown') {
82
+ vertical_box {
83
+ horizontal_box {
84
+ @hour_spinbox = spinbox(0, HOUR_MAX) {
85
+ stretchy false
86
+ value 0
87
+ }
88
+ label(':') {
89
+ stretchy false
90
+ }
91
+ @min_spinbox = spinbox(0, MINUTE_MAX) {
92
+ stretchy false
93
+ value 0
94
+ }
95
+ label(':') {
96
+ stretchy false
97
+ }
98
+ @sec_spinbox = spinbox(0, SECOND_MAX) {
99
+ stretchy false
100
+ value 0
101
+ }
102
+ }
103
+ horizontal_box {
104
+ @start_button = button('Start') {
105
+ on_clicked do
106
+ @start_button.enabled = false
107
+ @stop_button.enabled = true
108
+ @started = true
109
+ @played = false
110
+ end
111
+ }
112
+
113
+ @stop_button = button('Stop') {
114
+ enabled false
115
+
116
+ on_clicked do
117
+ @start_button.enabled = true
118
+ @stop_button.enabled = false
119
+ @started = false
120
+ end
121
+ }
122
+ }
123
+ }
124
+ }
125
+ }.show
126
+ end
127
+ end
128
+
129
+ Timer.new
Binary file