glimmer-dsl-libui 0.4.6 → 0.4.10
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 -0
- data/README.md +601 -323
- data/VERSION +1 -1
- data/examples/button_counter.rb +2 -1
- data/examples/cpu_percentage.rb +36 -0
- data/examples/date_time_picker.rb +19 -14
- data/examples/date_time_picker2.rb +20 -0
- data/examples/meta_example.rb +17 -6
- data/examples/midi_player.rb +5 -6
- data/examples/midi_player2.rb +83 -0
- data/examples/midi_player3.rb +84 -0
- data/examples/snake.rb +19 -10
- data/examples/snake2.rb +97 -0
- data/examples/tetris.rb +15 -18
- data/examples/tic_tac_toe.rb +1 -0
- data/examples/tic_tac_toe2.rb +84 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/libui/control_proxy/checkbox_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/color_button_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/combobox_proxy.rb +17 -2
- data/lib/glimmer/libui/control_proxy/date_time_picker_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/editable_combobox_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/entry_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/font_button_proxy.rb +5 -1
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/check_menu_item_proxy.rb +4 -0
- data/lib/glimmer/libui/control_proxy/menu_item_proxy/radio_menu_item_proxy.rb +16 -4
- data/lib/glimmer/libui/control_proxy/multiline_entry_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/radio_buttons_proxy.rb +19 -0
- data/lib/glimmer/libui/control_proxy/slider_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy/spinbox_proxy.rb +1 -2
- data/lib/glimmer/libui/control_proxy.rb +2 -2
- data/lib/glimmer/libui/data_bindable.rb +27 -2
- metadata +8 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.10
|
data/examples/button_counter.rb
CHANGED
@@ -13,7 +13,8 @@ class ButtonCounter
|
|
13
13
|
window('Hello, Button!', 190, 20) {
|
14
14
|
vertical_box {
|
15
15
|
button {
|
16
|
-
|
16
|
+
# data-bind button text to self count, converting to string on read.
|
17
|
+
text <= [self, :count, on_read: ->(count) {"Count: #{count}"}]
|
17
18
|
|
18
19
|
on_clicked do
|
19
20
|
self.count += 1
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
include Glimmer
|
5
|
+
|
6
|
+
data = [
|
7
|
+
['CPU', '0%', 0],
|
8
|
+
]
|
9
|
+
|
10
|
+
Glimmer::LibUI.timer(1) do
|
11
|
+
cpu_percentage_value = nil
|
12
|
+
if OS.windows?
|
13
|
+
cpu_percentage_raw_value = `wmic cpu get loadpercentage`
|
14
|
+
cpu_percentage_value = cpu_percentage_raw_value.split("\n")[2].to_i
|
15
|
+
elsif OS.mac?
|
16
|
+
cpu_percentage_value = `ps -A -o %cpu | awk '{s+=$1} END {print s}'`.to_i
|
17
|
+
elsif OS.linux?
|
18
|
+
stats = `top -n 1`
|
19
|
+
idle_percentage = stats.split("\n")[2].match(/ni,.* (.*) .*id/)[1]
|
20
|
+
cpu_percentage_value = (BigDecimal(100) - BigDecimal(idle_percentage)).to_i
|
21
|
+
end
|
22
|
+
data[0][1] = "#{cpu_percentage_value}%"
|
23
|
+
data[0][2] = cpu_percentage_value
|
24
|
+
end
|
25
|
+
|
26
|
+
window('CPU Percentage', 400, 200) {
|
27
|
+
vertical_box {
|
28
|
+
table {
|
29
|
+
text_column('Name')
|
30
|
+
text_column('Value')
|
31
|
+
progress_bar_column('Percentage')
|
32
|
+
|
33
|
+
cell_rows data # implicit data-binding
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}.show
|
@@ -2,19 +2,24 @@
|
|
2
2
|
|
3
3
|
require 'glimmer-dsl-libui'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
date_time_picker { |dtp|
|
10
|
-
on_changed do
|
11
|
-
time = dtp.time
|
12
|
-
p time
|
13
|
-
end
|
14
|
-
}
|
15
|
-
}
|
5
|
+
class DateTimePicker
|
6
|
+
include Glimmer
|
7
|
+
|
8
|
+
attr_accessor :picked_time
|
16
9
|
|
17
|
-
|
18
|
-
|
10
|
+
def launch
|
11
|
+
window('Date Time Pickers', 300, 200) {
|
12
|
+
vertical_box {
|
13
|
+
date_time_picker {
|
14
|
+
time <=> [self, :picked_time, after_write: ->(time) { p time }]
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
on_closing do
|
19
|
+
puts 'Bye Bye'
|
20
|
+
end
|
21
|
+
}.show
|
19
22
|
end
|
20
|
-
|
23
|
+
end
|
24
|
+
|
25
|
+
DateTimePicker.new.launch
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'glimmer-dsl-libui'
|
4
|
+
|
5
|
+
include Glimmer
|
6
|
+
|
7
|
+
window('Date Time Pickers', 300, 200) {
|
8
|
+
vertical_box {
|
9
|
+
date_time_picker { |dtp|
|
10
|
+
on_changed do
|
11
|
+
time = dtp.time
|
12
|
+
p time
|
13
|
+
end
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
on_closing do
|
18
|
+
puts 'Bye Bye'
|
19
|
+
end
|
20
|
+
}.show
|
data/examples/meta_example.rb
CHANGED
@@ -24,18 +24,28 @@ class MetaExample
|
|
24
24
|
@examples
|
25
25
|
end
|
26
26
|
|
27
|
+
def basic_examples
|
28
|
+
examples.select {|example| example.start_with?('Basic') || ADDITIONAL_BASIC_EXAMPLES.include?(example) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def advanced_examples
|
32
|
+
examples - basic_examples
|
33
|
+
end
|
34
|
+
|
27
35
|
def examples_with_versions
|
28
|
-
examples
|
29
|
-
version_count_for(example) > 1 ? "#{example} (#{version_count_for(example)} versions)" : example
|
30
|
-
end
|
36
|
+
append_versions(examples)
|
31
37
|
end
|
32
38
|
|
33
39
|
def basic_examples_with_versions
|
34
|
-
|
40
|
+
append_versions(basic_examples)
|
35
41
|
end
|
36
42
|
|
37
43
|
def advanced_examples_with_versions
|
38
|
-
|
44
|
+
append_versions(advanced_examples)
|
45
|
+
end
|
46
|
+
|
47
|
+
def append_versions(examples)
|
48
|
+
examples.map { |example| version_count_for(example) > 1 ? "#{example} (#{version_count_for(example)} versions)" : example }
|
39
49
|
end
|
40
50
|
|
41
51
|
def file_path_for(example)
|
@@ -72,7 +82,7 @@ class MetaExample
|
|
72
82
|
end
|
73
83
|
|
74
84
|
def launch
|
75
|
-
window('Meta-Example',
|
85
|
+
window('Meta-Example', 1000, 500) {
|
76
86
|
margined true
|
77
87
|
|
78
88
|
horizontal_box {
|
@@ -107,6 +117,7 @@ class MetaExample
|
|
107
117
|
@advanced_example_radio_buttons = radio_buttons {
|
108
118
|
stretchy false
|
109
119
|
items advanced_examples_with_versions
|
120
|
+
selected -1
|
110
121
|
|
111
122
|
on_selected do
|
112
123
|
@selected_example_index = examples_with_versions.index(advanced_examples_with_versions[@advanced_example_radio_buttons.selected])
|
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
|
@@ -68,13 +70,10 @@ class TinyMidiPlayer
|
|
68
70
|
}
|
69
71
|
}
|
70
72
|
|
71
|
-
combobox {
|
73
|
+
combobox {
|
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/snake.rb
CHANGED
@@ -12,6 +12,7 @@ class Snake
|
|
12
12
|
@game = Model::Game.new
|
13
13
|
@grid = Presenter::Grid.new(@game)
|
14
14
|
@game.start
|
15
|
+
@keypress_queue = []
|
15
16
|
create_gui
|
16
17
|
register_observers
|
17
18
|
end
|
@@ -31,7 +32,23 @@ class Snake
|
|
31
32
|
end
|
32
33
|
|
33
34
|
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
34
|
-
|
35
|
+
unless @game.over?
|
36
|
+
process_queued_keypress
|
37
|
+
@game.snake.move
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_queued_keypress
|
43
|
+
# key press queue ensures one turn per snake move to avoid a double-turn resulting in instant death (due to snake illogically going back against itself)
|
44
|
+
key = @keypress_queue.shift
|
45
|
+
case [@game.snake.head.orientation, key]
|
46
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
47
|
+
@game.snake.turn_right
|
48
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
49
|
+
@game.snake.turn_left
|
50
|
+
else
|
51
|
+
# No Op
|
35
52
|
end
|
36
53
|
end
|
37
54
|
|
@@ -56,15 +73,7 @@ class Snake
|
|
56
73
|
}
|
57
74
|
|
58
75
|
on_key_up do |area_key_event|
|
59
|
-
|
60
|
-
case orientation_and_key
|
61
|
-
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
62
|
-
@game.snake.turn_right
|
63
|
-
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
64
|
-
@game.snake.turn_left
|
65
|
-
else
|
66
|
-
# No Op
|
67
|
-
end
|
76
|
+
@keypress_queue << area_key_event[:ext_key]
|
68
77
|
end
|
69
78
|
}
|
70
79
|
end
|
data/examples/snake2.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
|
3
|
+
require_relative 'snake/presenter/grid'
|
4
|
+
|
5
|
+
class Snake
|
6
|
+
include Glimmer
|
7
|
+
|
8
|
+
CELL_SIZE = 15
|
9
|
+
SNAKE_MOVE_DELAY = 0.1
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@game = Model::Game.new
|
13
|
+
@grid = Presenter::Grid.new(@game)
|
14
|
+
@game.start
|
15
|
+
@keypress_queue = []
|
16
|
+
create_gui
|
17
|
+
register_observers
|
18
|
+
end
|
19
|
+
|
20
|
+
def launch
|
21
|
+
@main_window.show
|
22
|
+
end
|
23
|
+
|
24
|
+
def register_observers
|
25
|
+
@game.height.times do |row|
|
26
|
+
@game.width.times do |column|
|
27
|
+
observe(@grid.cells[row][column], :color) do |new_color|
|
28
|
+
@cell_grid[row][column].fill = new_color
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
observe(@game, :over) do |game_over|
|
34
|
+
Glimmer::LibUI.queue_main do
|
35
|
+
if game_over
|
36
|
+
msg_box('Game Over!', "Score: #{@game.score} | High Score: #{@game.high_score}")
|
37
|
+
@game.start
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
43
|
+
unless @game.over?
|
44
|
+
process_queued_keypress
|
45
|
+
@game.snake.move
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def process_queued_keypress
|
51
|
+
# key press queue ensures one turn per snake move to avoid a double-turn resulting in instant death (due to snake illogically going back against itself)
|
52
|
+
key = @keypress_queue.shift
|
53
|
+
case [@game.snake.head.orientation, key]
|
54
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
55
|
+
@game.snake.turn_right
|
56
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
57
|
+
@game.snake.turn_left
|
58
|
+
else
|
59
|
+
# No Op
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_gui
|
64
|
+
@cell_grid = []
|
65
|
+
@main_window = window {
|
66
|
+
# data-bind window title to game score, converting it to a title string on read from the model
|
67
|
+
title <= [@game, :score, on_read: -> (score) {"Snake (Score: #{@game.score})"}]
|
68
|
+
content_size @game.width * CELL_SIZE, @game.height * CELL_SIZE
|
69
|
+
resizable false
|
70
|
+
|
71
|
+
vertical_box {
|
72
|
+
padded false
|
73
|
+
|
74
|
+
@game.height.times do |row|
|
75
|
+
@cell_grid << []
|
76
|
+
horizontal_box {
|
77
|
+
padded false
|
78
|
+
|
79
|
+
@game.width.times do |column|
|
80
|
+
area {
|
81
|
+
@cell_grid.last << square(0, 0, CELL_SIZE) {
|
82
|
+
fill Presenter::Cell::COLOR_CLEAR
|
83
|
+
}
|
84
|
+
|
85
|
+
on_key_up do |area_key_event|
|
86
|
+
@keypress_queue << area_key_event[:ext_key]
|
87
|
+
end
|
88
|
+
}
|
89
|
+
end
|
90
|
+
}
|
91
|
+
end
|
92
|
+
}
|
93
|
+
}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
Snake.new.launch
|
data/examples/tetris.rb
CHANGED
@@ -109,22 +109,23 @@ class Tetris
|
|
109
109
|
menu('Game') {
|
110
110
|
@pause_menu_item = check_menu_item('Pause') {
|
111
111
|
enabled false
|
112
|
-
|
113
|
-
on_clicked do
|
114
|
-
@game.paused = @pause_menu_item.checked?
|
115
|
-
end
|
112
|
+
checked <=> [@game, :paused]
|
116
113
|
}
|
114
|
+
|
117
115
|
menu_item('Restart') {
|
118
116
|
on_clicked do
|
119
117
|
@game.restart!
|
120
118
|
end
|
121
119
|
}
|
120
|
+
|
122
121
|
separator_menu_item
|
122
|
+
|
123
123
|
menu_item('Exit') {
|
124
124
|
on_clicked do
|
125
125
|
exit(0)
|
126
126
|
end
|
127
127
|
}
|
128
|
+
|
128
129
|
quit_menu_item if OS.mac?
|
129
130
|
}
|
130
131
|
|
@@ -134,6 +135,7 @@ class Tetris
|
|
134
135
|
show_high_scores
|
135
136
|
end
|
136
137
|
}
|
138
|
+
|
137
139
|
menu_item('Clear High Scores') {
|
138
140
|
on_clicked {
|
139
141
|
@game.clear_high_scores!
|
@@ -142,22 +144,16 @@ class Tetris
|
|
142
144
|
}
|
143
145
|
|
144
146
|
menu('Options') {
|
145
|
-
radio_menu_item('Instant Down on Up Arrow') {
|
146
|
-
|
147
|
-
@game.instant_down_on_up = true
|
148
|
-
end
|
147
|
+
radio_menu_item('Instant Down on Up Arrow') { |r|
|
148
|
+
checked <=> [@game, :instant_down_on_up]
|
149
149
|
}
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
150
|
+
|
151
|
+
radio_menu_item('Rotate Right on Up Arrow') { |r|
|
152
|
+
checked <=> [@game, :rotate_right_on_up]
|
154
153
|
}
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
on_clicked do
|
159
|
-
@game.rotate_left_on_up = true
|
160
|
-
end
|
154
|
+
|
155
|
+
radio_menu_item('Rotate Left on Up Arrow') { |r|
|
156
|
+
checked <=> [@game, :rotate_left_on_up]
|
161
157
|
}
|
162
158
|
}
|
163
159
|
|
@@ -169,6 +165,7 @@ class Tetris
|
|
169
165
|
end
|
170
166
|
}
|
171
167
|
end
|
168
|
+
|
172
169
|
menu_item('About') {
|
173
170
|
on_clicked do
|
174
171
|
show_about_dialog
|
data/examples/tic_tac_toe.rb
CHANGED
@@ -41,6 +41,7 @@ class TicTacToe
|
|
41
41
|
text(23, 19) {
|
42
42
|
string {
|
43
43
|
font family: 'Arial', size: OS.mac? ? 20 : 16
|
44
|
+
# data-bind string property of area text attributed string to tic tac toe board cell sign
|
44
45
|
string <= [@tic_tac_toe_board[row + 1, column + 1], :sign] # board model is 1-based
|
45
46
|
}
|
46
47
|
}
|
@@ -0,0 +1,84 @@
|
|
1
|
+
|
2
|
+
require 'glimmer-dsl-libui'
|
3
|
+
|
4
|
+
require_relative "tic_tac_toe/board"
|
5
|
+
|
6
|
+
class TicTacToe
|
7
|
+
include Glimmer
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@tic_tac_toe_board = Board.new
|
11
|
+
end
|
12
|
+
|
13
|
+
def launch
|
14
|
+
create_gui
|
15
|
+
register_observers
|
16
|
+
@main_window.show
|
17
|
+
end
|
18
|
+
|
19
|
+
def register_observers
|
20
|
+
observe(@tic_tac_toe_board, :game_status) do |game_status|
|
21
|
+
display_win_message if game_status == Board::WIN
|
22
|
+
display_draw_message if game_status == Board::DRAW
|
23
|
+
end
|
24
|
+
|
25
|
+
3.times.map do |row|
|
26
|
+
3.times.map do |column|
|
27
|
+
observe(@tic_tac_toe_board[row + 1, column + 1], :sign) do |sign| # board model is 1-based
|
28
|
+
@cells[row][column].string = sign
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_gui
|
35
|
+
@main_window = window('Tic-Tac-Toe', 180, 180) {
|
36
|
+
resizable false
|
37
|
+
|
38
|
+
@cells = []
|
39
|
+
vertical_box {
|
40
|
+
padded false
|
41
|
+
|
42
|
+
3.times.map do |row|
|
43
|
+
@cells << []
|
44
|
+
horizontal_box {
|
45
|
+
padded false
|
46
|
+
|
47
|
+
3.times.map do |column|
|
48
|
+
area {
|
49
|
+
square(0, 0, 60) {
|
50
|
+
stroke :black, thickness: 2
|
51
|
+
}
|
52
|
+
text(23, 19) {
|
53
|
+
@cells[row] << string('') {
|
54
|
+
font family: 'Arial', size: OS.mac? ? 20 : 16
|
55
|
+
}
|
56
|
+
}
|
57
|
+
on_mouse_up do
|
58
|
+
@tic_tac_toe_board.mark(row + 1, column + 1) # board model is 1-based
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
}
|
63
|
+
end
|
64
|
+
}
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
def display_win_message
|
69
|
+
display_game_over_message("Player #{@tic_tac_toe_board.winning_sign} has won!")
|
70
|
+
end
|
71
|
+
|
72
|
+
def display_draw_message
|
73
|
+
display_game_over_message("Draw!")
|
74
|
+
end
|
75
|
+
|
76
|
+
def display_game_over_message(message_text)
|
77
|
+
Glimmer::LibUI.queue_main do
|
78
|
+
msg_box('Game Over', message_text)
|
79
|
+
@tic_tac_toe_board.reset!
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
TicTacToe.new.launch
|
data/glimmer-dsl-libui.gemspec
CHANGED
Binary file
|
@@ -29,6 +29,10 @@ module Glimmer
|
|
29
29
|
# Follows the Proxy Design Pattern
|
30
30
|
class CheckboxProxy < ControlProxy
|
31
31
|
DEFAULT_TEXT = ''
|
32
|
+
|
33
|
+
def data_bind_write(property, model_binding)
|
34
|
+
handle_listener('on_toggled') { model_binding.call(checked) } if property == 'checked'
|
35
|
+
end
|
32
36
|
|
33
37
|
private
|
34
38
|
|