1 #
2 # tk/texttag.rb - methods for treating text tags
3 #
4 require 'tk'
5 require 'tk/text'
6 require 'tk/tagfont'
7
8 class 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, '00000'.taint]).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(key)
133 @t.tag_cget @id, key
134 end
135 def cget_strict(key)
136 @t.tag_cget_strict @id, key
137 end
138 =begin
139 def cget(key)
140 case key.to_s
141 when 'text', 'label', 'show', 'data', 'file'
142 _fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget', @id, "-#{key}"))
143 when 'font', 'kanjifont'
144 #fnt = tk_tcl2ruby(tk_call(@t.path, 'tag', 'cget', @id, "-#{key}"))
145 fnt = tk_tcl2ruby(_fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget',
146 @id, '-font')))
147 unless fnt.kind_of?(TkFont)
148 fnt = tagfontobj(@id, fnt)
149 end
150 if key.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/
151 # obsolete; just for compatibility
152 fnt.kanji_font
153 else
154 fnt
155 end
156 else
157 tk_tcl2ruby(_fromUTF8(tk_call_without_enc(@t.path, 'tag', 'cget',
158 @id, "-#{key}")))
159 end
160 end
161 =end
162
163 def configure(key, val=None)
164 @t.tag_configure @id, key, val
165 end
166 # def configure(key, val=None)
167 # if key.kind_of?(Hash)
168 # tk_call @t.path, 'tag', 'configure', @id, *hash_kv(key)
169 # else
170 # tk_call @t.path, 'tag', 'configure', @id, "-#{key}", val
171 # end
172 # end
173 # def configure(key, value)
174 # if value == FALSE
175 # value = "0"
176 # elsif value.kind_of?(Proc)
177 # value = install_cmd(value)
178 # end
179 # tk_call @t.path, 'tag', 'configure', @id, "-#{key}", value
180 # end
181
182 def configinfo(key=nil)
183 @t.tag_configinfo @id, key
184 end
185
186 def current_configinfo(key=nil)
187 @t.current_tag_configinfo @id, key
188 end
189
190 #def bind(seq, cmd=Proc.new, *args)
191 # _bind([@t.path, 'tag', 'bind', @id], seq, cmd, *args)
192 # self
193 #end
194 def bind(seq, *args)
195 # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
196 if TkComm._callback_entry?(args[0]) || !block_given?
197 cmd = args.shift
198 else
199 cmd = Proc.new
200 end
201 _bind([@t.path, 'tag', 'bind', @id], seq, cmd, *args)
202 self
203 end
204
205 #def bind_append(seq, cmd=Proc.new, *args)
206 # _bind_append([@t.path, 'tag', 'bind', @id], seq, cmd, *args)
207 # self
208 #end
209 def bind_append(seq, *args)
210 # if args[0].kind_of?(Proc) || args[0].kind_of?(Method)
211 if TkComm._callback_entry?(args[0]) || !block_given?
212 cmd = args.shift
213 else
214 cmd = Proc.new
215 end
216 _bind_append([@t.path, 'tag', 'bind', @id], seq, cmd, *args)
217 self
218 end
219
220 def bind_remove(seq)
221 _bind_remove([@t.path, 'tag', 'bind', @id], seq)
222 self
223 end
224
225 def bindinfo(context=nil)
226 _bindinfo([@t.path, 'tag', 'bind', @id], context)
227 end
228
229 def raise(above=None)
230 tk_call_without_enc(@t.path, 'tag', 'raise', @id,
231 _get_eval_enc_str(above))
232 self
233 end
234
235 def lower(below=None)
236 tk_call_without_enc(@t.path, 'tag', 'lower', @id,
237 _get_eval_enc_str(below))
238 self
239 end
240
241 def destroy
242 tk_call_without_enc(@t.path, 'tag', 'delete', @id)
243 TTagID_TBL.mutex.synchronize{
244 TTagID_TBL[@tpath].delete(@id) if TTagID_TBL[@tpath]
245 }
246 self
247 end
248 end
249 TktTag = TkTextTag
250
251 class TkTextNamedTag<TkTextTag
252 def self.new(parent, name, *args)
253 tagobj = nil
254 TTagID_TBL.mutex.synchronize{
255 if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name]
256 tagobj = TTagID_TBL[parent.path][name]
257 else
258 # super(parent, name, *args)
259 (tagobj = self.allocate).instance_eval{
260 @parent = @t = parent
261 @tpath = parent.path
262 @path = @id = name
263 TTagID_TBL[@id] = self
264 TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath]
265 TTagID_TBL[@tpath][@id] = self unless TTagID_TBL[@tpath][@id]
266 @t._addtag @id, self
267 }
268 end
269 }
270
271 if args != []
272 keys = args.pop
273 if keys.kind_of?(Hash)
274 tagobj.add(*args) if args != []
275 tagobj.configure(keys)
276 else
277 args.push keys
278 tagobj.add(*args)
279 end
280 end
281
282 tagobj
283 end
284
285 def initialize(parent, name, *args)
286 # dummy:: not called by 'new' method
287
288 #unless parent.kind_of?(Tk::Text)
289 # fail ArgumentError, "expect Tk::Text for 1st argument"
290 #end
291 @parent = @t = parent
292 @tpath = parent.path
293 @path = @id = name
294
295 #if mode
296 # tk_call @t.path, "addtag", @id, *args
297 #end
298 if args != []
299 keys = args.pop
300 if keys.kind_of?(Hash)
301 add(*args) if args != []
302 configure(keys)
303 else
304 args.push keys
305 add(*args)
306 end
307 end
308 @t._addtag @id, self
309 end
310 end
311 TktNamedTag = TkTextNamedTag
312
313 class TkTextTagSel<TkTextNamedTag
314 def self.new(parent, *args)
315 super(parent, 'sel', *args)
316 end
317 end
318 TktTagSel = TkTextTagSel