1#
2# tk/canvastag.rb - methods for treating canvas tags
3#
4require 'tk'
5require 'tk/tagfont'
6
7module TkcTagAccess
8  include TkComm
9  include TkTreatTagFont
10end
11
12require 'tk/canvas'
13
14module TkcTagAccess
15  def addtag(tag)
16    @c.addtag(tag, 'withtag', @id)
17    self
18  end
19
20  def bbox
21    @c.bbox(@id)
22  end
23
24  #def bind(seq, cmd=Proc.new, *args)
25  #  @c.itembind(@id, seq, cmd, *args)
26  #  self
27  #end
28  def bind(seq, *args)
29    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
30    if TkComm._callback_entry?(args[0]) || !block_given?
31      cmd = args.shift
32    else
33      cmd = Proc.new
34    end
35    @c.itembind(@id, seq, cmd, *args)
36    self
37  end
38
39  #def bind_append(seq, cmd=Proc.new, *args)
40  #  @c.itembind_append(@id, seq, cmd, *args)
41  #  self
42  #end
43  def bind_append(seq, *args)
44    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
45    if TkComm._callback_entry?(args[0]) || !block_given?
46      cmd = args.shift
47    else
48      cmd = Proc.new
49    end
50    @c.itembind_append(@id, seq, cmd, *args)
51    self
52  end
53
54  def bind_remove(seq)
55    @c.itembind_remove(@id, seq)
56    self
57  end
58
59  def bindinfo(seq=nil)
60    @c.itembindinfo(@id, seq)
61  end
62
63  def cget_tkstring(option)
64    @c.itemcget_tkstring(@id, option)
65  end
66  def cget(option)
67    @c.itemcget(@id, option)
68  end
69  def cget_strict(option)
70    @c.itemcget_strict(@id, option)
71  end
72
73  def configure(key, value=None)
74    @c.itemconfigure(@id, key, value)
75    self
76  end
77#  def configure(keys)
78#    @c.itemconfigure @id, keys
79#  end
80
81  def configinfo(key=nil)
82    @c.itemconfiginfo(@id, key)
83  end
84
85  def current_configinfo(key=nil)
86    @c.current_itemconfiginfo(@id, key)
87  end
88
89  def coords(*args)
90    @c.coords(@id, *args)
91  end
92
93  def dchars(first, last=None)
94    @c.dchars(@id, first, last)
95    self
96  end
97
98  def dtag(tag_to_del=None)
99    @c.dtag(@id, tag_to_del)
100    self
101  end
102  alias deltag dtag
103
104  def find
105    @c.find('withtag', @id)
106  end
107  alias list find
108
109  def focus
110    @c.itemfocus(@id)
111  end
112
113  def gettags
114    @c.gettags(@id)
115  end
116
117  def icursor(index)
118    @c.icursor(@id, index)
119    self
120  end
121
122  def imove(idx, x, y)
123    # Tcl/Tk 8.6 or later
124    @c.imove(@id, idx, x, y)
125    self
126  end
127  alias i_move imove
128
129  def index(idx)
130    @c.index(@id, idx)
131  end
132
133  def insert(beforethis, string)
134    @c.insert(@id, beforethis, string)
135    self
136  end
137
138  def lower(belowthis=None)
139    @c.lower(@id, belowthis)
140    self
141  end
142
143  def move(xamount, yamount)
144    @c.move(@id, xamount, yamount)
145    self
146  end
147
148  def moveto(x, y)
149    # Tcl/Tk 8.6 or later
150    @c.moveto(@id, x, y)
151    self
152  end
153  alias move_to moveto
154
155  def raise(abovethis=None)
156    @c.raise(@id, abovethis)
157    self
158  end
159
160  def scale(xorigin, yorigin, xscale, yscale)
161    @c.scale(@id, xorigin, yorigin, xscale, yscale)
162    self
163  end
164
165  def rchars(first, last, str_or_coords)
166    # Tcl/Tk 8.6 or later
167    @c.rchars(@id, first, last, str_or_coords)
168    self
169  end
170  alias replace_chars rchars
171  alias replace_coords rchars
172
173  def select_adjust(index)
174    @c.select('adjust', @id, index)
175    self
176  end
177  def select_from(index)
178    @c.select('from', @id, index)
179    self
180  end
181  def select_to(index)
182    @c.select('to', @id, index)
183    self
184  end
185
186  def itemtype
187    @c.itemtype(@id)
188  end
189
190  # Following operators support logical expressions of canvas tags
191  # (for Tk8.3+).
192  # If tag1.path is 't1' and tag2.path is 't2', then
193  #      ltag = tag1 & tag2; ltag.path => "(t1)&&(t2)"
194  #      ltag = tag1 | tag2; ltag.path => "(t1)||(t2)"
195  #      ltag = tag1 ^ tag2; ltag.path => "(t1)^(t2)"
196  #      ltag = - tag1;      ltag.path => "!(t1)"
197  def & (tag)
198    if tag.kind_of? TkObject
199      TkcTagString.new(@c, '(' + @id + ')&&(' + tag.path + ')')
200    else
201      TkcTagString.new(@c, '(' + @id + ')&&(' + tag.to_s + ')')
202    end
203  end
204
205  def | (tag)
206    if tag.kind_of? TkObject
207      TkcTagString.new(@c, '(' + @id + ')||(' + tag.path + ')')
208    else
209      TkcTagString.new(@c, '(' + @id + ')||(' + tag.to_s + ')')
210    end
211  end
212
213  def ^ (tag)
214    if tag.kind_of? TkObject
215      TkcTagString.new(@c, '(' + @id + ')^(' + tag.path + ')')
216    else
217      TkcTagString.new(@c, '(' + @id + ')^(' + tag.to_s + ')')
218    end
219  end
220
221  def -@
222    TkcTagString.new(@c, '!(' + @id + ')')
223  end
224end
225
226class TkcTag<TkObject
227  include TkcTagAccess
228
229  CTagID_TBL = TkCore::INTERP.create_table
230
231  (Tk_CanvasTag_ID = ['ctag'.freeze, TkUtil.untrust('00000')]).instance_eval{
232    @mutex = Mutex.new
233    def mutex; @mutex; end
234    freeze
235  }
236
237  TkCore::INTERP.init_ip_env{
238    CTagID_TBL.mutex.synchronize{ CTagID_TBL.clear }
239  }
240
241  def TkcTag.id2obj(canvas, id)
242    cpath = canvas.path
243    CTagID_TBL.mutex.synchronize{
244      if CTagID_TBL[cpath]
245        CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id
246      else
247        id
248      end
249    }
250  end
251
252  def initialize(parent, mode=nil, *args)
253    #unless parent.kind_of?(TkCanvas)
254    #  fail ArgumentError, "expect TkCanvas for 1st argument"
255    #end
256    @c = parent
257    @cpath = parent.path
258    Tk_CanvasTag_ID.mutex.synchronize{
259      # @path = @id = Tk_CanvasTag_ID.join('')
260      @path = @id = Tk_CanvasTag_ID.join(TkCore::INTERP._ip_id_)
261      Tk_CanvasTag_ID[1].succ!
262    }
263    CTagID_TBL.mutex.synchronize{
264      CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
265      CTagID_TBL[@cpath][@id] = self
266    }
267    if mode
268      tk_call_without_enc(@c.path, "addtag", @id, mode, *args)
269    end
270  end
271  def id
272    @id
273  end
274
275  def exist?
276    if @c.find_withtag(@id)
277      true
278    else
279      false
280    end
281  end
282
283  def delete
284    @c.delete @id
285    CTagID_TBL.mutex.synchronize{
286      CTagID_TBL[@cpath].delete(@id) if CTagID_TBL[@cpath]
287    }
288    self
289  end
290  alias remove  delete
291  alias destroy delete
292
293  def set_to_above(target)
294    @c.addtag_above(@id, target)
295    self
296  end
297  alias above set_to_above
298
299  def set_to_all
300    @c.addtag_all(@id)
301    self
302  end
303  alias all set_to_all
304
305  def set_to_below(target)
306    @c.addtag_below(@id, target)
307    self
308  end
309  alias below set_to_below
310
311  def set_to_closest(x, y, halo=None, start=None)
312    @c.addtag_closest(@id, x, y, halo, start)
313    self
314  end
315  alias closest set_to_closest
316
317  def set_to_enclosed(x1, y1, x2, y2)
318    @c.addtag_enclosed(@id, x1, y1, x2, y2)
319    self
320  end
321  alias enclosed set_to_enclosed
322
323  def set_to_overlapping(x1, y1, x2, y2)
324    @c.addtag_overlapping(@id, x1, y1, x2, y2)
325    self
326  end
327  alias overlapping set_to_overlapping
328
329  def set_to_withtag(target)
330    @c.addtag_withtag(@id, target)
331    self
332  end
333  alias withtag set_to_withtag
334end
335
336class TkcTagString<TkcTag
337  def self.new(parent, name, mode=nil, *args)
338    obj = nil
339    CTagID_TBL.mutex.synchronize{
340      if CTagID_TBL[parent.path] && CTagID_TBL[parent.path][name]
341        obj = CTagID_TBL[parent.path][name]
342      else
343        # super(parent, name, *args)
344        (obj = self.allocate).instance_eval{
345          @c = parent
346          @cpath = parent.path
347          @path = @id = name
348          CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
349          CTagID_TBL[@cpath][@id] = self
350        }
351      end
352    }
353    if obj && mode
354      tk_call_without_enc(@c.path, "addtag", @id, mode, *args)
355    end
356    obj
357  end
358
359  def initialize(parent, name, mode=nil, *args)
360    # dummy:: not called by 'new' method
361
362    #unless parent.kind_of?(TkCanvas)
363    #  fail ArgumentError, "expect TkCanvas for 1st argument"
364    #end
365    @c = parent
366    @cpath = parent.path
367    @path = @id = name
368
369    if mode
370      tk_call_without_enc(@c.path, "addtag", @id, mode, *args)
371    end
372  end
373end
374TkcNamedTag = TkcTagString
375
376class TkcTagAll<TkcTagString
377  def self.new(parent)
378    super(parent, 'all')
379  end
380=begin
381  def initialize(parent)
382    #unless parent.kind_of?(TkCanvas)
383    #  fail ArgumentError, "expect TkCanvas for 1st argument"
384    #end
385    @c = parent
386    @cpath = parent.path
387    @path = @id = 'all'
388    CTagID_TBL.mutex.synchronize{
389      CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
390      CTagID_TBL[@cpath][@id] = self
391    }
392  end
393=end
394end
395
396class TkcTagCurrent<TkcTagString
397  def self.new(parent)
398    super(parent, 'current')
399  end
400=begin
401  def initialize(parent)
402    #unless parent.kind_of?(TkCanvas)
403    #  fail ArgumentError, "expect TkCanvas for 1st argument"
404    #end
405    @c = parent
406    @cpath = parent.path
407    @path = @id = 'current'
408    CTagID_TBL.mutex.synchronize{
409      CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
410      CTagID_TBL[@cpath][@id] = self
411    }
412  end
413=end
414end
415
416class TkcGroup<TkcTag
417  (Tk_cGroup_ID = ['tkcg'.freeze, TkUtil.untrust('00000')]).instance_eval{
418    @mutex = Mutex.new
419    def mutex; @mutex; end
420    freeze
421  }
422
423  #def create_self(parent, *args)
424  def initialize(parent, *args)
425    #unless parent.kind_of?(TkCanvas)
426    #  fail ArgumentError, "expect TkCanvas for 1st argument"
427    #end
428    @c = parent
429    @cpath = parent.path
430    Tk_cGroup_ID.mutex.synchronize{
431      # @path = @id = Tk_cGroup_ID.join('')
432      @path = @id = Tk_cGroup_ID.join(TkCore::INTERP._ip_id_)
433      Tk_cGroup_ID[1].succ!
434    }
435    CTagID_TBL.mutex.synchronize{
436      CTagID_TBL[@cpath] = {} unless CTagID_TBL[@cpath]
437      CTagID_TBL[@cpath][@id] = self
438    }
439    include(*args) if args != []
440  end
441  #private :create_self
442
443  def include(*tags)
444    for i in tags
445      #i.addtag(@id)
446      @c.addtag_withtag(@id, i)
447    end
448    self
449  end
450  alias add include
451
452  def exclude(*tags)
453    for i in tags
454      #i.dtag(@id)
455      @c.dtag(i, @id)
456    end
457    self
458  end
459end
460