reight 0.1.2

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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/release-gem.yml +62 -0
  3. data/.github/workflows/tag.yml +35 -0
  4. data/.github/workflows/test.yml +37 -0
  5. data/.github/workflows/utils.rb +56 -0
  6. data/.gitignore +1 -0
  7. data/ChangeLog.md +23 -0
  8. data/Gemfile +6 -0
  9. data/LICENSE +21 -0
  10. data/README.md +62 -0
  11. data/Rakefile +30 -0
  12. data/VERSION +1 -0
  13. data/bin/r8 +35 -0
  14. data/lib/reight/all.rb +59 -0
  15. data/lib/reight/app/map/brush.rb +27 -0
  16. data/lib/reight/app/map/brush_base.rb +54 -0
  17. data/lib/reight/app/map/canvas.rb +150 -0
  18. data/lib/reight/app/map/chips.rb +84 -0
  19. data/lib/reight/app/map/editor.rb +117 -0
  20. data/lib/reight/app/map/line.rb +35 -0
  21. data/lib/reight/app/map/rect.rb +29 -0
  22. data/lib/reight/app/map/tool.rb +32 -0
  23. data/lib/reight/app/map.rb +8 -0
  24. data/lib/reight/app/music/editor.rb +25 -0
  25. data/lib/reight/app/music.rb +1 -0
  26. data/lib/reight/app/navigator.rb +172 -0
  27. data/lib/reight/app/runner.rb +275 -0
  28. data/lib/reight/app/sound/editor.rb +25 -0
  29. data/lib/reight/app/sound.rb +1 -0
  30. data/lib/reight/app/sprite/brush.rb +43 -0
  31. data/lib/reight/app/sprite/canvas.rb +254 -0
  32. data/lib/reight/app/sprite/chips.rb +92 -0
  33. data/lib/reight/app/sprite/color.rb +30 -0
  34. data/lib/reight/app/sprite/editor.rb +272 -0
  35. data/lib/reight/app/sprite/fill.rb +45 -0
  36. data/lib/reight/app/sprite/line.rb +37 -0
  37. data/lib/reight/app/sprite/select.rb +58 -0
  38. data/lib/reight/app/sprite/shape.rb +43 -0
  39. data/lib/reight/app/sprite/tool.rb +27 -0
  40. data/lib/reight/app/sprite.rb +10 -0
  41. data/lib/reight/app.rb +123 -0
  42. data/lib/reight/button.rb +93 -0
  43. data/lib/reight/chip.rb +150 -0
  44. data/lib/reight/extension.rb +24 -0
  45. data/lib/reight/helpers.rb +69 -0
  46. data/lib/reight/history.rb +135 -0
  47. data/lib/reight/map.rb +264 -0
  48. data/lib/reight/project.rb +115 -0
  49. data/lib/reight/reight.rb +83 -0
  50. data/lib/reight.rb +18 -0
  51. data/reight.gemspec +40 -0
  52. data/res/icons.png +0 -0
  53. data/test/helper.rb +15 -0
  54. data/test/test_chip.rb +108 -0
  55. data/test/test_chip_list.rb +68 -0
  56. data/test/test_map.rb +232 -0
  57. data/test/test_map_chunk.rb +226 -0
  58. metadata +244 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 86f61ce22f69d112815dcccd0800f21f73183c45bc26a8aef3818dfae72cb556
4
+ data.tar.gz: 4f6ec4c31e86ec0007454fb7e2b4d1c40b8e952671f69347fd429d0e7906deca
5
+ SHA512:
6
+ metadata.gz: 21497433b9c5736683a9ca12db7ed8d728325005b1ca2002e30d619ea97fd7f97c0bc677dd8cab0ed28af8d45aed684e70e83cc1d681f641b4c5077dbe7ccda1
7
+ data.tar.gz: ac2d9d3adbca86a3f18bc1d3a141465dd7787abff61f6ad17ffdb411385448d39b01141961f2ce7f673957f59620cc078d05240833ff5eb781df518decdba6fb
@@ -0,0 +1,62 @@
1
+ name: Release Gem
2
+
3
+ on:
4
+ push:
5
+ tags: ['v[0-9]*']
6
+
7
+ jobs:
8
+ release:
9
+ runs-on: macos-latest
10
+
11
+ steps:
12
+ - name: ruby 3.2
13
+ uses: ruby/setup-ruby@v1
14
+ with:
15
+ ruby-version: 3.2
16
+
17
+ - name: checkout
18
+ uses: actions/checkout@v4
19
+
20
+ - name: setup gems
21
+ run: bundle install
22
+
23
+ - name: setup dependencies
24
+ run: "ruby -I.github/workflows -rutils -e 'setup_dependencies'"
25
+
26
+ - name: test
27
+ run: bundle exec rake quiet packages test
28
+
29
+ - name: create gem
30
+ id: gem
31
+ run: |
32
+ bundle exec rake gem
33
+ echo path=$(ruby -e 'print Dir.glob("*.gem").first') >> $GITHUB_OUTPUT
34
+
35
+ - name: create github release
36
+ id: release
37
+ uses: actions/create-release@v1
38
+ env:
39
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
40
+ with:
41
+ tag_name: ${{ github.ref }}
42
+ release_name: ${{ github.ref }}
43
+
44
+ - name: upload to github release
45
+ uses: actions/upload-release-asset@v1
46
+ env:
47
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
48
+ with:
49
+ upload_url: ${{ steps.release.outputs.upload_url }}
50
+ asset_path: ./${{ steps.gem.outputs.path }}
51
+ asset_name: ${{ steps.gem.outputs.path }}
52
+ asset_content_type: application/zip
53
+
54
+ - name: upload to rubygems
55
+ env:
56
+ GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_AUTH_TOKEN }}
57
+ run: |
58
+ mkdir -p $HOME/.gem
59
+ touch $HOME/.gem/credentials
60
+ chmod 0600 $HOME/.gem/credentials
61
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
62
+ bundle exec rake upload
@@ -0,0 +1,35 @@
1
+ name: Tag
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+
7
+ jobs:
8
+ tag:
9
+ runs-on: ubuntu-latest
10
+
11
+ steps:
12
+ - name: ruby 3.2
13
+ uses: ruby/setup-ruby@v1
14
+ with:
15
+ ruby-version: 3.2
16
+
17
+ - name: checkout
18
+ uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 0
21
+ token: ${{ secrets.PAT }}
22
+
23
+ - name: setup dependencies
24
+ run: "ruby -I.github/workflows -rutils -e 'setup_dependencies only: :xot'"
25
+
26
+ - name: setup user name and email
27
+ run: |
28
+ git config --global user.email "xordog@gmail.com"
29
+ git config --global user.name "xord"
30
+
31
+ - name: tag versions
32
+ run: "ruby -I.github/workflows -rutils -e 'tag_versions'"
33
+
34
+ - name: push tags
35
+ run: git push origin --tags
@@ -0,0 +1,37 @@
1
+ name: Test
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: macos-latest
11
+
12
+ steps:
13
+ - name: ruby 3.2
14
+ uses: ruby/setup-ruby@v1
15
+ with:
16
+ ruby-version: 3.2
17
+
18
+ - name: checkout
19
+ uses: actions/checkout@v4
20
+
21
+ - name: setup gems
22
+ run: bundle install
23
+
24
+ - name: setup dependencies
25
+ run: "ruby -I.github/workflows -rutils -e 'setup_dependencies'"
26
+
27
+ - name: packages
28
+ run: bundle exec rake packages
29
+
30
+ - name: lib
31
+ run: bundle exec rake lib
32
+
33
+ - name: ext
34
+ run: bundle exec rake ext
35
+
36
+ - name: test
37
+ run: bundle exec rake test
@@ -0,0 +1,56 @@
1
+ RENAMES = {reflex: 'reflexion'}
2
+
3
+ def sh(cmd)
4
+ puts cmd
5
+ system cmd
6
+ end
7
+
8
+ def setup_dependencies(build: true, only: nil)
9
+ gemspec_path = `git ls-files`.lines(chomp: true).find {|l| l =~ /\.gemspec$/}
10
+ return unless gemspec_path
11
+
12
+ gemspec = File.read gemspec_path
13
+ name = File.basename gemspec_path, '.gemspec'
14
+
15
+ exts = File.readlines('Rakefile')
16
+ .map {|l| l[%r|^\s*require\W+(\w+)/extension\W+$|, 1]}
17
+ .compact
18
+ .reject {|ext| ext == name}
19
+ exts = exts & [only].flatten.map(&:to_s) if only
20
+
21
+ exts.each do |ext|
22
+ gem = RENAMES[ext.to_sym].then {|s| s || ext}
23
+ ver = gemspec[/add_dependency.*['"]#{gem}['"].*['"]\s*>=\s*([\d\.]+)\s*['"]/, 1]
24
+ opts = '-c advice.detachedHead=false --depth 1'
25
+ clone = "git clone #{opts} https://github.com/xord/#{ext}.git ../#{ext}"
26
+
27
+ # 'rake subtree:push' pushes all subrepos, so cloning by new tag
28
+ # often fails before tagging each new tag
29
+ sh %( #{clone} --branch v#{ver} || #{clone} )
30
+ sh %( cd ../#{ext} && rake ext )
31
+ end
32
+ end
33
+
34
+ def tag_versions()
35
+ tags = `git tag`.lines chomp: true
36
+ vers = `git log --oneline ./VERSION`
37
+ .lines(chomp: true)
38
+ .map {|line| line.split.first[/^\w+$/]}
39
+ .map {|hash| [`git cat-file -p #{hash}:./VERSION 2>/dev/null`[/[\d\.]+/], hash]}
40
+ .select {|ver, hash| ver && hash}
41
+ .reverse
42
+ .to_h
43
+
44
+ changes = File.read('ChangeLog.md')
45
+ .split(/^\s*##\s*\[\s*v([\d\.]+)\s*\].*$/)
46
+ .slice(1..-1)
47
+ .each_slice(2)
48
+ .to_h
49
+ .transform_values(&:strip!)
50
+
51
+ vers.to_a.reverse.each do |ver, hash|
52
+ tag = "v#{ver}"
53
+ break if tags.include?(tag)
54
+ sh %( git tag -a -m \"#{changes[ver]&.gsub '"', '\\"'}\" #{tag} #{hash} )
55
+ end
56
+ end
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *~
data/ChangeLog.md ADDED
@@ -0,0 +1,23 @@
1
+ # reight ChangeLog
2
+
3
+
4
+ ## [v0.1.2] - 2025-01-14
5
+
6
+ - User can change the file name of user scripts
7
+ - Rename from 'bin/r8.rb' to 'bin/r8'
8
+ - Change the file/directory structure of the source code
9
+ - Update icon images
10
+ - Update workflow files
11
+ - Set minumum version for runtime dependency
12
+
13
+ - Fix an error on first launch
14
+
15
+
16
+ ## [v0.1.1] - 2025-01-13
17
+
18
+ - Update README.md
19
+
20
+
21
+ ## [v0.1] - 2025-01-13
22
+
23
+ - Alpha version
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'rexml'
4
+ gem 'rake'
5
+ gem 'test-unit'
6
+ gem 'yard'
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 xord.org
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,62 @@
1
+
2
+ # Reight - A Retro Game Engine for Ruby
3
+
4
+ Reight is an open-source Ruby library inspired by the powerful [Processing](https://processing.org/) API, designed to make creative coding accessible and enjoyable for everyone. With support for both Mac and Windows, this library brings the joy of visual programming to Ruby developers.
5
+
6
+ ## Features
7
+
8
+ - **Processing API Compatibility**: Leverage the well-known Processing API to create stunning visuals, animations, and interactive applications using Ruby.
9
+ - **Cross-Platform**: Works seamlessly on both macOS and Windows environments.
10
+ - **Ruby-Powered**: Enjoy the elegance and simplicity of Ruby while crafting creative projects.
11
+ - **Extensible and Open**: Modify and extend the library to fit your unique needs.
12
+
13
+ ## Installation
14
+
15
+ Install the gem via RubyGems:
16
+
17
+ ```bash
18
+ gem install reight
19
+ ```
20
+
21
+ Or add it to your Gemfile:
22
+
23
+ ```ruby
24
+ gem 'reight'
25
+ ```
26
+
27
+ Then run:
28
+
29
+ ```bash
30
+ bundle install
31
+ ```
32
+
33
+ ## Getting Started
34
+
35
+ Here’s a simple example to get you started:
36
+
37
+ ```ruby
38
+ # Create a window and draw something
39
+ draw do
40
+ background 0
41
+ $sprites ||= project.maps.first.map(&:to_sprite)
42
+ sprite $sprites
43
+ end
44
+ ```
45
+
46
+ Run the script and watch your window come to life!
47
+
48
+ ```
49
+ $ bundle exec r8 .
50
+ ```
51
+
52
+ ## Documentation
53
+
54
+ Comprehensive documentation and guides can be found [here](https://www.rubydoc.info/gems/reight/0.1/index).
55
+
56
+ ## License
57
+
58
+ This project is licensed under the [MIT License](LICENSE).
59
+
60
+ ---
61
+
62
+ Happy coding with Ruby and Processing!
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ # -*- mode: ruby -*-
2
+
3
+ %w[../xot ../rucy ../beeps ../rays ../reflex ../processing ../rubysketch .]
4
+ .map {|s| File.expand_path "#{s}/lib", __dir__}
5
+ .each {|s| $:.unshift s if !$:.include?(s) && File.directory?(s)}
6
+
7
+ require 'xot/rake'
8
+
9
+ require 'xot/extension'
10
+ require 'rucy/extension'
11
+ require 'beeps/extension'
12
+ require 'rays/extension'
13
+ require 'reflex/extension'
14
+ require 'processing/extension'
15
+ require 'rubysketch/extension'
16
+ require 'reight/extension'
17
+
18
+
19
+ EXTENSIONS = [Xot, Rucy, Beeps, Rays, Reflex, Processing, RubySketch, Reight]
20
+
21
+ default_tasks
22
+ test_ruby_extension
23
+ build_ruby_gem
24
+
25
+
26
+ task :run do
27
+ libs = %w[xot rucy beeps rays reflex processing rubysketch]
28
+ .map {|lib| "-I#{ENV['ALL']}/#{lib}/lib"}
29
+ sh %( ruby #{libs.join ' '} -Ilib bin/r8 '#{ENV["path"] || "."}' )
30
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.2
data/bin/r8 ADDED
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'reight'
4
+ using Reight
5
+
6
+
7
+ def r8 = $r8__
8
+
9
+ def usage()
10
+ <<~END
11
+ USAGE: r8 [path]
12
+ END
13
+ end
14
+
15
+ Reight::CONTEXT__.tap do |c|
16
+ path = ARGV.shift or return puts usage
17
+ path = File.expant_path path, Dir.pwd if path.start_with?('/')
18
+ c.setup {Reight::R8.new(path).setup}
19
+ c.draw {r8.draw}
20
+ c.key_pressed {r8.key_pressed}
21
+ c.key_released {r8.key_released}
22
+ c.key_typed {r8.key_typed}
23
+ c.mouse_pressed {r8.mouse_pressed}
24
+ c.mouse_released {r8.mouse_released}
25
+ c.mouse_moved {r8.mouse_moved}
26
+ c.mouse_dragged {r8.mouse_dragged}
27
+ c.mouse_clicked {r8.mouse_clicked}
28
+ c.double_clicked {r8.double_clicked}
29
+ c.mouse_wheel {r8.mouse_wheel}
30
+ c.touch_started {r8.touch_started}
31
+ c.touch_ended {r8.touch_ended}
32
+ c.touch_moved {r8.touch_moved}
33
+ c.window_moved {r8.window_moved}
34
+ c.window_resized {r8.window_resized}
35
+ end
data/lib/reight/all.rb ADDED
@@ -0,0 +1,59 @@
1
+ module Reight
2
+ def self.to_snake_case(camel_case_names)
3
+ camel_case_names.map(&:to_s)
4
+ .map {[_1, _1.gsub(/([a-z])([A-Z])/) {"#{$1}_#{$2.downcase}"}]}
5
+ end
6
+
7
+ # alias snake_case methods
8
+ [Processing, RubySketch]
9
+ .map {|mod| mod.constants.map {mod.const_get _1}}
10
+ .flatten
11
+ .select {_1.class == Module || _1.class == Class}
12
+ .each do |klass|
13
+ Reight.to_snake_case(klass.instance_methods false)
14
+ .reject {|camel, snake| camel =~ /__$/}
15
+ .reject {|camel, snake| klass.method_defined? snake}
16
+ .each {|camel, snake| klass.alias_method snake, camel}
17
+ end
18
+
19
+ w = (ENV['WIDTH'] || 500).to_i
20
+ h = (ENV['HEIGHT'] || 500).to_i
21
+ WINDOW__ = Processing::Window.new(w, h) {start}
22
+ CONTEXT__ = RubySketch::Context.new WINDOW__
23
+
24
+ excludes = Reight.to_snake_case(%i[
25
+ setup draw
26
+ keyPressed keyReleased keyTyped
27
+ mousePressed mouseReleased mouseMoved mouseDragged
28
+ mouseClicked doubleClicked mouseWheel
29
+ touchStarted touchEnded touchMoved
30
+ windowMoved windowResized motion
31
+ ]).flatten.uniq
32
+ refine Object do
33
+ (CONTEXT__.methods - Object.instance_methods - excludes)
34
+ .reject {_1 =~ /__$/} # methods for internal use
35
+ .each do |method|
36
+ define_method(method) do |*args, **kwargs, &block|
37
+ CONTEXT__.__send__(method, *args, **kwargs, &block)
38
+ end
39
+ end
40
+ end
41
+ end# Reight
42
+
43
+
44
+ require 'reight/extension'
45
+ require 'reight/helpers'
46
+ require 'reight/project'
47
+ require 'reight/history'
48
+ require 'reight/button'
49
+
50
+ require 'reight/reight'
51
+ require 'reight/chip'
52
+ require 'reight/map'
53
+ require 'reight/app'
54
+ require 'reight/app/navigator'
55
+ require 'reight/app/runner'
56
+ require 'reight/app/sprite'
57
+ require 'reight/app/map'
58
+ require 'reight/app/sound'
59
+ require 'reight/app/music'
@@ -0,0 +1,27 @@
1
+ using Reight
2
+
3
+
4
+ class Reight::MapEditor::Brush < Reight::MapEditor::BrushBase
5
+
6
+ def initialize(app, &block)
7
+ super app, icon: app.icon(1, 2, 8), &block
8
+ set_help left: name, right: 'Pick Chip'
9
+ end
10
+
11
+ def brush(cursor_from, cursor_to, chip)
12
+ x, y, = cursor_to
13
+ put_or_delete_chip x, y, chip
14
+ false
15
+ end
16
+
17
+ def canvas_pressed(...)
18
+ canvas.begin_editing
19
+ super
20
+ end
21
+
22
+ def canvas_released(...)
23
+ super
24
+ canvas.end_editing
25
+ end
26
+
27
+ end# Brush
@@ -0,0 +1,54 @@
1
+ using Reight
2
+
3
+
4
+ class Reight::MapEditor::BrushBase < Reight::MapEditor::Tool
5
+
6
+ def brush(cursor_from, cursor_to, chip) = nil
7
+
8
+ def put_or_delete_chip(x, y, chip)
9
+ return false unless x && y && chip
10
+ m = canvas.map
11
+ return false if !@deleting && m[x, y]&.id == chip.id
12
+
13
+ result = false
14
+ m.each_chip x, y, chip.w, chip.h do |ch|
15
+ m.delete_chip ch
16
+ result |= history.append [:delete_chip, ch.pos.x, ch.pos.y, ch.id]
17
+ end
18
+ unless @deleting
19
+ m.put x, y, chip
20
+ result |= history.append [:put_chip, x, y, chip.id]
21
+ end
22
+ result
23
+ end
24
+
25
+ def canvas_pressed(x, y, button)
26
+ return unless button == LEFT
27
+ @cursor_from, @deleting = canvas.cursor.dup, chips.chip.empty?
28
+ @undo_prev = brush @cursor_from, canvas.cursor, chips.chip
29
+ end
30
+
31
+ def canvas_released(x, y, button)
32
+ return unless button == LEFT
33
+ end
34
+
35
+ def canvas_moved(x, y)
36
+ update_cursor x, y
37
+ end
38
+
39
+ def canvas_dragged(x, y, button)
40
+ update_cursor x, y
41
+ return unless button == LEFT
42
+ app.undo flash: false if @undo_prev
43
+ @undo_prev = brush @cursor_from, canvas.cursor, chips.chip
44
+ end
45
+
46
+ def canvas_clicked(x, y, button)
47
+ pick_chip x, y if button == RIGHT
48
+ end
49
+
50
+ def update_cursor(x, y)
51
+ canvas.set_cursor x, y, chips.size, chips.size
52
+ end
53
+
54
+ end# BrushBase
@@ -0,0 +1,150 @@
1
+ using Reight
2
+
3
+
4
+ class Reight::MapEditor::Canvas
5
+
6
+ include Reight::Hookable
7
+
8
+ def initialize(app, map, path)
9
+ hook :tool_changed
10
+
11
+ @app, @map, @path = app, map, path
12
+ @x, @y, @tool, @cursor = 0, 0, nil, nil, nil
13
+ end
14
+
15
+ attr_accessor :x, :y
16
+
17
+ attr_reader :map, :tool, :cursor
18
+
19
+ def save()
20
+ @app.project.save
21
+ end
22
+
23
+ def tool=(tool)
24
+ @tool = tool
25
+ tool_changed! tool
26
+ end
27
+
28
+ def set_cursor(x, y, w, h)
29
+ @cursor = correct_bounds x, y, w, h
30
+ end
31
+
32
+ def chip_at_cursor()
33
+ x, y, = cursor
34
+ map[@x + x, @y + y]
35
+ end
36
+
37
+ def begin_editing(&block)
38
+ @app.history.begin_grouping
39
+ block.call if block
40
+ ensure
41
+ end_editing if block
42
+ end
43
+
44
+ def end_editing()
45
+ @app.history.end_grouping
46
+ save
47
+ end
48
+
49
+ def sprite()
50
+ @sprite ||= Sprite.new.tap do |sp|
51
+ pos = -> {to_image sp.mouse_x, sp.mouse_y}
52
+ sp.draw {draw}
53
+ sp.mouse_pressed {mouse_pressed( *pos.call, sp.mouse_button)}
54
+ sp.mouse_released {mouse_released(*pos.call, sp.mouse_button)}
55
+ sp.mouse_moved {mouse_moved( *pos.call)}
56
+ sp.mouse_dragged {mouse_dragged( *pos.call, sp.mouse_button)}
57
+ sp.mouse_clicked {mouse_clicked( *pos.call, sp.mouse_button)}
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def to_image(x, y)
64
+ return x, y unless @x && @y
65
+ return x - @x, y - @y
66
+ end
67
+
68
+ def correct_bounds(x, y, w, h)
69
+ x, y, w, h = [x, y, w, h].map &:to_i
70
+ return x / w * w, y / h * h, w, h
71
+ end
72
+
73
+ def draw()
74
+ sp = sprite
75
+
76
+ clip sp.x, sp.y, sp.w, sp.h
77
+ translate @x, @y
78
+
79
+ fill 0, 0, 0
80
+ no_stroke
81
+ rect(-@x, -@y, sp.w, sp.h)
82
+
83
+ draw_grids
84
+
85
+ map.each_chip(-@x, -@y, sp.w, sp.h, clip_by_chunk: true).each do |chip|
86
+ pos = chip.pos
87
+ copy chip.image, *chip.frame, pos.x, pos.y, chip.w, chip.h
88
+ end
89
+
90
+ if @cursor
91
+ no_fill
92
+ stroke 255, 255, 255
93
+ stroke_weight 1
94
+ rect(*@cursor)
95
+ end
96
+ end
97
+
98
+ def draw_grids()
99
+ push do
100
+ app = Reight::App
101
+ sw, sh = app::SCREEN_WIDTH, app::SCREEN_HEIGHT
102
+ mw, mh = sw * 10, sh * 10
103
+ stroke 20
104
+ shape grid 8, 8, mw, mh if @app.pressing?(SPACE)
105
+ stroke 50
106
+ shape grid sw / 2, sh / 2, mw, mh
107
+ stroke 100
108
+ shape grid sw, sh, mw, mh
109
+ end
110
+ end
111
+
112
+ def grid(xinterval, yinterval, xmax, ymax)
113
+ (@grids ||= {})[xinterval] ||= create_shape.tap do |sh|
114
+ sh.begin_shape LINES
115
+ (0..xmax).step(xinterval).each do |x|
116
+ sh.vertex x, 0
117
+ sh.vertex x, ymax
118
+ end
119
+ (0..ymax).step(yinterval).each do |y|
120
+ sh.vertex 0, y
121
+ sh.vertex xmax, y
122
+ end
123
+ sh.end_shape
124
+ end
125
+ end
126
+
127
+ def mouse_pressed(...)
128
+ tool&.canvas_pressed(...) unless hand?
129
+ end
130
+
131
+ def mouse_released(...)
132
+ tool&.canvas_released(...) unless hand?
133
+ end
134
+
135
+ def mouse_dragged(...)
136
+ if hand?
137
+ sp = sprite
138
+ @x += sp.mouse_x - sp.pmouse_x
139
+ @y += sp.mouse_y - sp.pmouse_y
140
+ else
141
+ tool&.canvas_dragged(...)
142
+ end
143
+ end
144
+
145
+ def mouse_moved(...) = tool&.canvas_moved(...)
146
+ def mouse_clicked(...) = tool&.canvas_clicked(...)
147
+
148
+ def hand? = @app.pressing?(SPACE)
149
+
150
+ end# Canvas