tkar 0.63
Sign up to get free protection for your applications and to get access to all the features.
- 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
|