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
@@ -0,0 +1,190 @@
|
|
1
|
+
using Reight
|
2
|
+
|
3
|
+
|
4
|
+
class Reight::SoundEditor::Canvas
|
5
|
+
|
6
|
+
include Reight::Hookable
|
7
|
+
|
8
|
+
SEQUENCE_LEN = 32
|
9
|
+
NOTE_HEIGHT = 3
|
10
|
+
|
11
|
+
def initialize(app)
|
12
|
+
hook :sound_changed
|
13
|
+
|
14
|
+
@app, @sound = app, app.project.sounds.first
|
15
|
+
@scrolly = NOTE_HEIGHT * Reight::Sound::Note::MAX / 3
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :tone, :tool
|
19
|
+
|
20
|
+
attr_reader :sound
|
21
|
+
|
22
|
+
def sound=(sound)
|
23
|
+
@sound = sound
|
24
|
+
sound_changed! sound
|
25
|
+
end
|
26
|
+
|
27
|
+
def save()
|
28
|
+
@app.project.save
|
29
|
+
end
|
30
|
+
|
31
|
+
def begin_editing(&block)
|
32
|
+
@app.history.begin_grouping
|
33
|
+
block.call if block
|
34
|
+
ensure
|
35
|
+
end_editing if block
|
36
|
+
end
|
37
|
+
|
38
|
+
def end_editing()
|
39
|
+
@app.history.end_grouping
|
40
|
+
save
|
41
|
+
end
|
42
|
+
|
43
|
+
def note_pos_at(x, y)
|
44
|
+
sp = sprite
|
45
|
+
notew = sp.w / SEQUENCE_LEN
|
46
|
+
max = Reight::Sound::Note::MAX
|
47
|
+
time_index = (x / notew).floor
|
48
|
+
note_index = max - ((@scrolly + y) / NOTE_HEIGHT).floor
|
49
|
+
return time_index, note_index.clamp(0, max)
|
50
|
+
end
|
51
|
+
|
52
|
+
def put(x, y)
|
53
|
+
time_i, note_i = note_pos_at x, y
|
54
|
+
|
55
|
+
@sound.each_note(time_index: time_i)
|
56
|
+
.select {|note,| (note.index == note_i) != (note.tone == tone)}
|
57
|
+
.each {|note,| remove_note time_i, note.index, note.tone}
|
58
|
+
add_note time_i, note_i, tone
|
59
|
+
|
60
|
+
@app.flash note_name y
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete(x, y)
|
64
|
+
time_i, note_i = note_pos_at x, y
|
65
|
+
note = @sound.at time_i, note_i
|
66
|
+
return unless note
|
67
|
+
|
68
|
+
remove_note time_i, note_i, note.tone
|
69
|
+
|
70
|
+
@app.flash note_name y
|
71
|
+
end
|
72
|
+
|
73
|
+
def sprite()
|
74
|
+
@sprite ||= RubySketch::Sprite.new.tap do |sp|
|
75
|
+
pos = -> {return sp.mouse_x, sp.mouse_y}
|
76
|
+
sp.draw {draw}
|
77
|
+
sp.mouse_pressed {mouse_pressed( *pos.call, sp.mouse_button)}
|
78
|
+
sp.mouse_released {mouse_released(*pos.call, sp.mouse_button)}
|
79
|
+
sp.mouse_moved {mouse_moved( *pos.call)}
|
80
|
+
sp.mouse_dragged {mouse_dragged( *pos.call, sp.mouse_button)}
|
81
|
+
sp.mouse_clicked {mouse_clicked( *pos.call, sp.mouse_button)}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def add_note(ti, ni, tone)
|
88
|
+
return if @sound.at(ti, ni)&.tone == tone
|
89
|
+
@sound.add ti, ni, tone
|
90
|
+
@sound.at(ti, ni)&.play 120
|
91
|
+
@app.history.append [:put_note, ti, ni, tone]
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_note(ti, ni, tone)
|
95
|
+
#@sound.at(ti, ni)&.play @sound.bpm
|
96
|
+
@sound.remove ti, ni
|
97
|
+
@app.history.append [:delete_note, ti, ni, tone]
|
98
|
+
end
|
99
|
+
|
100
|
+
def draw()
|
101
|
+
sp = sprite
|
102
|
+
clip sp.x, sp.y, sp.w, sp.h
|
103
|
+
|
104
|
+
no_stroke
|
105
|
+
fill 0
|
106
|
+
rect 0, 0, sp.w, sp.h
|
107
|
+
|
108
|
+
translate 0, -@scrolly
|
109
|
+
draw_grids
|
110
|
+
draw_notes
|
111
|
+
draw_note_names
|
112
|
+
end
|
113
|
+
|
114
|
+
TONE_COLORS = {
|
115
|
+
sine: 5,
|
116
|
+
triangle: 29,
|
117
|
+
square: 19,
|
118
|
+
sawtooth: 30,
|
119
|
+
pulse12_5: 27,
|
120
|
+
pulse25: 14,
|
121
|
+
noise: 12
|
122
|
+
}.transform_values {Reight::App::PALETTE_COLORS[_1]}
|
123
|
+
|
124
|
+
GRID_COLORS = [1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1]
|
125
|
+
.map.with_index {|n, i| i == 0 ? 100 : (n == 1 ? 80 : 60)}
|
126
|
+
|
127
|
+
def draw_grids()
|
128
|
+
sp = sprite
|
129
|
+
noteh = NOTE_HEIGHT
|
130
|
+
Reight::Sound::Note::MAX.downto(0).with_index do |y, index|
|
131
|
+
fill GRID_COLORS[index % GRID_COLORS.size]
|
132
|
+
rect 0, y * noteh, sp.w, noteh
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def draw_notes()
|
137
|
+
sp = sprite
|
138
|
+
notew, noteh = sp.w / SEQUENCE_LEN, NOTE_HEIGHT
|
139
|
+
tones, max = Reight::Sound::Note::TONES, Reight::Sound::Note::MAX
|
140
|
+
@sound.each_note do |note, index|
|
141
|
+
fill TONE_COLORS[note.tone]
|
142
|
+
rect index * notew, (max - note.index) * noteh, notew, noteh
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def draw_note_names()
|
147
|
+
fill 200
|
148
|
+
text_size 4
|
149
|
+
text_align LEFT, CENTER
|
150
|
+
noteh = NOTE_HEIGHT
|
151
|
+
max = Reight::Sound::Note::MAX
|
152
|
+
(0..Reight::Sound::Note::MAX).step(12).with_index do |y, index|
|
153
|
+
text "C#{index}", 2, (max - y) * noteh, 10, noteh
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def mouse_pressed(...)
|
158
|
+
tool&.canvas_pressed(...) unless hand?
|
159
|
+
end
|
160
|
+
|
161
|
+
def mouse_released(...)
|
162
|
+
tool&.canvas_released(...) unless hand?
|
163
|
+
end
|
164
|
+
|
165
|
+
def mouse_moved(x, y)
|
166
|
+
tool&.canvas_moved(x, y)
|
167
|
+
@app.flash note_name y
|
168
|
+
end
|
169
|
+
|
170
|
+
def mouse_dragged(...)
|
171
|
+
if hand?
|
172
|
+
sp = sprite
|
173
|
+
@scrolly -= sp.mouse_y - sp.pmouse_y
|
174
|
+
else
|
175
|
+
tool&.canvas_dragged(...)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def mouse_clicked(...)
|
180
|
+
tool&.canvas_clicked(...) unless hand?
|
181
|
+
end
|
182
|
+
|
183
|
+
def hand? = @app.pressing?(SPACE)
|
184
|
+
|
185
|
+
def note_name(y)
|
186
|
+
_, note_i = note_pos_at 0, y
|
187
|
+
Reight::Sound::Note.new(note_i).to_s.split(':').first.capitalize
|
188
|
+
end
|
189
|
+
|
190
|
+
end# Canvas
|
@@ -3,23 +3,183 @@ using Reight
|
|
3
3
|
|
4
4
|
class Reight::SoundEditor < Reight::App
|
5
5
|
|
6
|
+
def canvas()
|
7
|
+
@canvas ||= Canvas.new self
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup()
|
11
|
+
super
|
12
|
+
history.disable do
|
13
|
+
tones[0].click
|
14
|
+
tools[0].click
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
6
18
|
def draw()
|
7
19
|
background 200
|
20
|
+
sprite(*sprites)
|
21
|
+
super
|
22
|
+
end
|
8
23
|
|
9
|
-
|
10
|
-
|
24
|
+
def key_pressed()
|
25
|
+
super
|
26
|
+
case key_code
|
27
|
+
when ENTER then play_or_stop.click
|
28
|
+
when :b then brush.click
|
29
|
+
when :e then eraser.click
|
30
|
+
when /^[#{(1..Reight::Sound::Note::TONES.size).to_a.join}]$/
|
31
|
+
tones[key_code.to_s.to_i - 1].click
|
32
|
+
end
|
33
|
+
end
|
11
34
|
|
12
|
-
|
13
|
-
|
14
|
-
|
35
|
+
def window_resized()
|
36
|
+
super
|
37
|
+
index.sprite.tap do |sp|
|
38
|
+
sp.w, sp.h = 32, BUTTON_SIZE
|
39
|
+
sp.x = SPACE
|
40
|
+
sp.y = NAVIGATOR_HEIGHT + SPACE
|
41
|
+
end
|
42
|
+
bpm.sprite.tap do |sp|
|
43
|
+
sp.w, sp.h = 40, BUTTON_SIZE
|
44
|
+
sp.x = index.sprite.right + SPACE
|
45
|
+
sp.y = index.sprite.y
|
46
|
+
end
|
47
|
+
edits.map(&:sprite).each.with_index do |sp, i|
|
48
|
+
sp.w, sp.h = 32, BUTTON_SIZE
|
49
|
+
sp.x = bpm.sprite.right + SPACE + (sp.w + 1) * i
|
50
|
+
sp.y = bpm.sprite.y
|
51
|
+
end
|
52
|
+
controls.map(&:sprite).each.with_index do |sp, i|
|
53
|
+
sp.w, sp.h = 32, BUTTON_SIZE
|
54
|
+
sp.x = SPACE + (sp.w + 1) * i
|
55
|
+
sp.y = height - (SPACE + sp.h)
|
56
|
+
end
|
57
|
+
tools.map(&:sprite).each.with_index do |sp, i|
|
58
|
+
sp.w = sp.h = BUTTON_SIZE
|
59
|
+
sp.x = controls.last.sprite.right + SPACE * 2 + (sp.w + 1) * i
|
60
|
+
sp.y = controls.last.sprite.y
|
61
|
+
end
|
62
|
+
tones.map(&:sprite).each.with_index do |sp, i|
|
63
|
+
sp.w = sp.h = BUTTON_SIZE
|
64
|
+
sp.x = tools.last.sprite.right + SPACE * 2 + (sp.w + 1) * i
|
65
|
+
sp.y = tools.last.sprite.y
|
66
|
+
end
|
67
|
+
canvas.sprite.tap do |sp|
|
68
|
+
sp.x = SPACE
|
69
|
+
sp.y = index.sprite.bottom + SPACE
|
70
|
+
sp.right = width - SPACE
|
71
|
+
sp.bottom = tools.first.sprite.y - SPACE
|
72
|
+
end
|
73
|
+
end
|
15
74
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
75
|
+
def undo(flash: true)
|
76
|
+
history.undo do |action|
|
77
|
+
case action
|
78
|
+
in [:put_note, ti, ni, _] then canvas.sound.remove ti, ni
|
79
|
+
in [:delete_note, ti, ni, tone] then canvas.sound.add ti, ni, tone
|
80
|
+
end
|
81
|
+
self.flash 'Undo!' if flash
|
20
82
|
end
|
83
|
+
end
|
21
84
|
|
22
|
-
|
85
|
+
def redo(flash: true)
|
86
|
+
history.redo do |action|
|
87
|
+
case action
|
88
|
+
in [:put_note, ti, ni, tone] then canvas.sound.add ti, ni, tone
|
89
|
+
in [:delete_note, ti, ni, _] then canvas.sound.remove ti, ni
|
90
|
+
end
|
91
|
+
self.flash 'Redo!' if flash
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def sprites()
|
98
|
+
[index, bpm, *edits, *controls, *tools, *tones, canvas]
|
99
|
+
.map(&:sprite) + super
|
100
|
+
end
|
101
|
+
|
102
|
+
def index()
|
103
|
+
@index ||= Reight::Index.new do |index|
|
104
|
+
canvas.sound = project.sounds[index] ||= Reight::Sound.new
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def bpm()
|
109
|
+
@bpm ||= Reight::Text.new(
|
110
|
+
canvas.sound.bpm, label: 'BPM ', regexp: /^\-?\d+$/, editable: true
|
111
|
+
) do |str, text|
|
112
|
+
bpm = str.to_i.clamp(0, Reight::Sound::BPM_MAX)
|
113
|
+
next text.revert if bpm <= 0
|
114
|
+
text.value = canvas.sound.bpm = bpm
|
115
|
+
canvas.save
|
116
|
+
end.tap do |text|
|
117
|
+
canvas.sound_changed {text.value = _1.bpm}
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def edits()
|
122
|
+
@edits ||= [
|
123
|
+
Reight::Button.new(name: 'Clear All Notes', label: 'Clear') {
|
124
|
+
canvas.sound.clear
|
125
|
+
canvas.save
|
126
|
+
},
|
127
|
+
Reight::Button.new(name: 'Delete Sound', label: 'Delete') {
|
128
|
+
project.sounds.delete_at index.index
|
129
|
+
canvas.sound = project.sounds[index.index] ||= Reight::Sound.new
|
130
|
+
canvas.save
|
131
|
+
},
|
132
|
+
]
|
133
|
+
end
|
134
|
+
|
135
|
+
def controls()
|
136
|
+
@controls ||= [play_or_stop]
|
137
|
+
end
|
138
|
+
|
139
|
+
def play_or_stop()
|
140
|
+
@play_or_stop ||= Reight::Button.new(name: 'Play Sound', label: 'Play') {|b|
|
141
|
+
played = -> {b.name, b.label = 'Stop Sound', 'Stop'}
|
142
|
+
stopped = -> {b.name, b.label = 'Play Sound', 'Play'}
|
143
|
+
if canvas.sound.playing?
|
144
|
+
canvas.sound.stop
|
145
|
+
stopped.call
|
146
|
+
else
|
147
|
+
canvas.sound.play {stopped.call}
|
148
|
+
played.call
|
149
|
+
end
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
def tools()
|
154
|
+
@tools ||= group brush, eraser
|
155
|
+
end
|
156
|
+
|
157
|
+
def brush = @brush ||= Brush.new(self) {canvas.tool = _1}
|
158
|
+
def eraser = @eraser ||= Eraser.new(self) {canvas.tool = _1}
|
159
|
+
|
160
|
+
def tones()
|
161
|
+
@tones ||= group(*Reight::Sound::Note::TONES.map.with_index {|tone, index|
|
162
|
+
name = tone.to_s.capitalize.gsub('_', '.')
|
163
|
+
name += ' Wave' if name !~ /noise/i
|
164
|
+
color = Canvas::TONE_COLORS[tone]
|
165
|
+
Reight::Button.new name: name, icon: icon(index, 3, 8) do
|
166
|
+
canvas.tone = tone
|
167
|
+
Reight::Sound::Note.new(60, tone).play 120 if active?
|
168
|
+
end.tap do |b|
|
169
|
+
b.instance_variable_set :@color, color
|
170
|
+
class << b
|
171
|
+
alias draw_ draw
|
172
|
+
def draw
|
173
|
+
draw_
|
174
|
+
no_fill
|
175
|
+
stroke @color
|
176
|
+
stroke_weight 1
|
177
|
+
w, h = sprite.width, sprite.height
|
178
|
+
line 3, h - 1, w - 3, h - 1
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
})
|
23
183
|
end
|
24
184
|
|
25
185
|
end# SoundEditor
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Reight::SoundEditor::Eraser < Reight::SoundEditor::Tool
|
2
|
+
|
3
|
+
def initialize(app, &block)
|
4
|
+
super app, icon: app.icon(3, 2, 8), &block
|
5
|
+
set_help left: name
|
6
|
+
end
|
7
|
+
|
8
|
+
def erase(x, y, button)
|
9
|
+
canvas.delete x, y
|
10
|
+
end
|
11
|
+
|
12
|
+
def canvas_pressed(x, y, button)
|
13
|
+
return unless button == LEFT
|
14
|
+
canvas.begin_editing
|
15
|
+
erase 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
|
+
erase x, y, button
|
26
|
+
end
|
27
|
+
|
28
|
+
end# Eraser
|
@@ -0,0 +1,29 @@
|
|
1
|
+
using Reight
|
2
|
+
|
3
|
+
|
4
|
+
class Reight::SoundEditor::Tool < Reight::Button
|
5
|
+
|
6
|
+
def initialize(app, *a, **k, &b)
|
7
|
+
super(*a, **k, &b)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :app
|
12
|
+
|
13
|
+
def canvas = app.canvas
|
14
|
+
|
15
|
+
def history = app.history
|
16
|
+
|
17
|
+
def name = self.class.name.split('::').last
|
18
|
+
|
19
|
+
def pick_tone(x, y)
|
20
|
+
canvas.tone = canvas.tone_at x, y
|
21
|
+
end
|
22
|
+
|
23
|
+
def canvas_pressed( x, y, button) = nil
|
24
|
+
def canvas_released(x, y, button) = nil
|
25
|
+
def canvas_moved( x, y) = nil
|
26
|
+
def canvas_dragged( x, y, button) = nil
|
27
|
+
def canvas_clicked( x, y, button) = nil
|
28
|
+
|
29
|
+
end# Tool
|
data/lib/reight/app/sound.rb
CHANGED
@@ -6,17 +6,21 @@ class Reight::SpriteEditor::Canvas
|
|
6
6
|
include Reight::Hookable
|
7
7
|
|
8
8
|
def initialize(app, image, path)
|
9
|
-
hook :
|
9
|
+
hook :frame_changed
|
10
|
+
hook :selection_changed
|
11
|
+
hook :color_changed
|
10
12
|
|
11
13
|
@app, @image, @path = app, image, path
|
12
|
-
@tool, @color, @selection = nil, [255, 255, 255], nil
|
14
|
+
@tool, @color, @selection = nil, [255, 255, 255, 255], nil
|
13
15
|
|
14
16
|
@app.history.disable do
|
15
17
|
set_frame 0, 0, 16, 16
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
|
-
|
21
|
+
attr_accessor :tool
|
22
|
+
|
23
|
+
attr_reader :x, :y, :w, :h, :color
|
20
24
|
|
21
25
|
def width = @image.width
|
22
26
|
|
@@ -27,17 +31,12 @@ class Reight::SpriteEditor::Canvas
|
|
27
31
|
@app.project.save
|
28
32
|
end
|
29
33
|
|
30
|
-
def tool=(tool)
|
31
|
-
@tool = tool
|
32
|
-
tool_changed! tool
|
33
|
-
end
|
34
|
-
|
35
34
|
def set_frame(x, y, w, h)
|
36
35
|
old = [@x, @y, @w, @h]
|
37
36
|
new = correct_bounds x, y, w, h
|
38
37
|
return if new == old
|
39
38
|
@x, @y, @w, @h = new
|
40
|
-
|
39
|
+
frame_changed! old, new
|
41
40
|
end
|
42
41
|
|
43
42
|
def frame = [x, y, w, h]
|
@@ -53,7 +52,7 @@ class Reight::SpriteEditor::Canvas
|
|
53
52
|
new = correct_bounds x, y, w, h
|
54
53
|
return if new == old
|
55
54
|
@selection = new
|
56
|
-
|
55
|
+
selection_changed! old, new
|
57
56
|
end
|
58
57
|
|
59
58
|
def selection()
|
@@ -68,7 +67,7 @@ class Reight::SpriteEditor::Canvas
|
|
68
67
|
def deselect()
|
69
68
|
return if @selection == nil
|
70
69
|
old, @selection = @selection, nil
|
71
|
-
|
70
|
+
selection_changed! old, nil
|
72
71
|
end
|
73
72
|
|
74
73
|
def paint(&block)
|
@@ -76,6 +75,7 @@ class Reight::SpriteEditor::Canvas
|
|
76
75
|
g.clip(*(selection || frame))
|
77
76
|
g.push do
|
78
77
|
g.translate x, y
|
78
|
+
g.blend_mode REPLACE
|
79
79
|
block.call g
|
80
80
|
end
|
81
81
|
end
|
@@ -85,24 +85,24 @@ class Reight::SpriteEditor::Canvas
|
|
85
85
|
tmp = sub_image x, y, w, h
|
86
86
|
tmp.update_pixels {|pixels| block.call pixels}
|
87
87
|
@image.begin_draw do |g|
|
88
|
-
g.
|
88
|
+
g.blend tmp, 0, 0, w, h, x, y, w, h, REPLACE
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
92
|
def sub_image(x, y, w, h)
|
93
93
|
create_graphics(w, h).tap do |g|
|
94
|
-
g.begin_draw {g.
|
94
|
+
g.begin_draw {g.blend @image, x, y, w, h, 0, 0, w, h, REPLACE}
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
98
|
def pixel_at(x, y)
|
99
|
-
img = sub_image x, y, 1, 1
|
99
|
+
img = sub_image self.x + x, self.y + y, 1, 1
|
100
100
|
img.load_pixels
|
101
101
|
c = img.pixels[0]
|
102
102
|
[red(c), green(c), blue(c), alpha(c)].map &:to_i
|
103
103
|
end
|
104
104
|
|
105
|
-
def clear(frame, color:
|
105
|
+
def clear(frame, color:)
|
106
106
|
paint do |g|
|
107
107
|
g.fill(*color)
|
108
108
|
g.no_stroke
|
@@ -127,7 +127,7 @@ class Reight::SpriteEditor::Canvas
|
|
127
127
|
x, y, w, h = frame
|
128
128
|
create_graphics(w, h).tap do |g|
|
129
129
|
g.begin_draw do
|
130
|
-
g.
|
130
|
+
g.blend @image, x, y, w, h, 0, 0, w, h, REPLACE
|
131
131
|
end
|
132
132
|
end
|
133
133
|
end
|
@@ -135,13 +135,13 @@ class Reight::SpriteEditor::Canvas
|
|
135
135
|
def apply_frame(image, x, y)
|
136
136
|
@image.begin_draw do |g|
|
137
137
|
w, h = image.width, image.height
|
138
|
-
g.
|
138
|
+
g.blend image, 0, 0, w, h, x, y, w, h, REPLACE
|
139
139
|
end
|
140
140
|
save
|
141
141
|
end
|
142
142
|
|
143
143
|
def sprite()
|
144
|
-
@sprite ||= Sprite.new.tap do |sp|
|
144
|
+
@sprite ||= RubySketch::Sprite.new.tap do |sp|
|
145
145
|
pos = -> {to_image sp.mouse_x, sp.mouse_y}
|
146
146
|
sp.draw {draw}
|
147
147
|
sp.mouse_pressed {tool&.canvas_pressed( *pos.call, sp.mouse_button)}
|
@@ -171,6 +171,11 @@ class Reight::SpriteEditor::Canvas
|
|
171
171
|
def draw()
|
172
172
|
sp = sprite
|
173
173
|
clip sp.x, sp.y, sp.w, sp.h
|
174
|
+
|
175
|
+
fill 0
|
176
|
+
no_stroke
|
177
|
+
rect 0, 0, sp.w, sp.h
|
178
|
+
|
174
179
|
copy @image, x, y, w, h, 0, 0, sp.w, sp.h if @image && x && y && w && h
|
175
180
|
|
176
181
|
sx, sy = sp.w / w, sp.h / h
|
@@ -4,8 +4,9 @@ using Reight
|
|
4
4
|
class Reight::SpriteEditor::Color < Reight::Button
|
5
5
|
|
6
6
|
def initialize(color, &clicked)
|
7
|
-
super name:
|
7
|
+
super name: color[0, 3].map {_1.to_s(16).upcase}.join, &clicked
|
8
8
|
@color = color
|
9
|
+
set_help name: "##{name}"
|
9
10
|
end
|
10
11
|
|
11
12
|
attr_reader :color
|
@@ -15,6 +16,7 @@ class Reight::SpriteEditor::Color < Reight::Button
|
|
15
16
|
|
16
17
|
fill(*color)
|
17
18
|
no_stroke
|
19
|
+
blend_mode REPLACE
|
18
20
|
rect 0, 0, sp.w, sp.h
|
19
21
|
|
20
22
|
if active?
|