trtl 0.0.1 → 0.1.0
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 +7 -0
- data/LICENSE.md +1 -1
- data/README.md +35 -13
- data/examples/example2.rb +1 -1
- data/lib/trtl/canvas.rb +273 -0
- data/lib/trtl/colors.rb +188 -0
- data/lib/trtl.rb +28 -24
- metadata +29 -26
- data/.gitignore +0 -4
- data/Gemfile +0 -4
- data/Rakefile +0 -5
- data/test/helper.rb +0 -3
- data/test/test_trtl.rb +0 -64
- data/trtl.gemspec +0 -20
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 9dfd21924c3f6626d0b10b91df30b90dce0f8adce0c861fd6adda1fbf0bac6c1
|
|
4
|
+
data.tar.gz: fbcc9c05df13cb1109aff89f30b2e8932eaef3e04f70a157c27ea9e61c6bd9f2
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: f7a6013033c7c941e35e796d44181f69bae075866248203eaee8ab29e814f8bc1106e11ab46265fa6bcb65b290aea7e89bcdc11ca009b8b90f047580280a4d88
|
|
7
|
+
data.tar.gz: 94f13a513d82e4b182accc6eae2eea70d52ade1b44364d80acd0657e585d607d689f300cc654fc564f9bb935dac9d6311181b671b7a55d145c3b4cf3b38e8b6d
|
data/LICENSE.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2012 Peter Cooper
|
|
1
|
+
Copyright (c) 2012-2026 Peter Cooper
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
4
|
|
data/README.md
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
# Trtl - Simple Ruby Turtle Graphics
|
|
2
2
|
|
|
3
|
-
!
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> Trtl originally drew its graphics with Tk, which shipped with Ruby until Ruby 2.4 moved it out of the standard library and into a separate `tk` gem. That gem has to be compiled against a Tcl/Tk installation, which made Trtl a pain to set up, particularly on macOS. In 2026, Trtl was ported to [LibUI](https://github.com/kojix2/LibUI), whose gem includes a precompiled native library for macOS, Windows and Linux, so on most systems `gem install` is all it takes.
|
|
4
5
|
|
|
5
6
|
## Installation
|
|
7
|
+
|
|
6
8
|
gem install trtl
|
|
7
9
|
|
|
8
10
|
## Description
|
|
9
11
|
|
|
10
|
-
Trtl is a simple turtle system inspired by Python's turtle.py. It provides
|
|
11
|
-
simple turtle drawing capabilities in Ruby, even if you're just at an IRb
|
|
12
|
-
prompt. It leans on Tk which is part of MRI 1.9's standard library so in theory it should
|
|
13
|
-
work 'out of the box' with most MRI 1.9 installs.
|
|
12
|
+
Trtl is a simple 'turtle' system inspired by Python's turtle.py. It provides simple turtle drawing capabilities in Ruby, even if you're just at an IRB prompt. It draws using [LibUI](https://github.com/kojix2/LibUI).
|
|
14
13
|
|
|
15
14
|
## Usage
|
|
16
15
|
|
|
17
|
-
If Trtl detects you're in an
|
|
16
|
+
If Trtl detects you're in an IRB or Pry session, it'll automatically make turtle
|
|
18
17
|
methods available directly at the prompt. For example:
|
|
19
18
|
|
|
20
19
|
$ irb
|
|
@@ -28,35 +27,58 @@ can create a Trtl instance and use it directly:
|
|
|
28
27
|
require 'trtl'
|
|
29
28
|
t = Trtl.new
|
|
30
29
|
10.times { t.left(24); t.forward(30); t.ensure_drawn }
|
|
31
|
-
t.wait
|
|
30
|
+
t.wait # keeps the window open until it's closed or Enter is pressed
|
|
32
31
|
|
|
33
32
|
You can use Trtl's `run` method to use it in a more interactive fashion:
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
Trtl.new.run { 10.times { left(24); forward(30); ensure_drawn }; wait }
|
|
36
35
|
|
|
37
36
|
Or you can include InteractiveTurtle and get a similar effect as if you were in
|
|
38
|
-
|
|
37
|
+
IRB:
|
|
39
38
|
|
|
40
39
|
include InteractiveTurtle
|
|
41
40
|
10.times { left(24); forward(30) }
|
|
41
|
+
wait
|
|
42
42
|
|
|
43
43
|
Note: Using InteractiveTurtle makes drawing slower as it ensures all graphics
|
|
44
|
-
are drawn after every action (as necessary for
|
|
44
|
+
are drawn after every action (as necessary for IRB use).
|
|
45
|
+
|
|
46
|
+
## Commands
|
|
47
|
+
|
|
48
|
+
Only a small number of commands are currently implemented, but they're enough for the major actions:
|
|
49
|
+
|
|
50
|
+
* `title(title_name)`
|
|
51
|
+
* `forward(distance)` - aliased as `fd`
|
|
52
|
+
* `back(distance)` - aliased as `bk` and `backward`
|
|
53
|
+
* `left(angle)` - aliased as `lt` and `turnleft`
|
|
54
|
+
* `right(angle)` - aliased as `rt` and `turnright`
|
|
55
|
+
* `pen_up` - aliased as `pu` and `up` and `penup`
|
|
56
|
+
* `pen_down` - aliased as `pd` and `down` and `pendown`
|
|
57
|
+
* `color(color_name)` - aliased as `pencolor`. Accepts X11 color names (`"darkolivegreen"`) or hex (`"#1e90ff"`), and returns the current color if called with no argument
|
|
58
|
+
* `move(x, y)` - aliased as `goto`, `setpos` and `setposition`
|
|
59
|
+
* `home` - returns to the center of the canvas, facing right
|
|
60
|
+
* `position` - aliased as `pos`
|
|
61
|
+
* `circle(radius, extent = 360, steps = 360)`
|
|
62
|
+
* `dot(size)` - draws a dot, defaults to a sensible size but you can supply if you want
|
|
63
|
+
* `is_drawing?`
|
|
64
|
+
* `width(width_in_pixels)`
|
|
65
|
+
* `ensure_drawn` - makes sure everything drawn so far is on screen (useful in loops in scripts)
|
|
66
|
+
* `wait` - keeps the window open until it's closed or Enter is pressed (needed at the end of scripts, not in IRB)
|
|
45
67
|
|
|
46
68
|
## Examples
|
|
47
69
|
|
|
48
70
|
The examples in the `examples` folder should be reasonably illustrative. If you
|
|
49
71
|
try any of them, try `example4.rb` - it renders an awesome looking tree.
|
|
50
72
|
|
|
51
|
-

|
|
52
74
|
|
|
53
75
|
## Credits
|
|
54
76
|
|
|
55
|
-
* turtle.py for inspiration
|
|
77
|
+
* turtle.py for inspiration (in the 'Ruby needs this!' sense)
|
|
56
78
|
* Some of the examples taken from examples for an earlier Ruby turtle found at http://www.rubyquiz.com/quiz104.html
|
|
57
79
|
|
|
58
80
|
## Copyright and License
|
|
59
81
|
|
|
60
|
-
Copyright (c) 2012 Peter Cooper (other than minor parts of some samples.)
|
|
82
|
+
Copyright (c) 2012-2026 Peter Cooper (other than minor parts of some samples.)
|
|
61
83
|
|
|
62
84
|
MIT licensed. See LICENSE.md
|
data/examples/example2.rb
CHANGED
data/lib/trtl/canvas.rb
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
require 'libui'
|
|
2
|
+
|
|
3
|
+
class Trtl
|
|
4
|
+
# A window with a drawing area, built on LibUI. LibUI areas are repainted
|
|
5
|
+
# from scratch whenever the OS asks, so the canvas keeps a list of everything
|
|
6
|
+
# drawn so far and replays it on each repaint.
|
|
7
|
+
class Canvas
|
|
8
|
+
UI = LibUI
|
|
9
|
+
FRAME = 1 / 60.0
|
|
10
|
+
TWO_PI = Math::PI * 2
|
|
11
|
+
|
|
12
|
+
attr_reader :width, :height, :title
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
def canvases
|
|
16
|
+
@canvases ||= []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def init_ui
|
|
20
|
+
return if @ui_ready
|
|
21
|
+
UI.init
|
|
22
|
+
UI.main_steps
|
|
23
|
+
# Cmd+Q closes the windows rather than stopping the event loop
|
|
24
|
+
UI.on_should_quit do
|
|
25
|
+
canvases.each(&:close)
|
|
26
|
+
0
|
|
27
|
+
end
|
|
28
|
+
@ui_ready = true
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# UI calls must not be re-entered from the signal handler used by keep_responsive!
|
|
32
|
+
def busy
|
|
33
|
+
was_busy, @busy = @busy, true
|
|
34
|
+
yield
|
|
35
|
+
ensure
|
|
36
|
+
@busy = was_busy
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def busy?
|
|
40
|
+
@busy
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# IRb and Pry spend most of their time blocked waiting for keyboard input,
|
|
44
|
+
# when nothing would service the window (so it couldn't be moved, resized,
|
|
45
|
+
# or even repainted). A background thread signals the process regularly
|
|
46
|
+
# and the trap handler, which Ruby always runs on the main thread as the
|
|
47
|
+
# UI requires, processes any pending window events. Windows has no USR2,
|
|
48
|
+
# so there the window only updates when turtle commands run.
|
|
49
|
+
def keep_responsive!
|
|
50
|
+
return if @keeper || !Signal.list.key?('USR2')
|
|
51
|
+
Signal.trap('USR2') { canvases.each(&:pump) unless busy? }
|
|
52
|
+
@keeper = Thread.new do
|
|
53
|
+
loop do
|
|
54
|
+
Kernel.sleep(FRAME * 2)
|
|
55
|
+
Process.kill('USR2', Process.pid)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def initialize(width, height, title: 'trtl', background: 'black')
|
|
62
|
+
@width, @height, @title = width, height, title
|
|
63
|
+
@background = Colors.rgb(background)
|
|
64
|
+
@items = []
|
|
65
|
+
@turtles = []
|
|
66
|
+
self.class.canvases << self
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def line(x1, y1, x2, y2, width, color)
|
|
70
|
+
@items << [:line, x1.to_f, y1.to_f, x2.to_f, y2.to_f, width.to_f, Colors.rgb(color)]
|
|
71
|
+
changed
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def dot(x, y, size, color)
|
|
75
|
+
@items << [:dot, x.to_f, y.to_f, size / 2.0, Colors.rgb(color)]
|
|
76
|
+
changed
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def add_turtle(turtle)
|
|
80
|
+
@turtles << turtle
|
|
81
|
+
changed
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Marks the canvas as needing a repaint the next time events are processed
|
|
85
|
+
def changed
|
|
86
|
+
@dirty = true
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def title=(title)
|
|
90
|
+
@title = title.to_s
|
|
91
|
+
UI.window_set_title(@window, @title) if open?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def open?
|
|
95
|
+
!@window.nil?
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Opens the window if necessary, then processes window events for about
|
|
99
|
+
# +ms+ milliseconds, which is what gets the latest drawing on screen
|
|
100
|
+
def update(ms = 0)
|
|
101
|
+
open unless open?
|
|
102
|
+
deadline = clock + ms / 1000.0
|
|
103
|
+
pump
|
|
104
|
+
while (remaining = deadline - clock) > 0
|
|
105
|
+
Kernel.sleep([FRAME, remaining].min)
|
|
106
|
+
pump
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Keeps the window responsive until it's closed or Enter is pressed
|
|
111
|
+
def wait
|
|
112
|
+
update
|
|
113
|
+
while open?
|
|
114
|
+
if IO.select([$stdin], nil, nil, FRAME)
|
|
115
|
+
$stdin.gets
|
|
116
|
+
break
|
|
117
|
+
end
|
|
118
|
+
pump
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def pump
|
|
123
|
+
return unless open?
|
|
124
|
+
self.class.busy do
|
|
125
|
+
if @dirty
|
|
126
|
+
UI.area_queue_redraw_all(@area)
|
|
127
|
+
@dirty = false
|
|
128
|
+
end
|
|
129
|
+
# Each step handles at most one pending event
|
|
130
|
+
20.times { UI.main_step(0) }
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def close
|
|
135
|
+
return unless open?
|
|
136
|
+
self.class.busy { UI.control_destroy(@window) }
|
|
137
|
+
closed
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
private
|
|
141
|
+
|
|
142
|
+
def clock
|
|
143
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def open
|
|
147
|
+
self.class.init_ui
|
|
148
|
+
self.class.busy do
|
|
149
|
+
@window = UI.new_window(@title, @width, @height, 0)
|
|
150
|
+
|
|
151
|
+
@handler = struct(UI::FFI::AreaHandler)
|
|
152
|
+
# Fiddle closures are kept in instance variables so they aren't garbage collected
|
|
153
|
+
@draw_callback = Fiddle::Closure::BlockCaller.new(Fiddle::TYPE_VOID, [Fiddle::TYPE_VOIDP] * 3) do |_, _, params|
|
|
154
|
+
draw(UI::FFI::AreaDrawParams.new(params))
|
|
155
|
+
rescue Exception => e
|
|
156
|
+
warn "trtl: error while drawing: #{e.class}: #{e.message}"
|
|
157
|
+
end
|
|
158
|
+
@ignore_callback = Fiddle::Closure::BlockCaller.new(Fiddle::TYPE_VOID, [Fiddle::TYPE_VOIDP]) {}
|
|
159
|
+
@key_callback = Fiddle::Closure::BlockCaller.new(Fiddle::TYPE_INT, [Fiddle::TYPE_VOIDP]) { 0 }
|
|
160
|
+
@handler.Draw = @draw_callback
|
|
161
|
+
@handler.MouseEvent = @ignore_callback
|
|
162
|
+
@handler.MouseCrossed = @ignore_callback
|
|
163
|
+
@handler.DragBroken = @ignore_callback
|
|
164
|
+
@handler.KeyEvent = @key_callback
|
|
165
|
+
|
|
166
|
+
@area = UI.new_area(@handler)
|
|
167
|
+
UI.window_set_child(@window, @area)
|
|
168
|
+
# Returning 1 lets LibUI destroy the window (and the area inside it)
|
|
169
|
+
UI.window_on_closing(@window) do
|
|
170
|
+
closed
|
|
171
|
+
1
|
|
172
|
+
end
|
|
173
|
+
UI.control_show(@window)
|
|
174
|
+
end
|
|
175
|
+
changed
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def closed
|
|
179
|
+
@window = @area = nil
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def struct(type)
|
|
183
|
+
type.malloc.tap { |s| s.to_ptr.free = Fiddle::RUBY_FREE }
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def draw(params)
|
|
187
|
+
ctx = params.Context
|
|
188
|
+
@brush ||= struct(UI::FFI::DrawBrush).tap { |b| b.Type = UI::DrawBrushTypeSolid }
|
|
189
|
+
@stroke ||= struct(UI::FFI::DrawStrokeParams).tap do |s|
|
|
190
|
+
s.Cap = UI::DrawLineCapRound
|
|
191
|
+
s.Join = UI::DrawLineJoinRound
|
|
192
|
+
s.MiterLimit = UI::DrawDefaultMiterLimit
|
|
193
|
+
s.NumDashes = 0
|
|
194
|
+
s.DashPhase = 0
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
fill(ctx, @background) { |path| UI.draw_path_add_rectangle(path, 0, 0, params.AreaWidth, params.AreaHeight) }
|
|
198
|
+
|
|
199
|
+
# Keep the drawing centered if the window is resized
|
|
200
|
+
@matrix ||= struct(UI::FFI::DrawMatrix)
|
|
201
|
+
UI.draw_matrix_set_identity(@matrix)
|
|
202
|
+
UI.draw_matrix_translate(@matrix, (params.AreaWidth - @width) / 2.0, (params.AreaHeight - @height) / 2.0)
|
|
203
|
+
UI.draw_transform(ctx, @matrix)
|
|
204
|
+
|
|
205
|
+
draw_items(ctx)
|
|
206
|
+
@turtles.each { |turtle| draw_turtle(ctx, turtle) }
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Consecutive lines sharing a width and color go into a single path, joined
|
|
210
|
+
# up where one starts at the end of the last, which is much faster than
|
|
211
|
+
# stroking each line alone and gives cleaner joins
|
|
212
|
+
def draw_items(ctx)
|
|
213
|
+
path = style = last_x = last_y = nil
|
|
214
|
+
|
|
215
|
+
@items.each do |kind, *args|
|
|
216
|
+
if kind == :line
|
|
217
|
+
x1, y1, x2, y2, width, rgb = args
|
|
218
|
+
if path.nil? || style[0] != width || style[1] != rgb
|
|
219
|
+
stroke(ctx, path, style) if path
|
|
220
|
+
path = UI.draw_new_path(UI::DrawFillModeWinding)
|
|
221
|
+
style = [width, rgb]
|
|
222
|
+
UI.draw_path_new_figure(path, x1, y1)
|
|
223
|
+
elsif x1 != last_x || y1 != last_y
|
|
224
|
+
UI.draw_path_new_figure(path, x1, y1)
|
|
225
|
+
end
|
|
226
|
+
UI.draw_path_line_to(path, x2, y2)
|
|
227
|
+
last_x, last_y = x2, y2
|
|
228
|
+
else
|
|
229
|
+
stroke(ctx, path, style) if path
|
|
230
|
+
path = nil
|
|
231
|
+
x, y, radius, rgb = args
|
|
232
|
+
fill(ctx, rgb) { |p| UI.draw_path_new_figure_with_arc(p, x, y, radius, 0, TWO_PI, 0) }
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
stroke(ctx, path, style) if path
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# An arrowhead pointing in the turtle's direction of travel
|
|
240
|
+
def draw_turtle(ctx, turtle)
|
|
241
|
+
x, y = turtle.position
|
|
242
|
+
angle = turtle.heading * DEG
|
|
243
|
+
dx, dy = Math.cos(angle), Math.sin(angle)
|
|
244
|
+
fill(ctx, Colors.rgb(turtle.color)) do |path|
|
|
245
|
+
UI.draw_path_new_figure(path, x + dx * 10, y + dy * 10)
|
|
246
|
+
UI.draw_path_line_to(path, x - dx * 2 - dy * 6, y - dy * 2 + dx * 6)
|
|
247
|
+
UI.draw_path_line_to(path, x - dx * 2 + dy * 6, y - dy * 2 - dx * 6)
|
|
248
|
+
UI.draw_path_close_figure(path)
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def stroke(ctx, path, (width, rgb))
|
|
253
|
+
UI.draw_path_end(path)
|
|
254
|
+
set_brush(rgb)
|
|
255
|
+
@stroke.Thickness = width
|
|
256
|
+
UI.draw_stroke(ctx, path, @brush, @stroke)
|
|
257
|
+
UI.draw_free_path(path)
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def fill(ctx, rgb)
|
|
261
|
+
path = UI.draw_new_path(UI::DrawFillModeWinding)
|
|
262
|
+
yield path
|
|
263
|
+
UI.draw_path_end(path)
|
|
264
|
+
set_brush(rgb)
|
|
265
|
+
UI.draw_fill(ctx, path, @brush)
|
|
266
|
+
UI.draw_free_path(path)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def set_brush((r, g, b))
|
|
270
|
+
@brush.R, @brush.G, @brush.B, @brush.A = r, g, b, 1.0
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
data/lib/trtl/colors.rb
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
class Trtl
|
|
2
|
+
# Named colors follow the X11 color list, the same names (and values) Tk accepted.
|
|
3
|
+
# Lookup ignores case and spaces, so "DarkOliveGreen" and "dark olive green" both work.
|
|
4
|
+
module Colors
|
|
5
|
+
TABLE = <<~LIST.split.each_slice(2).to_h { |name, hex| [name, hex] }.freeze
|
|
6
|
+
aliceblue f0f8ff antiquewhite faebd7 antiquewhite1 ffefdb antiquewhite2 eedfcc
|
|
7
|
+
antiquewhite3 cdc0b0 antiquewhite4 8b8378 aqua 00ffff aquamarine 7fffd4
|
|
8
|
+
aquamarine1 7fffd4 aquamarine2 76eec6 aquamarine3 66cdaa aquamarine4 458b74
|
|
9
|
+
azure f0ffff azure1 f0ffff azure2 e0eeee azure3 c1cdcd
|
|
10
|
+
azure4 838b8b beige f5f5dc bisque ffe4c4 bisque1 ffe4c4
|
|
11
|
+
bisque2 eed5b7 bisque3 cdb79e bisque4 8b7d6b black 000000
|
|
12
|
+
blanchedalmond ffebcd blue 0000ff blue1 0000ff blue2 0000ee
|
|
13
|
+
blue3 0000cd blue4 00008b blueviolet 8a2be2 brown a52a2a
|
|
14
|
+
brown1 ff4040 brown2 ee3b3b brown3 cd3333 brown4 8b2323
|
|
15
|
+
burlywood deb887 burlywood1 ffd39b burlywood2 eec591 burlywood3 cdaa7d
|
|
16
|
+
burlywood4 8b7355 cadetblue 5f9ea0 cadetblue1 98f5ff cadetblue2 8ee5ee
|
|
17
|
+
cadetblue3 7ac5cd cadetblue4 53868b chartreuse 7fff00 chartreuse1 7fff00
|
|
18
|
+
chartreuse2 76ee00 chartreuse3 66cd00 chartreuse4 458b00 chocolate d2691e
|
|
19
|
+
chocolate1 ff7f24 chocolate2 ee7621 chocolate3 cd661d chocolate4 8b4513
|
|
20
|
+
coral ff7f50 coral1 ff7256 coral2 ee6a50 coral3 cd5b45
|
|
21
|
+
coral4 8b3e2f cornflowerblue 6495ed cornsilk fff8dc cornsilk1 fff8dc
|
|
22
|
+
cornsilk2 eee8cd cornsilk3 cdc8b1 cornsilk4 8b8878 crimson dc143c
|
|
23
|
+
cyan 00ffff cyan1 00ffff cyan2 00eeee cyan3 00cdcd
|
|
24
|
+
cyan4 008b8b darkblue 00008b darkcyan 008b8b darkgoldenrod b8860b
|
|
25
|
+
darkgoldenrod1 ffb90f darkgoldenrod2 eead0e darkgoldenrod3 cd950c darkgoldenrod4 8b6508
|
|
26
|
+
darkgray a9a9a9 darkgreen 006400 darkgrey a9a9a9 darkkhaki bdb76b
|
|
27
|
+
darkmagenta 8b008b darkolivegreen 556b2f darkolivegreen1 caff70 darkolivegreen2 bcee68
|
|
28
|
+
darkolivegreen3 a2cd5a darkolivegreen4 6e8b3d darkorange ff8c00 darkorange1 ff7f00
|
|
29
|
+
darkorange2 ee7600 darkorange3 cd6600 darkorange4 8b4500 darkorchid 9932cc
|
|
30
|
+
darkorchid1 bf3eff darkorchid2 b23aee darkorchid3 9a32cd darkorchid4 68228b
|
|
31
|
+
darkred 8b0000 darksalmon e9967a darkseagreen 8fbc8f darkseagreen1 c1ffc1
|
|
32
|
+
darkseagreen2 b4eeb4 darkseagreen3 9bcd9b darkseagreen4 698b69 darkslateblue 483d8b
|
|
33
|
+
darkslategray 2f4f4f darkslategray1 97ffff darkslategray2 8deeee darkslategray3 79cdcd
|
|
34
|
+
darkslategray4 528b8b darkslategrey 2f4f4f darkturquoise 00ced1 darkviolet 9400d3
|
|
35
|
+
deeppink ff1493 deeppink1 ff1493 deeppink2 ee1289 deeppink3 cd1076
|
|
36
|
+
deeppink4 8b0a50 deepskyblue 00bfff deepskyblue1 00bfff deepskyblue2 00b2ee
|
|
37
|
+
deepskyblue3 009acd deepskyblue4 00688b dimgray 696969 dimgrey 696969
|
|
38
|
+
dodgerblue 1e90ff dodgerblue1 1e90ff dodgerblue2 1c86ee dodgerblue3 1874cd
|
|
39
|
+
dodgerblue4 104e8b firebrick b22222 firebrick1 ff3030 firebrick2 ee2c2c
|
|
40
|
+
firebrick3 cd2626 firebrick4 8b1a1a floralwhite fffaf0 forestgreen 228b22
|
|
41
|
+
fractal 808080 freeze 000000 fuchsia ff00ff gainsboro dcdcdc
|
|
42
|
+
ghostwhite f8f8ff gold ffd700 gold1 ffd700 gold2 eec900
|
|
43
|
+
gold3 cdad00 gold4 8b7500 goldenrod daa520 goldenrod1 ffc125
|
|
44
|
+
goldenrod2 eeb422 goldenrod3 cd9b1d goldenrod4 8b6914 gray bebebe
|
|
45
|
+
gray0 000000 gray1 030303 gray10 1a1a1a gray100 ffffff
|
|
46
|
+
gray11 1c1c1c gray12 1f1f1f gray13 212121 gray14 242424
|
|
47
|
+
gray15 262626 gray16 292929 gray17 2b2b2b gray18 2e2e2e
|
|
48
|
+
gray19 303030 gray2 050505 gray20 333333 gray21 363636
|
|
49
|
+
gray22 383838 gray23 3b3b3b gray24 3d3d3d gray25 404040
|
|
50
|
+
gray26 424242 gray27 454545 gray28 474747 gray29 4a4a4a
|
|
51
|
+
gray3 080808 gray30 4d4d4d gray31 4f4f4f gray32 525252
|
|
52
|
+
gray33 545454 gray34 575757 gray35 595959 gray36 5c5c5c
|
|
53
|
+
gray37 5e5e5e gray38 616161 gray39 636363 gray4 0a0a0a
|
|
54
|
+
gray40 666666 gray41 696969 gray42 6b6b6b gray43 6e6e6e
|
|
55
|
+
gray44 707070 gray45 737373 gray46 757575 gray47 787878
|
|
56
|
+
gray48 7a7a7a gray49 7d7d7d gray5 0d0d0d gray50 7f7f7f
|
|
57
|
+
gray51 828282 gray52 858585 gray53 878787 gray54 8a8a8a
|
|
58
|
+
gray55 8c8c8c gray56 8f8f8f gray57 919191 gray58 949494
|
|
59
|
+
gray59 969696 gray6 0f0f0f gray60 999999 gray61 9c9c9c
|
|
60
|
+
gray62 9e9e9e gray63 a1a1a1 gray64 a3a3a3 gray65 a6a6a6
|
|
61
|
+
gray66 a8a8a8 gray67 ababab gray68 adadad gray69 b0b0b0
|
|
62
|
+
gray7 121212 gray70 b3b3b3 gray71 b5b5b5 gray72 b8b8b8
|
|
63
|
+
gray73 bababa gray74 bdbdbd gray75 bfbfbf gray76 c2c2c2
|
|
64
|
+
gray77 c4c4c4 gray78 c7c7c7 gray79 c9c9c9 gray8 141414
|
|
65
|
+
gray80 cccccc gray81 cfcfcf gray82 d1d1d1 gray83 d4d4d4
|
|
66
|
+
gray84 d6d6d6 gray85 d9d9d9 gray86 dbdbdb gray87 dedede
|
|
67
|
+
gray88 e0e0e0 gray89 e3e3e3 gray9 171717 gray90 e5e5e5
|
|
68
|
+
gray91 e8e8e8 gray92 ebebeb gray93 ededed gray94 f0f0f0
|
|
69
|
+
gray95 f2f2f2 gray96 f5f5f5 gray97 f7f7f7 gray98 fafafa
|
|
70
|
+
gray99 fcfcfc green 00ff00 green1 00ff00 green2 00ee00
|
|
71
|
+
green3 00cd00 green4 008b00 greenyellow adff2f grey bebebe
|
|
72
|
+
grey0 000000 grey1 030303 grey10 1a1a1a grey100 ffffff
|
|
73
|
+
grey11 1c1c1c grey12 1f1f1f grey13 212121 grey14 242424
|
|
74
|
+
grey15 262626 grey16 292929 grey17 2b2b2b grey18 2e2e2e
|
|
75
|
+
grey19 303030 grey2 050505 grey20 333333 grey21 363636
|
|
76
|
+
grey22 383838 grey23 3b3b3b grey24 3d3d3d grey25 404040
|
|
77
|
+
grey26 424242 grey27 454545 grey28 474747 grey29 4a4a4a
|
|
78
|
+
grey3 080808 grey30 4d4d4d grey31 4f4f4f grey32 525252
|
|
79
|
+
grey33 545454 grey34 575757 grey35 595959 grey36 5c5c5c
|
|
80
|
+
grey37 5e5e5e grey38 616161 grey39 636363 grey4 0a0a0a
|
|
81
|
+
grey40 666666 grey41 696969 grey42 6b6b6b grey43 6e6e6e
|
|
82
|
+
grey44 707070 grey45 737373 grey46 757575 grey47 787878
|
|
83
|
+
grey48 7a7a7a grey49 7d7d7d grey5 0d0d0d grey50 7f7f7f
|
|
84
|
+
grey51 828282 grey52 858585 grey53 878787 grey54 8a8a8a
|
|
85
|
+
grey55 8c8c8c grey56 8f8f8f grey57 919191 grey58 949494
|
|
86
|
+
grey59 969696 grey6 0f0f0f grey60 999999 grey61 9c9c9c
|
|
87
|
+
grey62 9e9e9e grey63 a1a1a1 grey64 a3a3a3 grey65 a6a6a6
|
|
88
|
+
grey66 a8a8a8 grey67 ababab grey68 adadad grey69 b0b0b0
|
|
89
|
+
grey7 121212 grey70 b3b3b3 grey71 b5b5b5 grey72 b8b8b8
|
|
90
|
+
grey73 bababa grey74 bdbdbd grey75 bfbfbf grey76 c2c2c2
|
|
91
|
+
grey77 c4c4c4 grey78 c7c7c7 grey79 c9c9c9 grey8 141414
|
|
92
|
+
grey80 cccccc grey81 cfcfcf grey82 d1d1d1 grey83 d4d4d4
|
|
93
|
+
grey84 d6d6d6 grey85 d9d9d9 grey86 dbdbdb grey87 dedede
|
|
94
|
+
grey88 e0e0e0 grey89 e3e3e3 grey9 171717 grey90 e5e5e5
|
|
95
|
+
grey91 e8e8e8 grey92 ebebeb grey93 ededed grey94 f0f0f0
|
|
96
|
+
grey95 f2f2f2 grey96 f5f5f5 grey97 f7f7f7 grey98 fafafa
|
|
97
|
+
grey99 fcfcfc honeydew f0fff0 honeydew1 f0fff0 honeydew2 e0eee0
|
|
98
|
+
honeydew3 c1cdc1 honeydew4 838b83 hotpink ff69b4 hotpink1 ff6eb4
|
|
99
|
+
hotpink2 ee6aa7 hotpink3 cd6090 hotpink4 8b3a62 indianred cd5c5c
|
|
100
|
+
indianred1 ff6a6a indianred2 ee6363 indianred3 cd5555 indianred4 8b3a3a
|
|
101
|
+
indigo 4b0082 ivory fffff0 ivory1 fffff0 ivory2 eeeee0
|
|
102
|
+
ivory3 cdcdc1 ivory4 8b8b83 khaki f0e68c khaki1 fff68f
|
|
103
|
+
khaki2 eee685 khaki3 cdc673 khaki4 8b864e lavender e6e6fa
|
|
104
|
+
lavenderblush fff0f5 lavenderblush1 fff0f5 lavenderblush2 eee0e5 lavenderblush3 cdc1c5
|
|
105
|
+
lavenderblush4 8b8386 lawngreen 7cfc00 lemonchiffon fffacd lemonchiffon1 fffacd
|
|
106
|
+
lemonchiffon2 eee9bf lemonchiffon3 cdc9a5 lemonchiffon4 8b8970 lightblue add8e6
|
|
107
|
+
lightblue1 bfefff lightblue2 b2dfee lightblue3 9ac0cd lightblue4 68838b
|
|
108
|
+
lightcoral f08080 lightcyan e0ffff lightcyan1 e0ffff lightcyan2 d1eeee
|
|
109
|
+
lightcyan3 b4cdcd lightcyan4 7a8b8b lightgoldenrod eedd82 lightgoldenrod1 ffec8b
|
|
110
|
+
lightgoldenrod2 eedc82 lightgoldenrod3 cdbe70 lightgoldenrod4 8b814c lightgoldenrodyellow fafad2
|
|
111
|
+
lightgray d3d3d3 lightgreen 90ee90 lightgrey d3d3d3 lightpink ffb6c1
|
|
112
|
+
lightpink1 ffaeb9 lightpink2 eea2ad lightpink3 cd8c95 lightpink4 8b5f65
|
|
113
|
+
lightsalmon ffa07a lightsalmon1 ffa07a lightsalmon2 ee9572 lightsalmon3 cd8162
|
|
114
|
+
lightsalmon4 8b5742 lightseagreen 20b2aa lightskyblue 87cefa lightskyblue1 b0e2ff
|
|
115
|
+
lightskyblue2 a4d3ee lightskyblue3 8db6cd lightskyblue4 607b8b lightslateblue 8470ff
|
|
116
|
+
lightslategray 778899 lightslategrey 778899 lightsteelblue b0c4de lightsteelblue1 cae1ff
|
|
117
|
+
lightsteelblue2 bcd2ee lightsteelblue3 a2b5cd lightsteelblue4 6e7b8b lightyellow ffffe0
|
|
118
|
+
lightyellow1 ffffe0 lightyellow2 eeeed1 lightyellow3 cdcdb4 lightyellow4 8b8b7a
|
|
119
|
+
lime 00ff00 limegreen 32cd32 linen faf0e6 magenta ff00ff
|
|
120
|
+
magenta1 ff00ff magenta2 ee00ee magenta3 cd00cd magenta4 8b008b
|
|
121
|
+
maroon b03060 maroon1 ff34b3 maroon2 ee30a7 maroon3 cd2990
|
|
122
|
+
maroon4 8b1c62 matte 000000 mediumaquamarine 66cdaa mediumblue 0000cd
|
|
123
|
+
mediumforestgreen 32814b mediumgoldenrod d1c166 mediumorchid ba55d3 mediumorchid1 e066ff
|
|
124
|
+
mediumorchid2 d15fee mediumorchid3 b452cd mediumorchid4 7a378b mediumpurple 9370db
|
|
125
|
+
mediumpurple1 ab82ff mediumpurple2 9f79ee mediumpurple3 8968cd mediumpurple4 5d478b
|
|
126
|
+
mediumseagreen 3cb371 mediumslateblue 7b68ee mediumspringgreen 00fa9a mediumturquoise 48d1cc
|
|
127
|
+
mediumvioletred c71585 midnightblue 191970 mintcream f5fffa mistyrose ffe4e1
|
|
128
|
+
mistyrose1 ffe4e1 mistyrose2 eed5d2 mistyrose3 cdb7b5 mistyrose4 8b7d7b
|
|
129
|
+
moccasin ffe4b5 navajowhite ffdead navajowhite1 ffdead navajowhite2 eecfa1
|
|
130
|
+
navajowhite3 cdb38b navajowhite4 8b795e navy 000080 navyblue 000080
|
|
131
|
+
none 000000 oldlace fdf5e6 olive 808000 olivedrab 6b8e23
|
|
132
|
+
olivedrab1 c0ff3e olivedrab2 b3ee3a olivedrab3 9acd32 olivedrab4 698b22
|
|
133
|
+
opaque 000000 orange ffa500 orange1 ffa500 orange2 ee9a00
|
|
134
|
+
orange3 cd8500 orange4 8b5a00 orangered ff4500 orangered1 ff4500
|
|
135
|
+
orangered2 ee4000 orangered3 cd3700 orangered4 8b2500 orchid da70d6
|
|
136
|
+
orchid1 ff83fa orchid2 ee7ae9 orchid3 cd69c9 orchid4 8b4789
|
|
137
|
+
palegoldenrod eee8aa palegreen 98fb98 palegreen1 9aff9a palegreen2 90ee90
|
|
138
|
+
palegreen3 7ccd7c palegreen4 548b54 paleturquoise afeeee paleturquoise1 bbffff
|
|
139
|
+
paleturquoise2 aeeeee paleturquoise3 96cdcd paleturquoise4 668b8b palevioletred db7093
|
|
140
|
+
palevioletred1 ff82ab palevioletred2 ee799f palevioletred3 cd6889 palevioletred4 8b475d
|
|
141
|
+
papayawhip ffefd5 peachpuff ffdab9 peachpuff1 ffdab9 peachpuff2 eecbad
|
|
142
|
+
peachpuff3 cdaf95 peachpuff4 8b7765 peru cd853f pink ffc0cb
|
|
143
|
+
pink1 ffb5c5 pink2 eea9b8 pink3 cd919e pink4 8b636c
|
|
144
|
+
plum dda0dd plum1 ffbbff plum2 eeaeee plum3 cd96cd
|
|
145
|
+
plum4 8b668b powderblue b0e0e6 purple a020f0 purple1 9b30ff
|
|
146
|
+
purple2 912cee purple3 7d26cd purple4 551a8b red ff0000
|
|
147
|
+
red1 ff0000 red2 ee0000 red3 cd0000 red4 8b0000
|
|
148
|
+
rosybrown bc8f8f rosybrown1 ffc1c1 rosybrown2 eeb4b4 rosybrown3 cd9b9b
|
|
149
|
+
rosybrown4 8b6969 royalblue 4169e1 royalblue1 4876ff royalblue2 436eee
|
|
150
|
+
royalblue3 3a5fcd royalblue4 27408b saddlebrown 8b4513 salmon fa8072
|
|
151
|
+
salmon1 ff8c69 salmon2 ee8262 salmon3 cd7054 salmon4 8b4c39
|
|
152
|
+
sandybrown f4a460 seagreen 2e8b57 seagreen1 54ff9f seagreen2 4eee94
|
|
153
|
+
seagreen3 43cd80 seagreen4 2e8b57 seashell fff5ee seashell1 fff5ee
|
|
154
|
+
seashell2 eee5de seashell3 cdc5bf seashell4 8b8682 sienna a0522d
|
|
155
|
+
sienna1 ff8247 sienna2 ee7942 sienna3 cd6839 sienna4 8b4726
|
|
156
|
+
silver c0c0c0 skyblue 87ceeb skyblue1 87ceff skyblue2 7ec0ee
|
|
157
|
+
skyblue3 6ca6cd skyblue4 4a708b slateblue 6a5acd slateblue1 836fff
|
|
158
|
+
slateblue2 7a67ee slateblue3 6959cd slateblue4 473c8b slategray 708090
|
|
159
|
+
slategray1 c6e2ff slategray2 b9d3ee slategray3 9fb6cd slategray4 6c7b8b
|
|
160
|
+
slategrey 708090 snow fffafa snow1 fffafa snow2 eee9e9
|
|
161
|
+
snow3 cdc9c9 snow4 8b8989 springgreen 00ff7f springgreen1 00ff7f
|
|
162
|
+
springgreen2 00ee76 springgreen3 00cd66 springgreen4 008b45 steelblue 4682b4
|
|
163
|
+
steelblue1 63b8ff steelblue2 5cacee steelblue3 4f94cd steelblue4 36648b
|
|
164
|
+
tan d2b48c tan1 ffa54f tan2 ee9a49 tan3 cd853f
|
|
165
|
+
tan4 8b5a2b teal 008080 thistle d8bfd8 thistle1 ffe1ff
|
|
166
|
+
thistle2 eed2ee thistle3 cdb5cd thistle4 8b7b8b tomato ff6347
|
|
167
|
+
tomato1 ff6347 tomato2 ee5c42 tomato3 cd4f39 tomato4 8b3626
|
|
168
|
+
transparent 000000 turquoise 40e0d0 turquoise1 00f5ff turquoise2 00e5ee
|
|
169
|
+
turquoise3 00c5cd turquoise4 00868b violet ee82ee violetred d02090
|
|
170
|
+
violetred1 ff3e96 violetred2 ee3a8c violetred3 cd3278 violetred4 8b2252
|
|
171
|
+
wheat f5deb3 wheat1 ffe7ba wheat2 eed8ae wheat3 cdba96
|
|
172
|
+
wheat4 8b7e66 white ffffff whitesmoke f5f5f5 yellow ffff00
|
|
173
|
+
yellow1 ffff00 yellow2 eeee00 yellow3 cdcd00 yellow4 8b8b00
|
|
174
|
+
yellowgreen 9acd32
|
|
175
|
+
LIST
|
|
176
|
+
|
|
177
|
+
# Returns [r, g, b] with components between 0.0 and 1.0
|
|
178
|
+
def self.rgb(color)
|
|
179
|
+
case color
|
|
180
|
+
when /\A#(\h{3})\z/ then $1.chars.map { |c| (c * 2).to_i(16) / 255.0 }
|
|
181
|
+
when /\A#(\h{6})\z/ then $1.scan(/../).map { |c| c.to_i(16) / 255.0 }
|
|
182
|
+
else
|
|
183
|
+
hex = TABLE[color.to_s.downcase.delete(" ")] or raise ArgumentError, "unknown color: #{color.inspect}"
|
|
184
|
+
hex.scan(/../).map { |c| c.to_i(16) / 255.0 }
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
data/lib/trtl.rb
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
require_relative 'trtl/colors'
|
|
2
|
+
require_relative 'trtl/canvas'
|
|
2
3
|
|
|
3
4
|
class Trtl
|
|
4
|
-
VERSION = "0.0.1"
|
|
5
|
-
|
|
6
5
|
CANVAS_WIDTH = 800
|
|
7
6
|
CANVAS_HEIGHT = 600
|
|
8
7
|
HOME_X = CANVAS_WIDTH / 2
|
|
@@ -20,23 +19,23 @@ class Trtl
|
|
|
20
19
|
@canvas = options[:canvas] || self.class.canvas
|
|
21
20
|
@width = options[:width] || 1
|
|
22
21
|
@drawing = true
|
|
22
|
+
@canvas.add_turtle(self)
|
|
23
23
|
home
|
|
24
24
|
draw
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def self.canvas
|
|
28
|
-
|
|
28
|
+
@canvas ||= Canvas.new(CANVAS_WIDTH, CANVAS_HEIGHT)
|
|
29
|
+
end
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
@canvas.pack(:fill => 'both', :expand => 1)
|
|
33
|
-
@canvas
|
|
31
|
+
def title(title)
|
|
32
|
+
canvas.title = title
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
def pen_up
|
|
37
36
|
@drawing = false
|
|
38
37
|
end
|
|
39
|
-
|
|
38
|
+
|
|
40
39
|
def pen_down
|
|
41
40
|
@drawing = true
|
|
42
41
|
end
|
|
@@ -45,14 +44,16 @@ class Trtl
|
|
|
45
44
|
@drawing
|
|
46
45
|
end
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
# With no argument, returns the current color
|
|
48
|
+
def color(color = nil)
|
|
49
|
+
return @color if color.nil?
|
|
49
50
|
@color = color.to_s
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
def width(width)
|
|
53
54
|
@width = width
|
|
54
55
|
end
|
|
55
|
-
|
|
56
|
+
|
|
56
57
|
def forward(amount = 20)
|
|
57
58
|
new_x = (@x + dx * amount)
|
|
58
59
|
new_y = (@y + dy * amount)
|
|
@@ -64,18 +65,18 @@ class Trtl
|
|
|
64
65
|
new_y = (@y - dy * amount)
|
|
65
66
|
move(new_x, new_y)
|
|
66
67
|
end
|
|
67
|
-
|
|
68
|
+
|
|
68
69
|
def move(new_x, new_y)
|
|
69
|
-
|
|
70
|
+
canvas.line(@x, @y, new_x, new_y, @width, @color) if @drawing
|
|
70
71
|
@x, @y = new_x, new_y
|
|
71
72
|
draw
|
|
72
73
|
end
|
|
73
|
-
|
|
74
|
+
|
|
74
75
|
def right(offset)
|
|
75
76
|
@heading = (@heading + offset) % 360
|
|
76
77
|
draw
|
|
77
78
|
end
|
|
78
|
-
|
|
79
|
+
|
|
79
80
|
def left(offset)
|
|
80
81
|
@heading = (@heading - offset) % 360
|
|
81
82
|
draw
|
|
@@ -83,7 +84,7 @@ class Trtl
|
|
|
83
84
|
|
|
84
85
|
def dot(size = nil)
|
|
85
86
|
size ||= [@width + 4, @width * 2].max
|
|
86
|
-
|
|
87
|
+
canvas.dot(@x, @y, size, @color)
|
|
87
88
|
end
|
|
88
89
|
|
|
89
90
|
# TODO / TOFIX: This is horribly wrong with the fewer steps due to circumference varying ;-)
|
|
@@ -106,16 +107,18 @@ class Trtl
|
|
|
106
107
|
draw
|
|
107
108
|
end
|
|
108
109
|
|
|
110
|
+
# Shows the window and keeps it responsive for +time+ milliseconds
|
|
109
111
|
def sleep(time = 100000)
|
|
110
|
-
|
|
112
|
+
canvas.update(time)
|
|
111
113
|
end
|
|
112
114
|
|
|
113
115
|
def ensure_drawn
|
|
114
116
|
sleep 30
|
|
115
117
|
end
|
|
116
118
|
|
|
119
|
+
# Keeps the window open until it's closed or Enter is pressed
|
|
117
120
|
def wait
|
|
118
|
-
|
|
121
|
+
canvas.wait
|
|
119
122
|
end
|
|
120
123
|
|
|
121
124
|
alias :run :instance_eval
|
|
@@ -144,16 +147,14 @@ class Trtl
|
|
|
144
147
|
def dx
|
|
145
148
|
Math.cos(@heading * DEG)
|
|
146
149
|
end
|
|
147
|
-
|
|
150
|
+
|
|
148
151
|
def dy
|
|
149
152
|
Math.sin(@heading * DEG)
|
|
150
153
|
end
|
|
151
154
|
|
|
152
155
|
def draw
|
|
153
|
-
canvas.
|
|
154
|
-
|
|
155
|
-
# Can probably just use ensure_drawn actually..
|
|
156
|
-
TkTimer.new(60, 1) { Tk.update }.start.wait if @interactive
|
|
156
|
+
canvas.changed
|
|
157
|
+
canvas.update(60) if @interactive
|
|
157
158
|
true
|
|
158
159
|
end
|
|
159
160
|
end
|
|
@@ -168,4 +169,7 @@ module InteractiveTurtle
|
|
|
168
169
|
end
|
|
169
170
|
end
|
|
170
171
|
|
|
171
|
-
|
|
172
|
+
if %w{irb pry}.include?(File.basename($0))
|
|
173
|
+
include InteractiveTurtle
|
|
174
|
+
Trtl::Canvas.keep_responsive!
|
|
175
|
+
end
|
metadata
CHANGED
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: trtl
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 0.1.0
|
|
6
5
|
platform: ruby
|
|
7
6
|
authors:
|
|
8
7
|
- Peter Cooper
|
|
9
|
-
autorequire:
|
|
10
8
|
bindir: bin
|
|
11
9
|
cert_chain: []
|
|
12
|
-
date:
|
|
13
|
-
dependencies:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: libui
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.2'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.2'
|
|
14
26
|
description: A Logo / turtle.py style turtle graphics system for Ruby
|
|
15
27
|
email:
|
|
16
28
|
- git@peterc.org
|
|
@@ -18,11 +30,8 @@ executables: []
|
|
|
18
30
|
extensions: []
|
|
19
31
|
extra_rdoc_files: []
|
|
20
32
|
files:
|
|
21
|
-
- .gitignore
|
|
22
|
-
- Gemfile
|
|
23
33
|
- LICENSE.md
|
|
24
34
|
- README.md
|
|
25
|
-
- Rakefile
|
|
26
35
|
- examples/example1.rb
|
|
27
36
|
- examples/example2.rb
|
|
28
37
|
- examples/example3.rb
|
|
@@ -30,33 +39,27 @@ files:
|
|
|
30
39
|
- examples/example5.rb
|
|
31
40
|
- examples/example6.rb
|
|
32
41
|
- lib/trtl.rb
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
- trtl.gemspec
|
|
42
|
+
- lib/trtl/canvas.rb
|
|
43
|
+
- lib/trtl/colors.rb
|
|
36
44
|
homepage: https://github.com/peterc/trtl
|
|
37
|
-
licenses:
|
|
38
|
-
|
|
45
|
+
licenses:
|
|
46
|
+
- MIT
|
|
47
|
+
metadata: {}
|
|
39
48
|
rdoc_options: []
|
|
40
49
|
require_paths:
|
|
41
50
|
- lib
|
|
42
51
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
43
|
-
none: false
|
|
44
52
|
requirements:
|
|
45
|
-
- -
|
|
53
|
+
- - ">="
|
|
46
54
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
55
|
+
version: '2.6'
|
|
48
56
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
-
none: false
|
|
50
57
|
requirements:
|
|
51
|
-
- -
|
|
58
|
+
- - ">="
|
|
52
59
|
- !ruby/object:Gem::Version
|
|
53
60
|
version: '0'
|
|
54
61
|
requirements: []
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
summary: Ruby turtle graphics (ideal for use from IRb)
|
|
60
|
-
test_files:
|
|
61
|
-
- test/helper.rb
|
|
62
|
-
- test/test_trtl.rb
|
|
62
|
+
rubygems_version: 4.0.6
|
|
63
|
+
specification_version: 4
|
|
64
|
+
summary: Ruby turtle graphics (ideal for use from IRB)
|
|
65
|
+
test_files: []
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
data/test/helper.rb
DELETED
data/test/test_trtl.rb
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
require_relative 'helper'
|
|
2
|
-
|
|
3
|
-
# Note: Only very simple high level tests here. Just stretching
|
|
4
|
-
# some of the public API. One day I may care to stub out Tk ;-)
|
|
5
|
-
|
|
6
|
-
describe Trtl do
|
|
7
|
-
before do
|
|
8
|
-
@trtl = Trtl.new
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it "gets a default canvas when none is provided" do
|
|
12
|
-
@trtl.canvas.must_be_instance_of TkCanvas
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
it "has pen down by default" do
|
|
16
|
-
@trtl.is_drawing?.must_equal true
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "can have pen moved up" do
|
|
20
|
-
@trtl.pen_up
|
|
21
|
-
@trtl.is_drawing?.must_equal false
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it "has default X and Y set" do
|
|
25
|
-
@trtl.x.must_equal Trtl::CANVAS_WIDTH / 2
|
|
26
|
-
@trtl.y.must_equal Trtl::CANVAS_HEIGHT / 2
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it "can report its position" do
|
|
30
|
-
@trtl.position.must_equal [@trtl.x, @trtl.y]
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it "can rotate and change heading" do
|
|
34
|
-
@trtl.left 20
|
|
35
|
-
@trtl.heading.must_equal 340
|
|
36
|
-
@trtl.right 40
|
|
37
|
-
@trtl.heading.must_equal 20
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it "can move in straight lines" do
|
|
41
|
-
start_x, start_y = @trtl.position
|
|
42
|
-
@trtl.heading = 0
|
|
43
|
-
@trtl.forward 50
|
|
44
|
-
@trtl.x.must_equal start_x + 50
|
|
45
|
-
@trtl.heading = 90
|
|
46
|
-
@trtl.forward 50
|
|
47
|
-
@trtl.y.must_equal start_y + 50
|
|
48
|
-
@trtl.back 50
|
|
49
|
-
@trtl.y.must_equal start_y
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "can move at angles" do
|
|
53
|
-
start_x, start_y = @trtl.position
|
|
54
|
-
@trtl.heading = 45
|
|
55
|
-
@trtl.forward 100
|
|
56
|
-
@trtl.x.must_be_close_to start_x + 100 / Math.sqrt(2)
|
|
57
|
-
@trtl.y.must_be_close_to start_y + 100 / Math.sqrt(2)
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
it "can be moved absolutely" do
|
|
61
|
-
@trtl.move(310, 201)
|
|
62
|
-
@trtl.position.must_equal [310, 201]
|
|
63
|
-
end
|
|
64
|
-
end
|
data/trtl.gemspec
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
-
require "trtl"
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |s|
|
|
6
|
-
s.name = "trtl"
|
|
7
|
-
s.version = Trtl::VERSION
|
|
8
|
-
s.authors = ["Peter Cooper"]
|
|
9
|
-
s.email = ["git@peterc.org"]
|
|
10
|
-
s.homepage = "https://github.com/peterc/trtl"
|
|
11
|
-
s.summary = %q{Ruby turtle graphics (ideal for use from IRb)}
|
|
12
|
-
s.description = %q{A Logo / turtle.py style turtle graphics system for Ruby}
|
|
13
|
-
|
|
14
|
-
s.rubyforge_project = "trtl"
|
|
15
|
-
|
|
16
|
-
s.files = `git ls-files`.split("\n")
|
|
17
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
-
s.require_paths = ["lib"]
|
|
20
|
-
end
|