glimmer-dsl-libui 0.4.3 → 0.4.7
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -1
- data/README.md +926 -153
- data/VERSION +1 -1
- data/examples/color_button.rb +18 -13
- data/examples/color_button2.rb +14 -0
- data/examples/date_time_picker.rb +19 -14
- data/examples/date_time_picker2.rb +20 -0
- data/examples/dynamic_area.rb +77 -90
- data/examples/dynamic_area2.rb +14 -12
- data/examples/dynamic_area3.rb +90 -0
- data/examples/dynamic_area4.rb +95 -0
- data/examples/font_button.rb +17 -12
- data/examples/font_button2.rb +18 -0
- data/examples/form_table.rb +0 -2
- data/examples/form_table2.rb +0 -2
- data/examples/histogram.rb +93 -91
- data/examples/histogram2.rb +109 -0
- data/examples/midi_player.rb +4 -5
- data/examples/midi_player2.rb +83 -0
- data/examples/midi_player3.rb +84 -0
- data/examples/timer.rb +28 -31
- data/examples/timer2.rb +129 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/libui/attributed_string.rb +3 -0
- data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +5 -0
- data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +18 -2
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +5 -0
- data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +5 -0
- data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/slider_proxy.rb +38 -0
- data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +38 -0
- data/lib/glimmer/libui/control_proxy.rb +4 -12
- data/lib/glimmer/libui/data_bindable.rb +39 -0
- data/lib/glimmer/libui/shape.rb +2 -0
- metadata +14 -2
data/examples/histogram.rb
CHANGED
@@ -2,106 +2,108 @@
|
|
2
2
|
|
3
3
|
require 'glimmer-dsl-libui'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
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
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
-
|
89
|
-
|
90
|
-
|
61
|
+
horizontal_box {
|
62
|
+
vertical_box {
|
63
|
+
stretchy false
|
91
64
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
105
|
-
}
|
106
|
-
|
107
|
-
|
104
|
+
}
|
105
|
+
}.show
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Histogram.new.launch
|
@@ -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/midi_player.rb
CHANGED
@@ -6,6 +6,8 @@ class TinyMidiPlayer
|
|
6
6
|
include Glimmer
|
7
7
|
|
8
8
|
VERSION = '0.0.1'
|
9
|
+
|
10
|
+
attr_accessor :selected_file
|
9
11
|
|
10
12
|
def initialize
|
11
13
|
@pid = nil
|
@@ -70,11 +72,8 @@ class TinyMidiPlayer
|
|
70
72
|
|
71
73
|
combobox { |c|
|
72
74
|
items @midi_files.map { |path| File.basename(path) }
|
73
|
-
|
74
|
-
|
75
|
-
@selected_file = @midi_files[c.selected]
|
76
|
-
play_midi if @th&.alive?
|
77
|
-
end
|
75
|
+
# data-bind selected item (String) to self.selected_file with on-read/on-write converters and after_write operation
|
76
|
+
selected_item <=> [self, :selected_file, on_read: ->(f) {File.basename(f.to_s)}, on_write: ->(f) {File.join(@music_directory, f)}, after_write: -> { play_midi if @th&.alive? }]
|
78
77
|
}
|
79
78
|
}
|
80
79
|
}.show
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'glimmer-dsl-libui'
|
4
|
+
|
5
|
+
class TinyMidiPlayer
|
6
|
+
include Glimmer
|
7
|
+
|
8
|
+
VERSION = '0.0.1'
|
9
|
+
|
10
|
+
attr_accessor :selected_file
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@pid = nil
|
14
|
+
@music_directory = File.expand_path('../sounds', __dir__)
|
15
|
+
@midi_files = Dir.glob(File.join(@music_directory, '**/*.mid'))
|
16
|
+
.sort_by { |path| File.basename(path) }
|
17
|
+
at_exit { stop_midi }
|
18
|
+
create_gui
|
19
|
+
end
|
20
|
+
|
21
|
+
def stop_midi
|
22
|
+
if @pid
|
23
|
+
Process.kill(:SIGKILL, @pid) if @th.alive?
|
24
|
+
@pid = nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def play_midi
|
29
|
+
stop_midi
|
30
|
+
if @pid.nil? && @selected_file
|
31
|
+
begin
|
32
|
+
@pid = spawn "timidity #{@selected_file}"
|
33
|
+
@th = Process.detach @pid
|
34
|
+
rescue Errno::ENOENT
|
35
|
+
warn 'Timidty++ not found. Please install Timidity++.'
|
36
|
+
warn 'https://sourceforge.net/projects/timidity/'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def show_version
|
42
|
+
msg_box('Tiny Midi Player',
|
43
|
+
"Written in Ruby\n" \
|
44
|
+
"https://github.com/kojix2/libui\n" \
|
45
|
+
"Version #{VERSION}")
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_gui
|
49
|
+
menu('Help') {
|
50
|
+
menu_item('Version') {
|
51
|
+
on_clicked do
|
52
|
+
show_version
|
53
|
+
end
|
54
|
+
}
|
55
|
+
}
|
56
|
+
window('Tiny Midi Player', 200, 50) {
|
57
|
+
horizontal_box {
|
58
|
+
vertical_box {
|
59
|
+
stretchy false
|
60
|
+
|
61
|
+
button('▶') {
|
62
|
+
on_clicked do
|
63
|
+
play_midi
|
64
|
+
end
|
65
|
+
}
|
66
|
+
button('■') {
|
67
|
+
on_clicked do
|
68
|
+
stop_midi
|
69
|
+
end
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
combobox { |c|
|
74
|
+
items @midi_files.map { |path| File.basename(path) }
|
75
|
+
# data-bind selected index (Integer) to self.selected_file with on-read/on-write converters and after_write operation
|
76
|
+
selected <=> [self, :selected_file, on_read: ->(f) {@midi_files.index(f)}, on_write: ->(i) {@midi_files[i]}, after_write: -> { play_midi if @th&.alive? }]
|
77
|
+
}
|
78
|
+
}
|
79
|
+
}.show
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
TinyMidiPlayer.new
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'glimmer-dsl-libui'
|
4
|
+
|
5
|
+
class TinyMidiPlayer
|
6
|
+
include Glimmer
|
7
|
+
|
8
|
+
VERSION = '0.0.1'
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@pid = nil
|
12
|
+
@music_directory = File.expand_path('../sounds', __dir__)
|
13
|
+
@midi_files = Dir.glob(File.join(@music_directory, '**/*.mid'))
|
14
|
+
.sort_by { |path| File.basename(path) }
|
15
|
+
at_exit { stop_midi }
|
16
|
+
create_gui
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop_midi
|
20
|
+
if @pid
|
21
|
+
Process.kill(:SIGKILL, @pid) if @th.alive?
|
22
|
+
@pid = nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def play_midi
|
27
|
+
stop_midi
|
28
|
+
if @pid.nil? && @selected_file
|
29
|
+
begin
|
30
|
+
@pid = spawn "timidity #{@selected_file}"
|
31
|
+
@th = Process.detach @pid
|
32
|
+
rescue Errno::ENOENT
|
33
|
+
warn 'Timidty++ not found. Please install Timidity++.'
|
34
|
+
warn 'https://sourceforge.net/projects/timidity/'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def show_version
|
40
|
+
msg_box('Tiny Midi Player',
|
41
|
+
"Written in Ruby\n" \
|
42
|
+
"https://github.com/kojix2/libui\n" \
|
43
|
+
"Version #{VERSION}")
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_gui
|
47
|
+
menu('Help') {
|
48
|
+
menu_item('Version') {
|
49
|
+
on_clicked do
|
50
|
+
show_version
|
51
|
+
end
|
52
|
+
}
|
53
|
+
}
|
54
|
+
window('Tiny Midi Player', 200, 50) {
|
55
|
+
horizontal_box {
|
56
|
+
vertical_box {
|
57
|
+
stretchy false
|
58
|
+
|
59
|
+
button('▶') {
|
60
|
+
on_clicked do
|
61
|
+
play_midi
|
62
|
+
end
|
63
|
+
}
|
64
|
+
button('■') {
|
65
|
+
on_clicked do
|
66
|
+
stop_midi
|
67
|
+
end
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
combobox { |c|
|
72
|
+
items @midi_files.map { |path| File.basename(path) }
|
73
|
+
|
74
|
+
on_selected do
|
75
|
+
@selected_file = @midi_files[c.selected]
|
76
|
+
play_midi if @th&.alive?
|
77
|
+
end
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}.show
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
TinyMidiPlayer.new
|
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 = @
|
45
|
-
minutes = @
|
46
|
-
hours = @
|
45
|
+
seconds = @sec
|
46
|
+
minutes = @min
|
47
|
+
hours = @hour
|
47
48
|
if seconds > 0
|
48
|
-
|
49
|
+
self.sec = seconds -= 1
|
49
50
|
end
|
50
51
|
if seconds == 0
|
51
52
|
if minutes > 0
|
52
|
-
|
53
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
85
|
+
spinbox(0, HOUR_MAX) {
|
87
86
|
stretchy false
|
88
|
-
value
|
87
|
+
value <=> [self, :hour]
|
89
88
|
}
|
90
89
|
label(':') {
|
91
90
|
stretchy false
|
92
91
|
}
|
93
|
-
|
92
|
+
spinbox(0, MINUTE_MAX) {
|
94
93
|
stretchy false
|
95
|
-
value
|
94
|
+
value <=> [self, :min]
|
96
95
|
}
|
97
96
|
label(':') {
|
98
97
|
stretchy false
|
99
98
|
}
|
100
|
-
|
99
|
+
spinbox(0, SECOND_MAX) {
|
101
100
|
stretchy false
|
102
|
-
value
|
101
|
+
value <=> [self, :sec]
|
103
102
|
}
|
104
103
|
}
|
105
104
|
horizontal_box {
|
106
|
-
|
105
|
+
button('Start') {
|
106
|
+
enabled <= [self, :started, on_read: :!]
|
107
|
+
|
107
108
|
on_clicked do
|
108
|
-
|
109
|
-
|
110
|
-
@started = true
|
111
|
-
@played = false
|
109
|
+
self.started = true
|
110
|
+
self.played = false
|
112
111
|
end
|
113
112
|
}
|
114
113
|
|
115
|
-
|
116
|
-
enabled
|
114
|
+
button('Stop') {
|
115
|
+
enabled <= [self, :started]
|
117
116
|
|
118
117
|
on_clicked do
|
119
|
-
|
120
|
-
@stop_button.enabled = false
|
121
|
-
@started = false
|
118
|
+
self.started = false
|
122
119
|
end
|
123
120
|
}
|
124
121
|
}
|