1#
2# tk/texttag.rb - methods for treating text tags
3#
4require 'tk'
5require 'tk/text'
6require 'tk/tagfont'
7
8class TkTextTag<TkObject
9  include TkTreatTagFont
10  include Tk::Text::IndexModMethods
11
12  TTagID_TBL = TkCore::INTERP.create_table
13
14  (Tk_TextTag_ID = ['tag'.freeze, TkUtil.untrust('00000')]).instance_eval{
15    @mutex = Mutex.new
16    def mutex; @mutex; end
17    freeze
18  }
19
20  TkCore::INTERP.init_ip_env{
21    TTagID_TBL.mutex.synchronize{ TTagID_TBL.clear }
22  }
23
24  def TkTextTag.id2obj(text, id)
25    tpath = text.path
26    TTagID_TBL.mutex.synchronize{
27      if TTagID_TBL[tpath]
28        TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id
29      else
30        id
31      end
32    }
33  end
34
35  def initialize(parent, *args)
36    #unless parent.kind_of?(TkText)
37    #  fail ArgumentError, "expect TkText for 1st argument"
38    #end
39    @parent = @t = parent
40    @tpath = parent.path
41    Tk_TextTag_ID.mutex.synchronize{
42      # @path = @id = Tk_TextTag_ID.join('')
43      @path = @id = Tk_TextTag_ID.join(TkCore::INTERP._ip_id_).freeze
44      Tk_TextTag_ID[1].succ!
45    }
46    TTagID_TBL.mutex.synchronize{
47      TTagID_TBL[@id] = self
48      TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath]
49      TTagID_TBL[@tpath][@id] = self
50    }
51    #tk_call @t.path, "tag", "configure", @id, *hash_kv(keys)
52    if args != []
53      keys = args.pop
54      if keys.kind_of?(Hash)
55        add(*args) if args != []
56        configure(keys)
57      else
58        args.push keys
59        add(*args)
60      end
61    end
62    @t._addtag id, self
63  end
64
65  def id
66    Tk::Text::IndexString.new(@id)
67  end
68
69  def exist?
70    #if ( tk_split_simplelist(_fromUTF8(tk_call_without_enc(@t.path, 'tag', 'names'))).find{|id| id == @id } )
71    if ( tk_split_simplelist(tk_call_without_enc(@t.path, 'tag', 'names'), false, true).find{|id| id == @id } )
72      true
73    else
74      false
75    end
76  end
77
78  def first
79    Tk::Text::IndexString.new(@id + '.first')
80  end
81
82  def last
83    Tk::Text::IndexString.new(@id + '.last')
84  end
85
86  def add(*indices)
87    tk_call_without_enc(@t.path, 'tag', 'add', @id,
88                        *(indices.collect{|idx| _get_eval_enc_str(idx)}))
89    self
90  end
91
92  def remove(*indices)
93    tk_call_without_enc(@t.path, 'tag', 'remove', @id,
94                        *(indices.collect{|idx| _get_eval_enc_str(idx)}))
95    self
96  end
97
98  def ranges
99    l = tk_split_simplelist(tk_call_without_enc(@t.path, 'tag', 'ranges', @id))
100    r = []
101    while key=l.shift
102      r.push [Tk::Text::IndexString.new(key), Tk::Text::IndexString.new(l.shift)]
103    end
104    r
105  end
106
107  def nextrange(first, last=None)
108    simplelist(tk_call_without_enc(@t.path, 'tag', 'nextrange', @id,
109                                   _get_eval_enc_str(first),
110                                   _get_eval_enc_str(last))).collect{|idx|
111      Tk::Text::IndexString.new(idx)
112    }
113  end
114
115  def prevrange(first, last=None)
116    simplelist(tk_call_without_enc(@t.path, 'tag', 'prevrange', @id,
117                                   _get_eval_enc_str(first),
118                                   _get_eval_enc_str(last))).collect{|idx|
119      Tk::Text::IndexString.new(idx)
120    }
121  end
122
123  def [](key)
124    cget key
125  end
126
127  def []=(key,val)
128    configure key, val
129    val
130  end
131
132  def cget_tkstring(key)
133    @t.tag_cget_tkstring @id, key
134  end
135  def cget(key)
136    @t.tag_cget @id, key
137  end
138  def cget_strict(key)
139    @t.tag_cget_strict @id, key
140  end
141=begin
142  def cget(key)
143    case key.to_s
144    when 'text', 'label', 'show', 'data', 'file'
145      _fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget', @id, "-#{key}"))
146    when 'font', 'kanjifont'
147      #fnt = tk_tcl2ruby(tk_call(@t.path, 'tag', 'cget', @id, "-#{key}"))
148      fnt = tk_tcl2ruby(_fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget',
149                                                      @id, '-font')))
150      unless fnt.kind_of?(TkFont)
151        fnt = tagfontobj(@id, fnt)
152      end
153      if key.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/
154        # obsolete; just for compatibility
155        fnt.kanji_font
156      else
157        fnt
158      end
159    else
160      tk_tcl2ruby(_fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget',
161                                                @id, "-#{key}")))
162    end
163  end
164=end
165
166  def configure(key, val=None)
167    @t.tag_configure @id, key, val
168  end
169#  def configure(key, val=None)
170#    if key.kind_of?(Hash)
171#      tk_call @t.path, 'tag', 'configure', @id, *hash_kv(key)
172#    else
173#      tk_call @t.path, 'tag', 'configure', @id, "-#{key}", val
174#    end
175#  end
176#  def configure(key, value)
177#    if value == FALSE
178#      value = "0"
179#    elsif value.kind_of?(Proc)
180#      value = install_cmd(value)
181#    end
182#    tk_call @t.path, 'tag', 'configure', @id, "-#{key}", value
183#  end
184
185  def configinfo(key=nil)
186    @t.tag_configinfo @id, key
187  end
188
189  def current_configinfo(key=nil)
190    @t.current_tag_configinfo @id, key
191  end
192
193  #def bind(seq, cmd=Proc.new, *args)
194  #  _bind([@t.path, 'tag', 'bind', @id], seq, cmd, *args)
195  #  self
196  #end
197  def bind(seq, *args)
198    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
199    if TkComm._callback_entry?(args[0]) || !block_given?
200      cmd = args.shift
201    else
202      cmd = Proc.new
203    end
204    _bind([@t.path, 'tag', 'bind', @id], seq, cmd, *args)
205    self
206  end
207
208  #def bind_append(seq, cmd=Proc.new, *args)
209  #  _bind_append([@t.path, 'tag', 'bind', @id], seq, cmd, *args)
210  #  self
211  #end
212  def bind_append(seq, *args)
213    # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
214    if TkComm._callback_entry?(args[0]) || !block_given?
215      cmd = args.shift
216    else
217      cmd = Proc.new
218    end
219    _bind_append([@t.path, 'tag', 'bind', @id], seq, cmd, *args)
220    self
221  end
222
223  def bind_remove(seq)
224    _bind_remove([@t.path, 'tag', 'bind', @id], seq)
225    self
226  end
227
228  def bindinfo(context=nil)
229    _bindinfo([@t.path, 'tag', 'bind', @id], context)
230  end
231
232  def raise(above=None)
233    tk_call_without_enc(@t.path, 'tag', 'raise', @id,
234                        _get_eval_enc_str(above))
235    self
236  end
237
238  def lower(below=None)
239    tk_call_without_enc(@t.path, 'tag', 'lower', @id,
240                        _get_eval_enc_str(below))
241    self
242  end
243
244  def destroy
245    tk_call_without_enc(@t.path, 'tag', 'delete', @id)
246    TTagID_TBL.mutex.synchronize{
247      TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath]
248    }
249    self
250  end
251end
252TktTag = TkTextTag
253
254class TkTextNamedTag<TkTextTag
255  def self.new(parent, name, *args)
256    tagobj = nil
257    TTagID_TBL.mutex.synchronize{
258      if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name]
259        tagobj = TTagID_TBL[parent.path][name]
260      else
261        # super(parent, name, *args)
262        (tagobj = self.allocate).instance_eval{
263          @parent = @t = parent
264          @tpath = parent.path
265          @path = @id = name
266          TTagID_TBL[@id] = self
267          TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath]
268          TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id]
269          @t._addtag @id, self
270        }
271      end
272    }
273
274    if args != []
275      keys = args.pop
276      if keys.kind_of?(Hash)
277        tagobj.add(*args) if args != []
278        tagobj.configure(keys)
279      else
280        args.push keys
281        tagobj.add(*args)
282      end
283    end
284
285    tagobj
286  end
287
288  def initialize(parent, name, *args)
289    # dummy:: not called by 'new' method
290
291    #unless parent.kind_of?(Tk::Text)
292    #  fail ArgumentError, "expect Tk::Text for 1st argument"
293    #end
294    @parent = @t = parent
295    @tpath = parent.path
296    @path = @id = name
297
298    #if mode
299    #  tk_call @t.path, "addtag", @id, *args
300    #end
301    if args != []
302      keys = args.pop
303      if keys.kind_of?(Hash)
304        add(*args) if args != []
305        configure(keys)
306      else
307        args.push keys
308        add(*args)
309      end
310    end
311    @t._addtag @id, self
312  end
313end
314TktNamedTag = TkTextNamedTag
315
316class TkTextTagSel<TkTextNamedTag
317  def self.new(parent, *args)
318    super(parent, 'sel', *args)
319  end
320end
321TktTagSel = TkTextTagSel
322