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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/README.md +926 -153
  4. data/VERSION +1 -1
  5. data/examples/color_button.rb +18 -13
  6. data/examples/color_button2.rb +14 -0
  7. data/examples/date_time_picker.rb +19 -14
  8. data/examples/date_time_picker2.rb +20 -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_table.rb +0 -2
  16. data/examples/form_table2.rb +0 -2
  17. data/examples/histogram.rb +93 -91
  18. data/examples/histogram2.rb +109 -0
  19. data/examples/midi_player.rb +4 -5
  20. data/examples/midi_player2.rb +83 -0
  21. data/examples/midi_player3.rb +84 -0
  22. data/examples/timer.rb +28 -31
  23. data/examples/timer2.rb +129 -0
  24. data/glimmer-dsl-libui.gemspec +0 -0
  25. data/lib/glimmer/libui/attributed_string.rb +3 -0
  26. data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +5 -0
  27. data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +18 -2
  28. data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +5 -0
  29. data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +5 -0
  30. data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +4 -0
  31. data/lib/glimmer/libui/control_proxy/slider_proxy.rb +38 -0
  32. data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +38 -0
  33. data/lib/glimmer/libui/control_proxy.rb +4 -12
  34. data/lib/glimmer/libui/data_bindable.rb +39 -0
  35. data/lib/glimmer/libui/shape.rb +2 -0
  36. metadata +14 -2
@@ -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
@@ -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
@@ -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
- on_selected do
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 = @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
  }