glimmer-dsl-libui 0.4.6 → 0.4.10
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|