1 #
2 # tk/composite.rb :
3 #
4 require 'tk'
5
6 module TkComposite
7 include Tk
8 extend Tk
9
10 =begin
11 def initialize(parent=nil, *args)
12 @delegates = {}
13 @option_methods = {}
14 @option_setting = {}
15
16 if parent.kind_of? Hash
17 keys = _symbolkey2str(parent)
18 parent = keys.delete('parent')
19 @frame = TkFrame.new(parent)
20 @path = @epath = @frame.path
21 initialize_composite(keys)
22 else
23 @frame = TkFrame.new(parent)
24 @path = @epath = @frame.path
25 initialize_composite(*args)
26 end
27 end
28 =end
29
30 def _choice_classname_of_baseframe
31 base_class_name = nil
32
33 klass = WidgetClassNames[self.class::WidgetClassName]
34
35 if klass
36 # WidgetClassName is a known class
37 #if klass <= TkFrame || klass < TkComposite
38 if klass <= TkFrame || klass < Tk::Frame || klass < TkComposite
39 # klass is valid for the base frame
40 if self.class <= klass
41 # use my classname
42 base_class_name = self.class.name
43 if base_class_name == ''
44 # anonymous class -> use ancestor's name
45 base_class_name = klass.name
46 end
47 else
48 # not subclass -> use WidgetClassName
49 base_class_name = klass.name
50 end
51
52 else
53 # klass is invalid for the base frame
54 #if self.class < TkFrame || self.class.superclass < TkComposite
55 if self.class < TkFrame || self.class.superclass < Tk::Frame || self.class.superclass < TkComposite
56 # my class name is valid for the base frame -> use my classname
57 base_class_name = self.class.name
58 if base_class_name == ''
59 # anonymous class -> use TkFrame
60 base_class_name = nil
61 end
62 else
63 # no idea for the base frame -> use TkFrame
64 base_class_name = nil
65 end
66 end
67
68 elsif self.class::WidgetClassName && ! self.class::WidgetClassName.empty?
69 # unknown WidgetClassName is defined -> use it for the base frame
70 base_class_name = self.class::WidgetClassName
71
72 else
73 # no valid WidgetClassName
74 #if self.class < TkFrame || self.class.superclass < TkComposite
75 if self.class < TkFrame || self.class.superclass < Tk::Frame || self.class.superclass < TkComposite
76 # my class name is valid for the base frame -> use my classname
77 base_class_name = self.class.name
78 if base_class_name == ''
79 # anonymous class -> use TkFrame
80 base_class_name = nil
81 end
82 else
83 # no idea for the base frame -> use TkFrame
84 base_class_name = nil
85 end
86 end
87
88 base_class_name
89 end
90 private :_choice_classname_of_baseframe
91
92 # def initialize(parent=nil, *args)
93 def initialize(*args)
94 @delegates = {}
95 @option_methods = {}
96 @option_setting = {}
97
98 if args[-1].kind_of?(Hash)
99 keys = _symbolkey2str(args.pop)
100 else
101 keys = {}
102 end
103 parent = args.shift
104 parent = keys.delete('parent') if keys.has_key?('parent')
105
106 if keys.key?('classname')
107 keys['class'] = keys.delete('classname')
108 end
109 if (base_class_name = (keys.delete('class')).to_s).empty?
110 base_class_name = _choice_classname_of_baseframe
111 end
112
113 if base_class_name
114 # @frame = Tk::Frame.new(parent, :class=>base_class_name)
115 # --> use current TkFrame class
116 @frame = TkFrame.new(parent, :class=>base_class_name)
117 else
118 # @frame = Tk::Frame.new(parent)
119 # --> use current TkFrame class
120 @frame = TkFrame.new(parent)
121 end
122 @path = @epath = @frame.path
123
124 args.push(keys) unless keys.empty?
125 initialize_composite(*args)
126 end
127
128 def database_classname
129 @frame.database_classname
130 end
131
132 def database_class
133 @frame.database_class
134 end
135
136 def epath
137 @epath
138 end
139
140 def initialize_composite(*args) end
141 private :initialize_composite
142
143 def inspect
144 str = super
145 str.chop << ' @epath=' << @epath.inspect << '>'
146 end
147
148 def option_methods(*opts)
149 opts.each{|m_set, m_cget, m_info|
150 m_set = m_set.to_s
151 m_cget = m_set if !m_cget && self.method(m_set).arity == -1
152 m_cget = m_cget.to_s if m_cget
153 m_info = m_info.to_s if m_info
154 @option_methods[m_set] = {
155 :set => m_set, :cget => m_cget, :info => m_info
156 }
157 }
158 end
159
160 def delegate_alias(alias_opt, option, *wins)
161 if wins.length == 0
162 fail ArgumentError, "target widgets are not given"
163 end
164 if alias_opt != option && (alias_opt == 'DEFAULT' || option == 'DEFAULT')
165 fail ArgumentError, "cannot alias 'DEFAULT' option"
166 end
167 alias_opt = alias_opt.to_s
168 option = option.to_s
169 if @delegates[alias_opt].kind_of?(Array)
170 if (elem = @delegates[alias_opt].assoc(option))
171 wins.each{|w| elem[1].push(w)}
172 else
173 @delegates[alias_opt] << [option, wins]
174 end
175 else
176 @delegates[alias_opt] = [ [option, wins] ]
177 end
178 end
179
180 def delegate(option, *wins)
181 delegate_alias(option, option, *wins)
182 end
183
184 def __cget_delegates(slot)
185 slot = slot.to_s
186
187 if @option_methods.include?(slot)
188 if @option_methods[slot][:cget]
189 return self.__send__(@option_methods[slot][:cget])
190 else
191 if @option_setting[slot]
192 return @option_setting[slot]
193 else
194 return ''
195 end
196 end
197 end
198
199 tbl = @delegates[slot]
200 tbl = @delegates['DEFAULT'] unless tbl
201
202 begin
203 if tbl
204 opt, wins = tbl[-1]
205 opt = slot if opt == 'DEFAULT'
206 if wins && wins[-1]
207 # return wins[-1].cget(opt)
208 return wins[-1].cget_strict(opt)
209 end
210 end
211 rescue
212 end
213
214 return None
215 end
216 private :__cget_delegates
217
218 def cget(slot)
219 if (ret = __cget_delegates(slot)) == None
220 super(slot)
221 else
222 ret
223 end
224 end
225
226 def cget_strict(slot)
227 if (ret = __cget_delegates(slot)) == None
228 super(slot)
229 else
230 ret
231 end
232 end
233
234 =begin
235 def cget(slot)
236 slot = slot.to_s
237
238 if @option_methods.include?(slot)
239 if @option_methods[slot][:cget]
240 return self.__send__(@option_methods[slot][:cget])
241 else
242 if @option_setting[slot]
243 return @option_setting[slot]
244 else
245 return ''
246 end
247 end
248 end
249
250 tbl = @delegates[slot]
251 tbl = @delegates['DEFAULT'] unless tbl
252
253 begin
254 if tbl
255 opt, wins = tbl[-1]
256 opt = slot if opt == 'DEFAULT'
257 if wins && wins[-1]
258 return wins[-1].cget(opt)
259 end
260 end
261 rescue
262 end
263
264 super(slot)
265 end
266 =end
267
268 def configure(slot, value=None)
269 if slot.kind_of? Hash
270 slot.each{|slot,value| configure slot, value}
271 return self
272 end
273
274 slot = slot.to_s
275
276 if @option_methods.include?(slot)
277 unless @option_methods[slot][:cget]
278 if value.kind_of?(Symbol)
279 @option_setting[slot] = value.to_s
280 else
281 @option_setting[slot] = value
282 end
283 end
284 return self.__send__(@option_methods[slot][:set], value)
285 end
286
287 tbl = @delegates[slot]
288 tbl = @delegates['DEFAULT'] unless tbl
289
290 begin
291 if tbl
292 last = nil
293 tbl.each{|opt, wins|
294 opt = slot if opt == 'DEFAULT'
295 wins.each{|w| last = w.configure(opt, value)}
296 }
297 return last
298 end
299 rescue
300 end
301
302 super(slot, value)
303 end
304
305 def configinfo(slot = nil)
306 if TkComm::GET_CONFIGINFO_AS_ARRAY
307 if slot
308 slot = slot.to_s
309 if @option_methods.include?(slot)
310 if @option_methods[slot][:info]
311 return self.__send__(@option_methods[slot][:info])
312 else
313 return [slot, '', '', '', self.cget(slot)]
314 end
315 end
316
317 tbl = @delegates[slot]
318 tbl = @delegates['DEFAULT'] unless tbl
319
320 begin
321 if tbl
322 if tbl.length == 1
323 opt, wins = tbl[0]
324 if slot == opt || opt == 'DEFAULT'
325 return wins[-1].configinfo(slot)
326 else
327 info = wins[-1].configinfo(opt)
328 info[0] = slot
329 return info
330 end
331 else
332 opt, wins = tbl[-1]
333 return [slot, '', '', '', wins[-1].cget(opt)]
334 end
335 end
336 rescue
337 end
338
339 super(slot)
340
341 else # slot == nil
342 info_list = super(slot)
343
344 tbl = @delegates['DEFAULT']
345 if tbl
346 wins = tbl[0][1]
347 if wins && wins[-1]
348 wins[-1].configinfo.each{|info|
349 slot = info[0]
350 info_list.delete_if{|i| i[0] == slot} << info
351 }
352 end
353 end
354
355 @delegates.each{|slot, tbl|
356 next if slot == 'DEFAULT'
357 if tbl.length == 1
358 opt, wins = tbl[0]
359 next unless wins && wins[-1]
360 if slot == opt
361 info_list.delete_if{|i| i[0] == slot} <<
362 wins[-1].configinfo(slot)
363 else
364 info = wins[-1].configinfo(opt)
365 info[0] = slot
366 info_list.delete_if{|i| i[0] == slot} << info
367 end
368 else
369 opt, wins = tbl[-1]
370 info_list.delete_if{|i| i[0] == slot} <<
371 [slot, '', '', '', wins[-1].cget(opt)]
372 end
373 }
374
375 @option_methods.each{|slot, m|
376 if m[:info]
377 info = self.__send__(m[:info])
378 else
379 info = [slot, '', '', '', self.cget(slot)]
380 end
381 info_list.delete_if{|i| i[0] == slot} << info
382 }
383
384 info_list
385 end
386
387 else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
388 if slot
389 slot = slot.to_s
390 if @option_methods.include?(slot)
391 if @option_methods[slot][:info]
392 return self.__send__(@option_methods[slot][:info])
393 else
394 return {slot => ['', '', '', self.cget(slot)]}
395 end
396 end
397
398 tbl = @delegates[slot]
399 tbl = @delegates['DEFAULT'] unless tbl
400
401 begin
402 if tbl
403 if tbl.length == 1
404 opt, wins = tbl[0]
405 if slot == opt || opt == 'DEFAULT'
406 return wins[-1].configinfo(slot)
407 else
408 return {slot => wins[-1].configinfo(opt)[opt]}
409 end
410 else
411 opt, wins = tbl[-1]
412 return {slot => ['', '', '', wins[-1].cget(opt)]}
413 end
414 end
415 rescue
416 end
417
418 super(slot)
419
420 else # slot == nil
421 info_list = super(slot)
422
423 tbl = @delegates['DEFAULT']
424 if tbl
425 wins = tbl[0][1]
426 info_list.update(wins[-1].configinfo) if wins && wins[-1]
427 end
428
429 @delegates.each{|slot, tbl|
430 next if slot == 'DEFAULT'
431 if tbl.length == 1
432 opt, wins = tbl[0]
433 next unless wins && wins[-1]
434 if slot == opt
435 info_list.update(wins[-1].configinfo(slot))
436 else
437 info_list.update({slot => wins[-1].configinfo(opt)[opt]})
438 end
439 else
440 opt, wins = tbl[-1]
441 info_list.update({slot => ['', '', '', wins[-1].cget(opt)]})
442 end
443 }
444
445 @option_methods.each{|slot, m|
446 if m[:info]
447 info = self.__send__(m[:info])
448 else
449 info = {slot => ['', '', '', self.cget(slot)]}
450 end
451 info_list.update(info)
452 }
453
454 info_list
455 end
456 end
457 end
458 end