tkar 0.63
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.
- data/.gitignore +5 -0
- data/FAQ.rdoc +39 -0
- data/History.txt +175 -0
- data/README.rdoc +153 -0
- data/TODO +67 -0
- data/bin/tkar +104 -0
- data/examples/dial.rb +172 -0
- data/examples/help.gif +0 -0
- data/examples/home.gif +0 -0
- data/examples/mkgrid.rb +58 -0
- data/examples/ps.rb +47 -0
- data/examples/rotate +26 -0
- data/examples/s +3 -0
- data/examples/sample +14 -0
- data/examples/sample.rb +98 -0
- data/examples/sample2 +48 -0
- data/examples/sample3 +57 -0
- data/examples/server.rb +45 -0
- data/examples/tavis.rb +90 -0
- data/install.rb +1015 -0
- data/lib/tkar.rb +109 -0
- data/lib/tkar/argos.rb +214 -0
- data/lib/tkar/canvas.rb +370 -0
- data/lib/tkar/help-window.rb +168 -0
- data/lib/tkar/primitives.rb +376 -0
- data/lib/tkar/stream.rb +284 -0
- data/lib/tkar/timer.rb +174 -0
- data/lib/tkar/tkaroid.rb +95 -0
- data/lib/tkar/version.rb +5 -0
- data/lib/tkar/window.rb +383 -0
- data/protocol.rdoc +539 -0
- data/rakefile +56 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- metadata +116 -0
data/lib/tkar/tkaroid.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
module Tkar
|
2
|
+
class Tkaroid
|
3
|
+
attr_accessor :shape, :id, :flags, :layer, :x, :y, :r, :params
|
4
|
+
# note r is in radians, unlike Tk
|
5
|
+
attr_accessor :newly_added
|
6
|
+
attr_reader :tag, :parts
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
yield self if block_given?
|
10
|
+
@tag = Tkaroid.tag(@id)
|
11
|
+
@parts = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.tag id
|
15
|
+
"tkar#{id}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def draggable?
|
19
|
+
true ## get from flags
|
20
|
+
end
|
21
|
+
|
22
|
+
def drop_target?
|
23
|
+
true ## get from flags
|
24
|
+
end
|
25
|
+
|
26
|
+
HOVER_COLOR = 'SeaGreen1' ## user config
|
27
|
+
DRAG_COLOR = 'SeaGreen3' ## user config
|
28
|
+
|
29
|
+
module CarefulColorize
|
30
|
+
def colorize canvas, color
|
31
|
+
parts = canvas.find_withtag(tag)
|
32
|
+
parts.each do |part|
|
33
|
+
case part
|
34
|
+
when TkcImage
|
35
|
+
else
|
36
|
+
canvas.itemconfigure part, :fill => color
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# note: call after update, or else color is lost
|
43
|
+
def colorize canvas, color
|
44
|
+
canvas.itemconfigure tag, :fill => color
|
45
|
+
rescue => ex
|
46
|
+
if ex.message =~ /unknown option "-fill"/
|
47
|
+
extend CarefulColorize
|
48
|
+
colorize canvas, color
|
49
|
+
else
|
50
|
+
raise
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def drag_colorize canvas
|
55
|
+
colorize canvas, DRAG_COLOR
|
56
|
+
end
|
57
|
+
|
58
|
+
def hover_colorize canvas
|
59
|
+
colorize canvas, HOVER_COLOR
|
60
|
+
end
|
61
|
+
|
62
|
+
def decolorize canvas
|
63
|
+
colorize canvas, nil
|
64
|
+
update canvas
|
65
|
+
end
|
66
|
+
|
67
|
+
def update canvas, zoom=canvas.zoom
|
68
|
+
tags = [tag]
|
69
|
+
result = @newly_added
|
70
|
+
|
71
|
+
if @newly_added
|
72
|
+
@shape[self].each do |klass, coords, config|
|
73
|
+
coords.map! {|x| x*zoom} if zoom
|
74
|
+
coords << config
|
75
|
+
part = klass.new(canvas, *coords)
|
76
|
+
@parts << part
|
77
|
+
part.raise tag rescue nil
|
78
|
+
part.tags tags
|
79
|
+
end
|
80
|
+
@newly_added = false
|
81
|
+
|
82
|
+
else
|
83
|
+
i = 0
|
84
|
+
@shape[self].each do |klass, coords, config|
|
85
|
+
part = parts[i]; i += 1
|
86
|
+
coords.map! {|x| x*zoom} if zoom
|
87
|
+
part.coords(*coords)
|
88
|
+
part.configure(config)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
return result
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/lib/tkar/window.rb
ADDED
@@ -0,0 +1,383 @@
|
|
1
|
+
require 'tk'
|
2
|
+
require 'tkar/canvas'
|
3
|
+
require 'tkar/help-window'
|
4
|
+
|
5
|
+
module Tkar
|
6
|
+
class Window
|
7
|
+
attr_reader :canvas
|
8
|
+
|
9
|
+
HELP_ICON = TkPhotoImage.new(
|
10
|
+
:format => 'GIF',
|
11
|
+
#:file => 'sample/help.gif'
|
12
|
+
:data => %{
|
13
|
+
R0lGODlhCAAIAMIEAKK1zQAAAIQAAP//AP///////////////yH5BAEKAAcA\nLAAAAAAIAA
|
14
|
+
gAAAMQSBQcug6qON9kFtud6dNEAgA7\n
|
15
|
+
}
|
16
|
+
)
|
17
|
+
|
18
|
+
## cmds to show grid, save image, make movie
|
19
|
+
## preferences
|
20
|
+
|
21
|
+
def initialize root, opts
|
22
|
+
@flip = opts["flip"]
|
23
|
+
|
24
|
+
canvas_frame = TkFrame.new(root) do
|
25
|
+
pack 'fill'=>'both', 'expand'=>true
|
26
|
+
background "lightgray"
|
27
|
+
end
|
28
|
+
TkGrid.rowconfigure(canvas_frame, 0, 'weight'=>1, 'minsize'=>0)
|
29
|
+
TkGrid.columnconfigure(canvas_frame, 0, 'weight'=>1, 'minsize'=>0)
|
30
|
+
|
31
|
+
@canvas = canvas = Tkar::Canvas.new(canvas_frame) do
|
32
|
+
@bounds = [-3000, -3000, 3000, 3000]
|
33
|
+
background "gray"
|
34
|
+
relief "sunken"
|
35
|
+
width 100; height 100 ## user prefs?
|
36
|
+
configure :scrollregion => @bounds
|
37
|
+
xscrollincrement 1
|
38
|
+
yscrollincrement 1
|
39
|
+
grid(:in => canvas_frame,
|
40
|
+
:row => 0, :column => 0,
|
41
|
+
:rowspan => 1, :columnspan => 1, :sticky => :news)
|
42
|
+
@root = root
|
43
|
+
end
|
44
|
+
|
45
|
+
xscroll = TkScrollbar.new(canvas_frame) do
|
46
|
+
background 'darkgray'
|
47
|
+
width 10
|
48
|
+
relief "sunken"
|
49
|
+
command do |*args|
|
50
|
+
canvas.xview *args
|
51
|
+
end
|
52
|
+
grid(:in => canvas_frame,
|
53
|
+
:row => 1, :column => 0,
|
54
|
+
:rowspan => 1, :columnspan => 1, :sticky => :news)
|
55
|
+
orient 'horiz'
|
56
|
+
end
|
57
|
+
|
58
|
+
yscroll = TkScrollbar.new(canvas_frame) do
|
59
|
+
background 'darkgray'
|
60
|
+
width 10
|
61
|
+
relief "sunken"
|
62
|
+
command do |*args|
|
63
|
+
canvas.yview *args
|
64
|
+
end
|
65
|
+
grid(:in => canvas_frame,
|
66
|
+
:row => 0, :column => 1,
|
67
|
+
:rowspan => 1, :columnspan => 1, :sticky => :news)
|
68
|
+
orient 'vertical'
|
69
|
+
end
|
70
|
+
|
71
|
+
TkButton.new(canvas_frame) do
|
72
|
+
image HELP_ICON
|
73
|
+
compound :none
|
74
|
+
relief "flat"
|
75
|
+
command {HelpWindow.show}
|
76
|
+
grid(:in => canvas_frame,
|
77
|
+
:row => 1, :column => 1,
|
78
|
+
:rowspan => 1, :columnspan => 1, :sticky => :news)
|
79
|
+
end
|
80
|
+
|
81
|
+
canvas.xscrollcommand do |first, last|
|
82
|
+
xscroll.set(first, last)
|
83
|
+
end
|
84
|
+
canvas.yscrollcommand do |first, last|
|
85
|
+
yscroll.set(first, last)
|
86
|
+
end
|
87
|
+
|
88
|
+
root.bind "Key-Right" do
|
89
|
+
canvas.xview "scroll", 10, "units"
|
90
|
+
end
|
91
|
+
|
92
|
+
root.bind "Key-Left" do
|
93
|
+
canvas.xview "scroll", -10, "units"
|
94
|
+
end
|
95
|
+
|
96
|
+
root.bind "Key-Down" do
|
97
|
+
canvas.yview "scroll", 10, "units"
|
98
|
+
end
|
99
|
+
|
100
|
+
root.bind "Key-Up" do
|
101
|
+
canvas.yview "scroll", -10, "units"
|
102
|
+
end
|
103
|
+
|
104
|
+
root.bind "Alt-Key-Right" do
|
105
|
+
canvas.xview "scroll", 1, "units"
|
106
|
+
end
|
107
|
+
|
108
|
+
root.bind "Alt-Key-Left" do
|
109
|
+
canvas.xview "scroll", -1, "units"
|
110
|
+
end
|
111
|
+
|
112
|
+
root.bind "Alt-Key-Down" do
|
113
|
+
canvas.yview "scroll", 1, "units"
|
114
|
+
end
|
115
|
+
|
116
|
+
root.bind "Alt-Key-Up" do
|
117
|
+
canvas.yview "scroll", -1, "units"
|
118
|
+
end
|
119
|
+
|
120
|
+
root.bind "Control-Up" do
|
121
|
+
canvas.zoom_by 0.75
|
122
|
+
end
|
123
|
+
|
124
|
+
root.bind "Control-Down" do
|
125
|
+
canvas.zoom_by 1.5
|
126
|
+
end
|
127
|
+
|
128
|
+
root.bind "Key-h" do
|
129
|
+
HelpWindow.show
|
130
|
+
end
|
131
|
+
|
132
|
+
root.bind "Control-q" do
|
133
|
+
exit
|
134
|
+
end
|
135
|
+
|
136
|
+
at_exit do
|
137
|
+
message_out "quit"
|
138
|
+
end
|
139
|
+
|
140
|
+
drag_start = drag_dx = drag_dy = drag_tkaroid = click_tkaroid = nil
|
141
|
+
drop_target = nil
|
142
|
+
drag_timer = nil
|
143
|
+
|
144
|
+
drag_proc = proc do |x, y|
|
145
|
+
if drop_target
|
146
|
+
drop_target.decolorize(canvas)
|
147
|
+
drop_target = nil # we'll check below if it still is
|
148
|
+
end
|
149
|
+
|
150
|
+
tkaroid = canvas.current_tkaroid
|
151
|
+
if tkaroid and tkaroid.draggable?
|
152
|
+
drag_tkaroid = tkaroid
|
153
|
+
x0, y0 = drag_start
|
154
|
+
|
155
|
+
drag_dx = (x-x0)/canvas.zoom
|
156
|
+
drag_dy = (y-y0)/canvas.zoom
|
157
|
+
new_x, new_y = tkaroid.x + drag_dx, tkaroid.y + drag_dy
|
158
|
+
canvas.moveto(tkaroid.id, new_x, new_y)
|
159
|
+
msg_x, msg_y = new_x, new_y
|
160
|
+
if @flip
|
161
|
+
msg_y = -msg_y
|
162
|
+
end
|
163
|
+
message_out "drag #{tkaroid.id} #{msg_x} #{msg_y}"
|
164
|
+
tkaroid.update(canvas)
|
165
|
+
tkaroid.drag_colorize(canvas)
|
166
|
+
drag_start = [x, y]
|
167
|
+
|
168
|
+
cx = canvas.canvasx(x)
|
169
|
+
cy = canvas.canvasy(y)
|
170
|
+
closest = canvas.find_closest(cx, cy, 0, "all") # start at top
|
171
|
+
tags = closest.map {|prim|prim.tag}.flatten
|
172
|
+
if tags.include? "current"
|
173
|
+
closest = canvas.find_closest(cx, cy, 0, "current")
|
174
|
+
tags = closest.map {|prim|prim.tag}.flatten
|
175
|
+
end
|
176
|
+
|
177
|
+
unless tags.include? "current"
|
178
|
+
tkar_id = tags.grep(/^tkar\d+$/).first[/\d+/].to_i
|
179
|
+
tgt = canvas.get_object tkar_id
|
180
|
+
if tgt.drop_target? and tgt != drag_tkaroid
|
181
|
+
drop_target = tgt
|
182
|
+
drop_target.hover_colorize(canvas)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
drag_outside = proc do |x, y|
|
189
|
+
drag_timer = TkTimer.new(50) do
|
190
|
+
# scroll canvas if out of window if needed
|
191
|
+
width = canvas.current_width
|
192
|
+
height = canvas.current_height
|
193
|
+
units = 10
|
194
|
+
xsi = canvas.cget("xscrollincrement")*units
|
195
|
+
ysi = canvas.cget("yscrollincrement")*units
|
196
|
+
|
197
|
+
if x < 0
|
198
|
+
canvas.xview "scroll", -units, "units"
|
199
|
+
x = -xsi
|
200
|
+
if drag_start
|
201
|
+
x0,y0 = drag_start
|
202
|
+
drag_start = [x0 + xsi, y0]
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
if x > width
|
207
|
+
canvas.xview "scroll", units, "units"
|
208
|
+
x = width + xsi
|
209
|
+
if drag_start
|
210
|
+
x0,y0 = drag_start
|
211
|
+
drag_start = [x0 - xsi, y0]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
if y < 0
|
216
|
+
canvas.yview "scroll", -units, "units"
|
217
|
+
y = -ysi
|
218
|
+
if drag_start
|
219
|
+
x0,y0 = drag_start
|
220
|
+
drag_start = [x0, y0 + ysi]
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
if y > height
|
225
|
+
canvas.yview "scroll", units, "units"
|
226
|
+
y = height + ysi
|
227
|
+
if drag_start
|
228
|
+
x0,y0 = drag_start
|
229
|
+
drag_start = [x0, y0 - ysi]
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
drag_proc[x,y] if drag_start
|
234
|
+
end
|
235
|
+
drag_timer.start
|
236
|
+
end
|
237
|
+
|
238
|
+
canvas.bind('B1-Motion', '%x %y') do |x, y|
|
239
|
+
if drag_timer
|
240
|
+
drag_timer.stop
|
241
|
+
drag_timer = nil
|
242
|
+
end
|
243
|
+
|
244
|
+
if x >= 0 and x <= canvas.current_width and
|
245
|
+
y >= 0 and y <= canvas.current_height
|
246
|
+
drag_proc[x,y] if drag_start
|
247
|
+
else
|
248
|
+
drag_outside[x,y] if drag_start
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
canvas.bind('B1-ButtonRelease', '%x %y') do |x, y|
|
253
|
+
if drag_timer
|
254
|
+
drag_timer.stop
|
255
|
+
drag_timer = nil
|
256
|
+
end
|
257
|
+
|
258
|
+
if drag_tkaroid
|
259
|
+
drag_tkaroid.hover_colorize(canvas)
|
260
|
+
|
261
|
+
if drop_target
|
262
|
+
message_out "drop #{drag_tkaroid.id} #{drop_target.id}"
|
263
|
+
drop_target.decolorize(canvas)
|
264
|
+
else
|
265
|
+
message_out "drop #{drag_tkaroid.id}"
|
266
|
+
end
|
267
|
+
|
268
|
+
# if mouse is now over a NEW object
|
269
|
+
# leave the old object
|
270
|
+
# enter the new object
|
271
|
+
# (since Tk doesn't seem to generate leave and enter events)
|
272
|
+
cx = canvas.canvasx(x)
|
273
|
+
cy = canvas.canvasy(y)
|
274
|
+
closest = canvas.find_closest(cx, cy, 0, "all") # start at top
|
275
|
+
tags = closest.map {|prim|prim.tag}.flatten
|
276
|
+
tkar_id = tags.grep(/^tkar\d+$/).first[/\d+/].to_i
|
277
|
+
top_tkaroid = canvas.get_object tkar_id
|
278
|
+
if top_tkaroid != drag_tkaroid
|
279
|
+
drag_tkaroid.update(canvas)
|
280
|
+
top_tkaroid.hover_colorize(canvas) if top_tkaroid
|
281
|
+
end
|
282
|
+
|
283
|
+
elsif click_tkaroid
|
284
|
+
click_tkaroid.hover_colorize(canvas)
|
285
|
+
end
|
286
|
+
|
287
|
+
drag_start = drag_dx = drag_dy = drag_tkaroid = drop_target = nil
|
288
|
+
click_tkaroid = nil
|
289
|
+
end
|
290
|
+
|
291
|
+
zoom_start = nil
|
292
|
+
canvas.bind('2', '%x %y') {|x,y| zoom_start = y}
|
293
|
+
canvas.bind('B2-Motion', '%x %y') {|x,y|
|
294
|
+
canvas.zoom_by(1 + (y - zoom_start)/500.0)
|
295
|
+
zoom_start = y
|
296
|
+
}
|
297
|
+
|
298
|
+
canvas.bind('3', '%x %y') {|x,y| canvas.scan_mark(x,y)}
|
299
|
+
canvas.bind('B3-Motion', '%x %y') {|x,y| canvas.scan_dragto(x,y,1)}
|
300
|
+
canvas.bind('Control-B3-Motion', '%x %y') {|x,y|
|
301
|
+
canvas.scan_dragto(x,y,3)}
|
302
|
+
|
303
|
+
small_zoom = 0.95
|
304
|
+
large_zoom = 0.75
|
305
|
+
|
306
|
+
canvas.bind('4') {canvas.zoom_by small_zoom}
|
307
|
+
canvas.bind('5') {canvas.zoom_by 1/small_zoom}
|
308
|
+
|
309
|
+
# For X windows:
|
310
|
+
canvas.bind('Control-4') {canvas.zoom_by large_zoom}
|
311
|
+
canvas.bind('Control-5') {canvas.zoom_by 1/large_zoom}
|
312
|
+
|
313
|
+
# For MSWindows:
|
314
|
+
root.bind('MouseWheel', "%D") { |delta|
|
315
|
+
canvas.zoom_by small_zoom**(delta/120)
|
316
|
+
}
|
317
|
+
root.bind('Control-MouseWheel', "%D") { |delta|
|
318
|
+
canvas.zoom_by large_zoom**(delta/120)
|
319
|
+
}
|
320
|
+
|
321
|
+
canvas.bind('Control-1', '%x %y') do |x, y|
|
322
|
+
tkaroid = canvas.current_tkaroid
|
323
|
+
if tkaroid
|
324
|
+
# handled in itembind('Control-1')
|
325
|
+
else
|
326
|
+
canvas.follow(nil)
|
327
|
+
canvas.view_at_screen(x,y)
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
canvas.itembind('all', '1', '%x %y') do |x, y|
|
332
|
+
tkaroid = canvas.current_tkaroid
|
333
|
+
if tkaroid
|
334
|
+
if tkaroid.draggable?
|
335
|
+
drag_start = [x, y]
|
336
|
+
tkaroid.drag_colorize(canvas)
|
337
|
+
end
|
338
|
+
message_out "click #{tkaroid.id}"
|
339
|
+
end
|
340
|
+
click_tkaroid = tkaroid
|
341
|
+
end
|
342
|
+
|
343
|
+
canvas.itembind('all', 'Control-1', '%x %y') do |x, y|
|
344
|
+
tkaroid = canvas.current_tkaroid
|
345
|
+
if tkaroid
|
346
|
+
if tkaroid.id == canvas.follow_id
|
347
|
+
canvas.follow(nil)
|
348
|
+
else
|
349
|
+
canvas.follow(tkaroid.id)
|
350
|
+
canvas.view_followed_obj
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
canvas.itembind('all', 'Double-1') do
|
356
|
+
tkaroid = canvas.current_tkaroid
|
357
|
+
message_out "doubleclick #{tkaroid.id}" if tkaroid
|
358
|
+
end
|
359
|
+
|
360
|
+
canvas.itembind('all', 'Any-Enter') do
|
361
|
+
unless drag_start
|
362
|
+
tkaroid = canvas.current_tkaroid
|
363
|
+
if tkaroid
|
364
|
+
tkaroid.hover_colorize(canvas)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
canvas.itembind('all', 'Any-Leave') do
|
370
|
+
tkaroid = canvas.current_tkaroid
|
371
|
+
tkaroid.decolorize(canvas) if tkaroid
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
def message_out msg
|
376
|
+
@message_out[msg] if @message_out
|
377
|
+
end
|
378
|
+
|
379
|
+
def def_message_out(&bl)
|
380
|
+
@message_out = bl
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|