reight 0.1.6 → 0.1.8
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/.github/PULL_REQUEST_TEMPLATE.md +12 -0
- data/CONTRIBUTING.md +7 -0
- data/ChangeLog.md +76 -0
- data/README.md +6 -5
- data/Rakefile +5 -2
- data/VERSION +1 -1
- data/bin/r8 +18 -8
- data/lib/reight/all.rb +7 -2
- data/lib/reight/app/chips.rb +124 -0
- data/lib/reight/app/map/brush.rb +1 -1
- data/lib/reight/app/map/brush_base.rb +3 -3
- data/lib/reight/app/map/canvas.rb +10 -15
- data/lib/reight/app/map/editor.rb +44 -17
- data/lib/reight/app/map/line.rb +5 -5
- data/lib/reight/app/map/rect.rb +2 -2
- data/lib/reight/app/map.rb +0 -1
- data/lib/reight/app/navigator.rb +33 -47
- data/lib/reight/app/runner.rb +123 -86
- data/lib/reight/app/sound/brush.rb +32 -0
- data/lib/reight/app/sound/canvas.rb +190 -0
- data/lib/reight/app/sound/editor.rb +170 -10
- data/lib/reight/app/sound/eraser.rb +28 -0
- data/lib/reight/app/sound/tool.rb +29 -0
- data/lib/reight/app/sound.rb +4 -0
- data/lib/reight/app/sprite/canvas.rb +23 -18
- data/lib/reight/app/sprite/color.rb +3 -1
- data/lib/reight/app/sprite/editor.rb +58 -47
- data/lib/reight/app/sprite/line.rb +1 -1
- data/lib/reight/app/sprite/shape.rb +1 -1
- data/lib/reight/app/sprite.rb +0 -1
- data/lib/reight/app.rb +24 -5
- data/lib/reight/button.rb +10 -7
- data/lib/reight/chip.rb +32 -6
- data/lib/reight/context.rb +168 -0
- data/lib/reight/helpers.rb +2 -2
- data/lib/reight/index.rb +87 -0
- data/lib/reight/map.rb +141 -11
- data/lib/reight/project.rb +45 -6
- data/lib/reight/reight.rb +11 -15
- data/lib/reight/sound.rb +238 -0
- data/lib/reight/sprite.rb +42 -0
- data/lib/reight/text.rb +124 -0
- data/lib/reight.rb +7 -3
- data/reight.gemspec +7 -7
- data/res/icons.png +0 -0
- data/test/helper.rb +16 -0
- data/test/test_map.rb +7 -7
- data/test/test_map_chunk.rb +6 -6
- data/test/test_sprite.rb +28 -0
- metadata +42 -32
- data/lib/reight/app/map/chips.rb +0 -84
- data/lib/reight/app/music/editor.rb +0 -25
- data/lib/reight/app/music.rb +0 -1
- data/lib/reight/app/sprite/chips.rb +0 -92
data/lib/reight/app/navigator.rb
CHANGED
@@ -32,14 +32,15 @@ class Reight::Navigator
|
|
32
32
|
|
33
33
|
def key_pressed()
|
34
34
|
index = [F1, F2, F3, F4, F5].index(key_code)
|
35
|
-
app_buttons[index]
|
35
|
+
app_buttons[index]&.click if index
|
36
36
|
end
|
37
37
|
|
38
38
|
def window_resized()
|
39
|
-
[app_buttons, history_buttons, edit_buttons]
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
[app_buttons, history_buttons, edit_buttons]
|
40
|
+
.flatten.map(&:sprite).each do |sp|
|
41
|
+
sp.w = sp.h = Reight::App::NAVIGATOR_HEIGHT
|
42
|
+
sp.y = 0
|
43
|
+
end
|
43
44
|
|
44
45
|
space = Reight::App::SPACE
|
45
46
|
x = space
|
@@ -47,20 +48,23 @@ class Reight::Navigator
|
|
47
48
|
app_buttons.map {_1.sprite}.each do |sp|
|
48
49
|
sp.x = x + 1
|
49
50
|
x = sp.right
|
51
|
+
end.tap do
|
52
|
+
x += space unless _1.empty?
|
50
53
|
end
|
51
|
-
x += space
|
52
54
|
|
53
55
|
history_buttons.map {_1.sprite}.each do |sp|
|
54
56
|
sp.x = x + 1
|
55
57
|
x = sp.right
|
58
|
+
end.tap do
|
59
|
+
x += space unless _1.empty?
|
56
60
|
end
|
57
|
-
x += space unless history_buttons.empty?
|
58
61
|
|
59
62
|
edit_buttons.map {_1.sprite}.each do |sp|
|
60
63
|
sp.x = x + 1
|
61
64
|
x = sp.right
|
65
|
+
end.tap do
|
66
|
+
x += space unless _1.empty?
|
62
67
|
end
|
63
|
-
x += space unless edit_buttons.empty?
|
64
68
|
|
65
69
|
message.sprite.tap do |sp|
|
66
70
|
sp.x = x + space
|
@@ -73,72 +77,54 @@ class Reight::Navigator
|
|
73
77
|
private
|
74
78
|
|
75
79
|
def app_buttons()
|
76
|
-
@app_buttons ||=
|
77
|
-
Reight::Button.new(name:
|
78
|
-
|
79
|
-
}
|
80
|
-
|
81
|
-
switch_app Reight::SpriteEditor
|
82
|
-
},
|
83
|
-
Reight::Button.new(name: 'Map Editor', icon: @app.icon(2, 0, 8)) {
|
84
|
-
switch_app Reight::MapEditor
|
85
|
-
},
|
86
|
-
Reight::Button.new(name: 'Sound Editor', icon: @app.icon(3, 0, 8)) {
|
87
|
-
switch_app Reight::SoundEditor
|
88
|
-
},
|
89
|
-
Reight::Button.new(name: 'Music Editor', icon: @app.icon(4, 0, 8)) {
|
90
|
-
switch_app Reight::MusicEditor
|
91
|
-
},
|
92
|
-
]
|
80
|
+
@app_buttons ||= r8.apps.map.with_index {|app, index|
|
81
|
+
Reight::Button.new(name: app.label, icon: app.icon(index, 0, 8)) {
|
82
|
+
r8.current = app
|
83
|
+
}
|
84
|
+
}
|
93
85
|
end
|
94
86
|
|
95
87
|
def history_buttons()
|
96
|
-
@history_buttons ||=
|
97
|
-
|
88
|
+
@history_buttons ||= [].tap do |buttons|
|
89
|
+
next unless @app.respond_to? :undo
|
90
|
+
buttons << Reight::Button.new(name: 'Undo', icon: @app.icon(3, 1, 8)) {
|
98
91
|
@app.undo flash: false
|
99
92
|
}.tap {|b|
|
100
93
|
b.enabled? {@app.history.can_undo?}
|
101
|
-
}
|
102
|
-
Reight::Button.new(name: 'Redo', icon: @app.icon(4, 1, 8)) {
|
94
|
+
}
|
95
|
+
buttons << Reight::Button.new(name: 'Redo', icon: @app.icon(4, 1, 8)) {
|
103
96
|
@app.redo flash: false
|
104
97
|
}.tap {|b|
|
105
98
|
b.enabled? {@app.history.can_redo?}
|
106
99
|
}
|
107
|
-
|
100
|
+
end
|
108
101
|
end
|
109
102
|
|
110
103
|
def edit_buttons()
|
111
|
-
@edit_buttons ||=
|
112
|
-
|
104
|
+
@edit_buttons ||= [].tap do |buttons|
|
105
|
+
next unless @app.respond_to? :paste
|
106
|
+
buttons << Reight::Button.new(name: 'Cut', icon: @app.icon(0, 1, 8)) {
|
113
107
|
@app.cut flash: false
|
114
108
|
}.tap {|b|
|
115
109
|
b.enabled? {@app.can_cut?}
|
116
|
-
}
|
117
|
-
Reight::Button.new(name: 'Copy', icon: @app.icon(1, 1, 8)) {
|
110
|
+
}
|
111
|
+
buttons << Reight::Button.new(name: 'Copy', icon: @app.icon(1, 1, 8)) {
|
118
112
|
@app.copy flash: false
|
119
113
|
}.tap {|b|
|
120
114
|
b.enabled? {@app.can_copy?}
|
121
|
-
}
|
122
|
-
Reight::Button.new(name: 'Paste', icon: @app.icon(2, 1, 8)) {
|
115
|
+
}
|
116
|
+
buttons << Reight::Button.new(name: 'Paste', icon: @app.icon(2, 1, 8)) {
|
123
117
|
@app.paste flash: false
|
124
118
|
}.tap {|b|
|
125
119
|
b.enabled? {@app.can_paste?}
|
126
|
-
}
|
127
|
-
|
120
|
+
}
|
121
|
+
end
|
128
122
|
end
|
129
123
|
|
130
|
-
def history_buttons? = @app.respond_to? :undo
|
131
|
-
def edit_buttons? = @app.respond_to? :cut
|
132
|
-
|
133
124
|
def message()
|
134
125
|
@message ||= Message.new
|
135
126
|
end
|
136
127
|
|
137
|
-
def switch_app(klass)
|
138
|
-
app = r8.apps.find {_1.class == klass}
|
139
|
-
r8.current = app if app
|
140
|
-
end
|
141
|
-
|
142
128
|
end# Navigator
|
143
129
|
|
144
130
|
|
@@ -159,7 +145,7 @@ class Reight::Navigator::Message
|
|
159
145
|
end
|
160
146
|
|
161
147
|
def sprite()
|
162
|
-
@sprite ||= Sprite.new.tap do |sp|
|
148
|
+
@sprite ||= RubySketch::Sprite.new.tap do |sp|
|
163
149
|
sp.draw do
|
164
150
|
next unless @text
|
165
151
|
fill 100
|
data/lib/reight/app/runner.rb
CHANGED
@@ -1,117 +1,148 @@
|
|
1
|
-
|
1
|
+
class Reight::Runner < Reight::App
|
2
2
|
|
3
|
+
include Xot::Inspectable
|
3
4
|
|
4
|
-
|
5
|
+
ROOT_CONTEXT = Reight::CONTEXT__
|
5
6
|
|
6
7
|
TEMPORARY_HASH = {}
|
7
8
|
|
9
|
+
def label = 'Run'
|
10
|
+
|
11
|
+
def setup()
|
12
|
+
navigator.visible = false
|
13
|
+
end
|
14
|
+
|
8
15
|
def activated()
|
9
|
-
super
|
10
16
|
run force: true
|
11
|
-
@context.call_activated__
|
17
|
+
@context.call_activated__ {|&b| call_event(ignore_pause: true, &b)}
|
18
|
+
super
|
12
19
|
end
|
13
20
|
|
14
21
|
def deactivated()
|
15
22
|
super
|
16
|
-
@context.call_deactivated__
|
23
|
+
@context.call_deactivated__ {|&b| call_event(ignore_pause: true, &b)}
|
17
24
|
pause
|
25
|
+
cleanup
|
18
26
|
end
|
19
27
|
|
20
28
|
def draw()
|
21
|
-
|
22
|
-
|
29
|
+
return unless @context
|
30
|
+
@initial_resize ||= true.tap do
|
31
|
+
call_event {@context.size ROOT_CONTEXT.width, ROOT_CONTEXT.height}
|
32
|
+
end
|
33
|
+
@context.call_draw__ {|push: true, &b| call_event(push: push, &b)}
|
34
|
+
if canvasFrame = @context.canvasFrame__
|
35
|
+
ROOT_CONTEXT.background 0
|
36
|
+
ROOT_CONTEXT.image @context, *canvasFrame
|
37
|
+
else
|
38
|
+
ROOT_CONTEXT.image @context, 0, 0
|
23
39
|
end
|
24
40
|
super
|
25
41
|
end
|
26
42
|
|
27
43
|
def key_pressed()
|
28
44
|
super
|
29
|
-
@context
|
45
|
+
call_event {@context.key_pressed}
|
30
46
|
end
|
31
47
|
|
32
48
|
def key_released()
|
33
49
|
super
|
34
|
-
@context
|
50
|
+
call_event {@context.key_released}
|
35
51
|
end
|
36
52
|
|
37
53
|
def key_typed()
|
38
54
|
super
|
39
|
-
@context
|
55
|
+
call_event {@context.key_typed}
|
40
56
|
end
|
41
57
|
|
42
58
|
def mouse_pressed()
|
43
59
|
super
|
44
|
-
@context
|
60
|
+
call_event {@context.mouse_pressed}
|
45
61
|
end
|
46
62
|
|
47
63
|
def mouse_released()
|
48
64
|
super
|
49
|
-
@context
|
65
|
+
call_event {@context.mouse_released}
|
50
66
|
end
|
51
67
|
|
52
68
|
def mouse_moved()
|
53
69
|
super
|
54
|
-
|
55
|
-
|
70
|
+
navigator.visible = ROOT_CONTEXT.mouse_y < NAVIGATOR_HEIGHT if r8.edit?
|
71
|
+
call_event {@context.mouse_moved}
|
56
72
|
end
|
57
73
|
|
58
74
|
def mouse_dragged()
|
59
75
|
super
|
60
|
-
@context
|
76
|
+
call_event {@context.mouse_dragged}
|
61
77
|
end
|
62
78
|
|
63
79
|
def mouse_clicked()
|
64
80
|
super
|
65
|
-
@context
|
81
|
+
call_event {@context.mouse_clicked}
|
66
82
|
end
|
67
83
|
|
68
84
|
def double_clicked()
|
69
85
|
super
|
70
|
-
@context
|
86
|
+
call_event {@context.double_clicked}
|
71
87
|
end
|
72
88
|
|
73
89
|
def mouse_wheel()
|
74
90
|
super
|
75
|
-
@context
|
91
|
+
call_event {@context.mouse_wheel}
|
76
92
|
end
|
77
93
|
|
78
94
|
def touch_started()
|
79
95
|
super
|
80
|
-
@context
|
96
|
+
call_event {@context.touch_started}
|
81
97
|
end
|
82
98
|
|
83
99
|
def touch_ended()
|
84
100
|
super
|
85
|
-
@context
|
101
|
+
call_event {@context.touch_ended}
|
86
102
|
end
|
87
103
|
|
88
104
|
def touch_moved()
|
89
105
|
super
|
90
|
-
@context
|
106
|
+
call_event {@context.touch_moved}
|
91
107
|
end
|
92
108
|
|
93
109
|
def window_moved()
|
94
110
|
super
|
95
|
-
@context
|
111
|
+
call_event(ignore_pause: true) {@context.window_moved}
|
96
112
|
end
|
97
113
|
|
98
114
|
def window_resized()
|
99
115
|
super
|
100
|
-
@context
|
116
|
+
call_event(ignore_pause: true) {@context.window_resized}
|
101
117
|
end
|
102
118
|
|
103
119
|
private
|
104
120
|
|
121
|
+
def call_event(push: true, ignore_pause: false, &block)
|
122
|
+
if @context
|
123
|
+
@context.beginDraw__
|
124
|
+
@context.push if push
|
125
|
+
block.call unless paused?
|
126
|
+
end
|
127
|
+
rescue ScriptError, StandardError => e
|
128
|
+
puts e.full_message
|
129
|
+
ensure
|
130
|
+
if @context
|
131
|
+
@context.pop if push
|
132
|
+
@context.endDraw__
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
105
136
|
def running? = @context && !@paused
|
106
137
|
|
107
138
|
def paused? = @context && @paused
|
108
139
|
|
109
140
|
def run(force: false)
|
110
141
|
return pause false if paused? && !force
|
111
|
-
cleanup
|
112
142
|
backup_global_vars
|
113
143
|
@context = create_context
|
114
144
|
@paused = false
|
145
|
+
Processing::Context.setContext__ @context
|
115
146
|
begin_wrapping_user_classes @context
|
116
147
|
eval_user_script @context, project.code_paths.zip(project.codes).to_h
|
117
148
|
end
|
@@ -121,9 +152,12 @@ class Reight::Runner < Reight::App
|
|
121
152
|
end
|
122
153
|
|
123
154
|
def cleanup()
|
124
|
-
remove_world @context.
|
155
|
+
ROOT_CONTEXT.remove_world @context.spriteWorld__ if @context
|
156
|
+
Processing::Context.setContext__ nil
|
125
157
|
@context = nil
|
126
158
|
end_wrapping_user_classes
|
159
|
+
clear_all_timers
|
160
|
+
project.clear_all_sprites
|
127
161
|
restore_global_vars
|
128
162
|
GC.enable
|
129
163
|
GC.start
|
@@ -131,55 +165,56 @@ class Reight::Runner < Reight::App
|
|
131
165
|
|
132
166
|
def create_context()
|
133
167
|
klass = Class.new do
|
134
|
-
|
168
|
+
include Reight::Context
|
135
169
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
139
|
-
add_world sprite_world__
|
140
|
-
activated
|
170
|
+
def call_activated__(&caller)
|
171
|
+
add_world spriteWorld__
|
172
|
+
caller.call {activated}
|
141
173
|
end
|
142
174
|
|
143
|
-
def call_deactivated__()
|
144
|
-
deactivated
|
145
|
-
remove_world
|
175
|
+
def call_deactivated__(&caller)
|
176
|
+
caller.call {deactivated}
|
177
|
+
remove_world spriteWorld__
|
146
178
|
@background_cleared__ = false
|
147
179
|
end
|
148
180
|
|
149
|
-
def call_draw__()
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
154
|
-
unless @background_cleared__
|
155
|
-
@background_cleared__ = true
|
156
|
-
background 100, 100, 100
|
157
|
-
end
|
158
|
-
draw
|
181
|
+
def call_draw__(&caller)
|
182
|
+
@setup_done__ ||= true.tap {caller.call(push: false) {setup}}
|
183
|
+
@background_cleared__ ||= true.tap {caller.call {background 100}}
|
184
|
+
caller.call {draw}
|
159
185
|
end
|
160
186
|
|
161
|
-
def
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
187
|
+
def inspect()
|
188
|
+
"#<#{self.class.name}:0x#{object_id}>"
|
189
|
+
end
|
190
|
+
|
191
|
+
methods = (instance_methods - Object.instance_methods)
|
192
|
+
.reject {_1.end_with? '__'}
|
193
|
+
Processing.to_snake_case__(methods).each do |camel, snake|
|
194
|
+
alias_method snake, camel if snake != camel
|
195
|
+
end
|
196
|
+
|
197
|
+
Processing.to_snake_case__(
|
198
|
+
%i[activated deactivated] + Processing::EVENT_NAMES__
|
199
|
+
).each do |camel, snake|
|
200
|
+
class_eval <<~END
|
201
|
+
def #{camel}(&block)
|
202
|
+
if block
|
203
|
+
@#{camel}_block__ = block
|
204
|
+
else
|
205
|
+
@#{camel}_block__&.call
|
206
|
+
end
|
175
207
|
end
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
208
|
+
END
|
209
|
+
alias_method snake, camel if snake != camel
|
210
|
+
end
|
211
|
+
|
212
|
+
Processing.funcs__(ROOT_CONTEXT).each do |func|
|
213
|
+
next if method_defined? func
|
214
|
+
define_method(func) {|*a, **k, &b| ROOT_CONTEXT.__send__ func, *a, **k, &b}
|
215
|
+
end
|
182
216
|
end
|
217
|
+
klass.new(ROOT_CONTEXT, project)
|
183
218
|
end
|
184
219
|
|
185
220
|
def begin_wrapping_user_classes(context)
|
@@ -207,27 +242,17 @@ class Reight::Runner < Reight::App
|
|
207
242
|
|
208
243
|
def create_user_class_wrapper(context)
|
209
244
|
Module.new.tap do |wrapper|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
klass.define_method(name) {|*a, **k, &b| context.public_send name, *a, **k, &b}
|
221
|
-
context.public_send name, *args, **kwargs, &block
|
222
|
-
else
|
223
|
-
super name, *args, **kwargs, &block
|
245
|
+
wrapper.define_method :respond_to_missing? do |name, include_private = false|
|
246
|
+
context.respond_to?(name, false) || super(name, include_private)
|
247
|
+
end
|
248
|
+
wrapper.define_method :method_missing do |name, *args, **kwargs, &block|
|
249
|
+
if context.respond_to? name
|
250
|
+
wrapper.define_method(name) {|*a, **k, &b| context.public_send name, *a, **k, &b}
|
251
|
+
context.public_send name, *args, **kwargs, &block
|
252
|
+
else
|
253
|
+
super name, *args, **kwargs, &block
|
254
|
+
end
|
224
255
|
end
|
225
|
-
end
|
226
|
-
Processing.to_snake_case__(%i[
|
227
|
-
project createSprite addSprite removeSprite gravity
|
228
|
-
]).each do |camel, snake|
|
229
|
-
klass.define_method(camel) {|*a, **k, &b| context.public_send camel, *a, **k, &b}
|
230
|
-
klass.alias_method snake, camel if snake != camel
|
231
256
|
end
|
232
257
|
end
|
233
258
|
|
@@ -237,19 +262,23 @@ class Reight::Runner < Reight::App
|
|
237
262
|
::Reight::Runner::TEMPORARY_HASH[:params] => {context:, codes:}
|
238
263
|
codes.each {|path, code| context.instance_eval code, path if code}
|
239
264
|
END
|
265
|
+
rescue ScriptError, StandardError => e
|
266
|
+
puts e.full_message
|
240
267
|
ensure
|
241
268
|
TEMPORARY_HASH.delete :params
|
242
269
|
end
|
243
270
|
|
271
|
+
EXCLUDE_GLOBAL_VARS = [:$FILENAME]
|
272
|
+
|
244
273
|
def backup_global_vars()
|
245
|
-
@global_vars = global_variables
|
274
|
+
@global_vars = (global_variables - EXCLUDE_GLOBAL_VARS)
|
246
275
|
.each.with_object({}) {|name, hash| hash[name] = eval name.to_s}
|
247
276
|
.freeze
|
248
277
|
end
|
249
278
|
|
250
279
|
def restore_global_vars()
|
251
280
|
return unless @global_vars
|
252
|
-
global_variables
|
281
|
+
(global_variables - EXCLUDE_GLOBAL_VARS)
|
253
282
|
.map {|name| [name, eval(name.to_s)]}
|
254
283
|
.select {|name, value| value != nil && @global_vars[name] == nil}
|
255
284
|
.each {|name, value| global_var_set name, nil}
|
@@ -267,4 +296,12 @@ class Reight::Runner < Reight::App
|
|
267
296
|
TEMPORARY_HASH.delete :value
|
268
297
|
end
|
269
298
|
|
299
|
+
def clear_all_timers()
|
300
|
+
prefix = Reight::Context::TIMER_PREFIX__
|
301
|
+
ROOT_CONTEXT.instance_eval do
|
302
|
+
@timers__ .delete_if {|id| id in [prefix, _]}
|
303
|
+
@firingTimers__.delete_if {|id| id in [prefix, _]}
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
270
307
|
end# Runner
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Reight::SoundEditor::Brush < Reight::SoundEditor::Tool
|
2
|
+
|
3
|
+
def initialize(app, &block)
|
4
|
+
super app, icon: app.icon(1, 2, 8), &block
|
5
|
+
set_help left: name, right: 'Pick Tone'
|
6
|
+
end
|
7
|
+
|
8
|
+
def brush(x, y, button)
|
9
|
+
canvas.put x, y
|
10
|
+
end
|
11
|
+
|
12
|
+
def canvas_pressed(x, y, button)
|
13
|
+
return unless button == LEFT
|
14
|
+
canvas.begin_editing
|
15
|
+
brush x, y, button
|
16
|
+
end
|
17
|
+
|
18
|
+
def canvas_released(x, y, button)
|
19
|
+
return unless button == LEFT
|
20
|
+
canvas.end_editing
|
21
|
+
end
|
22
|
+
|
23
|
+
def canvas_dragged(x, y, button)
|
24
|
+
return unless button == LEFT
|
25
|
+
brush x, y, button
|
26
|
+
end
|
27
|
+
|
28
|
+
def canvas_clicked(x, y, button)
|
29
|
+
pick_tone x, y if button == RIGHT
|
30
|
+
end
|
31
|
+
|
32
|
+
end# Brush
|