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.
@@ -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
@@ -0,0 +1,5 @@
1
+
2
+ module Tkar
3
+ VERSION = '0.63'
4
+ end
5
+
@@ -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