1 #
2 # tk/menu.rb : treat menu and menubutton
3 #
4 require 'tk'
5 require 'tk/itemconfig'
6 require 'tk/menuspec'
7
8 module TkMenuEntryConfig
9 include TkItemConfigMethod
10
11 def __item_cget_cmd(id)
12 [self.path, 'entrycget', id]
13 end
14 private :__item_cget_cmd
15
16 def __item_config_cmd(id)
17 [self.path, 'entryconfigure', id]
18 end
19 private :__item_config_cmd
20
21 def __item_strval_optkeys(id)
22 super(id) << 'selectcolor'
23 end
24 private :__item_strval_optkeys
25
26 def __item_listval_optkeys(id)
27 []
28 end
29 private :__item_listval_optkeys
30
31 def __item_val2ruby_optkeys(id) # { key=>proc, ... }
32 super(id).update('menu'=>proc{|i, v| window(v)})
33 end
34 private :__item_val2ruby_optkeys
35
36 alias entrycget itemcget
37 alias entrycget_strict itemcget_strict
38 alias entryconfigure itemconfigure
39 alias entryconfiginfo itemconfiginfo
40 alias current_entryconfiginfo current_itemconfiginfo
41
42 private :itemcget, :itemcget_strict
43 private :itemconfigure, :itemconfiginfo, :current_itemconfiginfo
44 end
45
46 class Tk::Menu<TkWindow
47 include Wm
48 include TkMenuEntryConfig
49 extend TkMenuSpec
50
51 TkCommandNames = ['menu'.freeze].freeze
52 WidgetClassName = 'Menu'.freeze
53 WidgetClassNames[WidgetClassName] = self
54
55 #def create_self(keys)
56 # if keys and keys != None
57 # tk_call_without_enc('menu', @path, *hash_kv(keys, true))
58 # else
59 # tk_call_without_enc('menu', @path)
60 # end
61 #end
62 #private :create_self
63
64 def __strval_optkeys
65 super() << 'selectcolor' << 'title'
66 end
67 private :__strval_optkeys
68
69 def __boolval_optkeys
70 super() << 'tearoff'
71 end
72 private :__boolval_optkeys
73
74 def self.new_menuspec(menu_spec, parent = nil, tearoff = false, keys = nil)
75 if parent.kind_of?(Hash)
76 keys = _symbolkey2str(parent)
77 parent = keys.delete('parent')
78 tearoff = keys.delete('tearoff')
79 elsif tearoff.kind_of?(Hash)
80 keys = _symbolkey2str(tearoff)
81 tearoff = keys.delete('tearoff')
82 elsif keys
83 keys = _symbolkey2str(keys)
84 else
85 keys = {}
86 end
87
88 widgetname = keys.delete('widgetname')
89 _create_menu(parent, menu_spec, widgetname, tearoff, keys)
90 end
91
92 def tagid(id)
93 #id.to_s
94 _get_eval_string(id)
95 end
96
97 def activate(index)
98 tk_send_without_enc('activate', _get_eval_enc_str(index))
99 self
100 end
101 def add(type, keys=nil)
102 tk_send_without_enc('add', type, *hash_kv(keys, true))
103 self
104 end
105 def add_cascade(keys=nil)
106 add('cascade', keys)
107 end
108 def add_checkbutton(keys=nil)
109 add('checkbutton', keys)
110 end
111 def add_command(keys=nil)
112 add('command', keys)
113 end
114 def add_radiobutton(keys=nil)
115 add('radiobutton', keys)
116 end
117 def add_separator(keys=nil)
118 add('separator', keys)
119 end
120
121 def clone_menu(*args)
122 if args[0].kind_of?(TkWindow)
123 parent = args.shift
124 else
125 parent = self
126 end
127
128 if args[0].kind_of?(String) || args[0].kind_of?(Symbol) # menu type
129 type = args.shift
130 else
131 type = None # 'normal'
132 end
133
134 if args[0].kind_of?(Hash)
135 keys = _symbolkey2str(args.shift)
136 else
137 keys = {}
138 end
139
140 parent = keys.delete('parent') if keys.has_key?('parent')
141 type = keys.delete('type') if keys.has_key?('type')
142
143 if keys.empty?
144 Tk::MenuClone.new(self, parent, type)
145 else
146 Tk::MenuClone.new(self, parent, type, keys)
147 end
148 end
149
150 def index(idx)
151 ret = tk_send_without_enc('index', _get_eval_enc_str(idx))
152 (ret == 'none')? nil: number(ret)
153 end
154 def invoke(index)
155 _fromUTF8(tk_send_without_enc('invoke', _get_eval_enc_str(index)))
156 end
157 def insert(index, type, keys=nil)
158 tk_send_without_enc('insert', _get_eval_enc_str(index),
159 type, *hash_kv(keys, true))
160 self
161 end
162 def delete(first, last=nil)
163 if last
164 tk_send_without_enc('delete', _get_eval_enc_str(first),
165 _get_eval_enc_str(last))
166 else
167 tk_send_without_enc('delete', _get_eval_enc_str(first))
168 end
169 self
170 end
171 def popup(x, y, index=nil)
172 if index
173 tk_call_without_enc('tk_popup', path, x, y,
174 _get_eval_enc_str(index))
175 else
176 tk_call_without_enc('tk_popup', path, x, y)
177 end
178 self
179 end
180 def post(x, y)
181 _fromUTF8(tk_send_without_enc('post', x, y))
182 end
183 def postcascade(index)
184 tk_send_without_enc('postcascade', _get_eval_enc_str(index))
185 self
186 end
187 def postcommand(cmd=Proc.new)
188 configure_cmd 'postcommand', cmd
189 self
190 end
191 def set_focus
192 tk_call_without_enc('tk_menuSetFocus', path)
193 self
194 end
195 def tearoffcommand(cmd=Proc.new)
196 configure_cmd 'tearoffcommand', cmd
197 self
198 end
199 def menutype(index)
200 tk_send_without_enc('type', _get_eval_enc_str(index))
201 end
202 def unpost
203 tk_send_without_enc('unpost')
204 self
205 end
206 def xposition(index)
207 number(tk_send_without_enc('xposition', _get_eval_enc_str(index)))
208 end
209 def yposition(index)
210 number(tk_send_without_enc('yposition', _get_eval_enc_str(index)))
211 end
212
213 =begin
214 def entrycget(index, key)
215 case key.to_s
216 when 'text', 'label', 'show'
217 _fromUTF8(tk_send_without_enc('entrycget',
218 _get_eval_enc_str(index), "-#{key}"))
219 when 'font', 'kanjifont'
220 #fnt = tk_tcl2ruby(tk_send('entrycget', index, "-#{key}"))
221 fnt = tk_tcl2ruby(_fromUTF8(tk_send_without_enc('entrycget', _get_eval_enc_str(index), '-font')))
222 unless fnt.kind_of?(TkFont)
223 fnt = tagfontobj(index, fnt)
224 end
225 if key.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/
226 # obsolete; just for compatibility
227 fnt.kanji_font
228 else
229 fnt
230 end
231 else
232 tk_tcl2ruby(_fromUTF8(tk_send_without_enc('entrycget', _get_eval_enc_str(index), "-#{key}")))
233 end
234 end
235 def entryconfigure(index, key, val=None)
236 if key.kind_of? Hash
237 if (key['font'] || key[:font] ||
238 key['kanjifont'] || key[:kanjifont] ||
239 key['latinfont'] || key[:latinfont] ||
240 key['asciifont'] || key[:asciifont])
241 tagfont_configure(index, _symbolkey2str(key))
242 else
243 tk_send_without_enc('entryconfigure', _get_eval_enc_str(index),
244 *hash_kv(key, true))
245 end
246
247 else
248 if (key == 'font' || key == :font ||
249 key == 'kanjifont' || key == :kanjifont ||
250 key == 'latinfont' || key == :latinfont ||
251 key == 'asciifont' || key == :asciifont )
252 if val == None
253 tagfontobj(index)
254 else
255 tagfont_configure(index, {key=>val})
256 end
257 else
258 tk_call('entryconfigure', index, "-#{key}", val)
259 end
260 end
261 self
262 end
263
264 def entryconfiginfo(index, key=nil)
265 if TkComm::GET_CONFIGINFO_AS_ARRAY
266 if key
267 case key.to_s
268 when 'text', 'label', 'show'
269 conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}")))
270 when 'font', 'kanjifont'
271 conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}")))
272 conf[4] = tagfont_configinfo(index, conf[4])
273 else
274 conf = tk_split_list(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}")))
275 end
276 conf[0] = conf[0][1..-1]
277 conf
278 else
279 ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure', _get_eval_enc_str(index)))).collect{|conflist|
280 conf = tk_split_simplelist(conflist)
281 conf[0] = conf[0][1..-1]
282 case conf[0]
283 when 'text', 'label', 'show'
284 else
285 if conf[3]
286 if conf[3].index('{')
287 conf[3] = tk_split_list(conf[3])
288 else
289 conf[3] = tk_tcl2ruby(conf[3])
290 end
291 end
292 if conf[4]
293 if conf[4].index('{')
294 conf[4] = tk_split_list(conf[4])
295 else
296 conf[4] = tk_tcl2ruby(conf[4])
297 end
298 end
299 end
300 conf[1] = conf[1][1..-1] if conf.size == 2 # alias info
301 conf
302 }
303 if fontconf
304 ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'}
305 fontconf[4] = tagfont_configinfo(index, fontconf[4])
306 ret.push(fontconf)
307 else
308 ret
309 end
310 end
311 else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
312 if key
313 case key.to_s
314 when 'text', 'label', 'show'
315 conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}")))
316 when 'font', 'kanjifont'
317 conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}")))
318 conf[4] = tagfont_configinfo(index, conf[4])
319 else
320 conf = tk_split_list(_fromUTF8(tk_send_without_enc('entryconfigure',_get_eval_enc_str(index),"-#{key}")))
321 end
322 key = conf.shift[1..-1]
323 { key => conf }
324 else
325 ret = {}
326 tk_split_simplelist(_fromUTF8(tk_send_without_enc('entryconfigure', _get_eval_enc_str(index)))).each{|conflist|
327 conf = tk_split_simplelist(conflist)
328 key = conf.shift[1..-1]
329 case key
330 when 'text', 'label', 'show'
331 else
332 if conf[2]
333 if conf[2].index('{')
334 conf[2] = tk_split_list(conf[2])
335 else
336 conf[2] = tk_tcl2ruby(conf[2])
337 end
338 end
339 if conf[3]
340 if conf[3].index('{')
341 conf[3] = tk_split_list(conf[3])
342 else
343 conf[3] = tk_tcl2ruby(conf[3])
344 end
345 end
346 end
347 if conf.size == 1
348 ret[key] = conf[0][1..-1] # alias info
349 else
350 ret[key] = conf
351 end
352 }
353 fontconf = ret['font']
354 if fontconf
355 ret.delete('font')
356 ret.delete('kanjifont')
357 fontconf[3] = tagfont_configinfo(index, fontconf[3])
358 ret['font'] = fontconf
359 end
360 ret
361 end
362 end
363 end
364
365 def current_entryconfiginfo(index, key=nil)
366 if TkComm::GET_CONFIGINFO_AS_ARRAY
367 if key
368 conf = entryconfiginfo(index, key)
369 {conf[0] => conf[4]}
370 else
371 ret = {}
372 entryconfiginfo(index).each{|conf|
373 ret[conf[0]] = conf[4] if conf.size > 2
374 }
375 ret
376 end
377 else # ! TkComm::GET_CONFIGINFO_AS_ARRAY
378 ret = {}
379 entryconfiginfo(index, key).each{|k, conf|
380 ret[k] = conf[-1] if conf.kind_of?(Array)
381 }
382 ret
383 end
384 end
385 =end
386 end
387
388 #TkMenu = Tk::Menu unless Object.const_defined? :TkMenu
389 Tk.__set_toplevel_aliases__(:Tk, Tk::Menu, :TkMenu)
390
391
392 class Tk::MenuClone<Tk::Menu
393 =begin
394 def initialize(parent, type=None)
395 widgetname = nil
396 if parent.kind_of? Hash
397 keys = _symbolkey2str(parent)
398 parent = keys.delete('parent')
399 widgetname = keys.delete('widgetname')
400 type = keys.delete('type'); type = None unless type
401 end
402 #unless parent.kind_of?(TkMenu)
403 # fail ArgumentError, "parent must be TkMenu"
404 #end
405 @parent = parent
406 install_win(@parent.path, widgetname)
407 tk_call_without_enc(@parent.path, 'clone', @path, type)
408 end
409 =end
410 def initialize(src_menu, *args)
411 widgetname = nil
412
413 if args[0].kind_of?(TkWindow) # parent window
414 parent = args.shift
415 else
416 parent = src_menu
417 end
418
419 if args[0].kind_of?(String) || args[0].kind_of?(Symbol) # menu type
420 type = args.shift
421 else
422 type = None # 'normal'
423 end
424
425 if args[0].kind_of?(Hash)
426 keys = _symbolkey2str(args.shift)
427 parent = keys.delete('parent') if keys.has_key?('parent')
428 widgetname = keys.delete('widgetname')
429 type = keys.delete('type') if keys.has_key?('type')
430 else
431 keys = nil
432 end
433
434 @src_menu = src_menu
435 @parent = parent
436 @type = type
437 install_win(@parent.path, widgetname)
438 tk_call_without_enc(@src_menu.path, 'clone', @path, @type)
439 configure(keys) if keys && !keys.empty?
440 end
441
442 def source_menu
443 @src_menu
444 end
445 end
446 Tk::CloneMenu = Tk::MenuClone
447 #TkMenuClone = Tk::MenuClone unless Object.const_defined? :TkMenuClone
448 #TkCloneMenu = Tk::CloneMenu unless Object.const_defined? :TkCloneMenu
449 Tk.__set_toplevel_aliases__(:Tk, Tk::MenuClone, :TkMenuClone, :TkCloneMenu)
450
451 module Tk::SystemMenu
452 def initialize(parent, keys=nil)
453 if parent.kind_of? Hash
454 keys = _symbolkey2str(parent)
455 parent = keys.delete('parent')
456 end
457 #unless parent.kind_of? TkMenu
458 # fail ArgumentError, "parent must be a TkMenu object"
459 #end
460 # @path = Kernel.format("%s.%s", parent.path, self.class::SYSMENU_NAME)
461 @path = parent.path + '.' + self.class::SYSMENU_NAME
462 #TkComm::Tk_WINDOWS[@path] = self
463 TkCore::INTERP.tk_windows[@path] = self
464 if self.method(:create_self).arity == 0
465 p 'create_self has no arg' if $DEBUG
466 create_self
467 configure(keys) if keys
468 else
469 p 'create_self has an arg' if $DEBUG
470 create_self(keys)
471 end
472 end
473 end
474 TkSystemMenu = Tk::SystemMenu
475
476
477 class Tk::SysMenu_Help<Tk::Menu
478 # for all platform
479 include Tk::SystemMenu
480 SYSMENU_NAME = 'help'
481 end
482 #TkSysMenu_Help = Tk::SysMenu_Help unless Object.const_defined? :TkSysMenu_Help
483 Tk.__set_toplevel_aliases__(:Tk, Tk::SysMenu_Help, :TkSysMenu_Help)
484
485
486 class Tk::SysMenu_System<Tk::Menu
487 # for Windows
488 include Tk::SystemMenu
489 SYSMENU_NAME = 'system'
490 end
491 #TkSysMenu_System = Tk::SysMenu_System unless Object.const_defined? :TkSysMenu_System
492 Tk.__set_toplevel_aliases__(:Tk, Tk::SysMenu_System, :TkSysMenu_System)
493
494
495 class Tk::SysMenu_Apple<Tk::Menu
496 # for Machintosh
497 include Tk::SystemMenu
498 SYSMENU_NAME = 'apple'
499 end
500 #TkSysMenu_Apple = Tk::SysMenu_Apple unless Object.const_defined? :TkSysMenu_Apple
501 Tk.__set_toplevel_aliases__(:Tk, Tk::SysMenu_Apple, :TkSysMenu_Apple)
502
503
504 class Tk::Menubutton<Tk::Label
505 TkCommandNames = ['menubutton'.freeze].freeze
506 WidgetClassName = 'Menubutton'.freeze
507 WidgetClassNames[WidgetClassName] = self
508 def create_self(keys)
509 if keys and keys != None
510 unless TkConfigMethod.__IGNORE_UNKNOWN_CONFIGURE_OPTION__
511 # tk_call_without_enc('menubutton', @path, *hash_kv(keys, true))
512 tk_call_without_enc(self.class::TkCommandNames[0], @path,
513 *hash_kv(keys, true))
514 else
515 begin
516 tk_call_without_enc(self.class::TkCommandNames[0], @path,
517 *hash_kv(keys, true))
518 rescue
519 tk_call_without_enc(self.class::TkCommandNames[0], @path)
520 keys = __check_available_configure_options(keys)
521 unless keys.empty?
522 tk_call_without_enc('destroy', @path) rescue nil
523 tk_call_without_enc(self.class::TkCommandNames[0], @path,
524 *hash_kv(keys, true))
525 end
526 end
527 end
528 else
529 # tk_call_without_enc('menubutton', @path)
530 tk_call_without_enc(self.class::TkCommandNames[0], @path)
531 end
532 end
533 private :create_self
534
535 def __boolval_optkeys
536 super() << 'indicatoron'
537 end
538 private :__boolval_optkeys
539
540 end
541 Tk::MenuButton = Tk::Menubutton
542 #TkMenubutton = Tk::Menubutton unless Object.const_defined? :TkMenubutton
543 #TkMenuButton = Tk::MenuButton unless Object.const_defined? :TkMenuButton
544 Tk.__set_toplevel_aliases__(:Tk, Tk::Menubutton, :TkMenubutton, :TkMenuButton)
545
546
547 class Tk::OptionMenubutton<Tk::Menubutton
548 TkCommandNames = ['tk_optionMenu'.freeze].freeze
549
550 class OptionMenu<TkMenu
551 def initialize(path) #==> return value of tk_optionMenu
552 @path = path
553 #TkComm::Tk_WINDOWS[@path] = self
554 TkCore::INTERP.tk_windows[@path] = self
555 end
556 end
557
558 def initialize(*args)
559 # args :: [parent,] [var,] [value[, ...],] [keys]
560 # parent --> TkWindow or nil
561 # var --> TkVariable or nil
562 # keys --> Hash
563 # keys[:parent] or keys['parent'] --> parent
564 # keys[:variable] or keys['variable'] --> var
565 # keys[:values] or keys['values'] --> value, ...
566 # other Hash keys are menubutton options
567 keys = {}
568 keys = args.pop if args[-1].kind_of?(Hash)
569 keys = _symbolkey2str(keys)
570
571 parent = nil
572 if args[0].kind_of?(TkWindow) || args[0] == nil
573 keys.delete('parent') # ignore
574 parent = args.shift
575 else
576 parent = keys.delete('parent')
577 end
578
579 @variable = nil
580 if args[0].kind_of?(TkVariable) || args[0] == nil
581 keys.delete('variable') # ignore
582 @variable = args.shift
583 else
584 @variable = keys.delete('variable')
585 end
586 @variable = TkVariable.new unless @variable
587
588 (args = keys.delete('values') || []) if args.empty?
589 if args.empty?
590 args << @variable.value
591 else
592 @variable.value = args[0]
593 end
594
595 install_win(if parent then parent.path end)
596 @menu = OptionMenu.new(tk_call('tk_optionMenu',
597 @path, @variable.id, *args))
598
599 configure(keys) if keys
600 end
601
602 def value
603 @variable.value
604 end
605
606 def value=(val)
607 @variable.value = val
608 end
609
610 def activate(index)
611 @menu.activate(index)
612 self
613 end
614 def add(value)
615 @menu.add('radiobutton', 'variable'=>@variable,
616 'label'=>value, 'value'=>value)
617 self
618 end
619 def index(index)
620 @menu.index(index)
621 end
622 def invoke(index)
623 @menu.invoke(index)
624 end
625 def insert(index, value)
626 @menu.insert(index, 'radiobutton', 'variable'=>@variable,
627 'label'=>value, 'value'=>value)
628 self
629 end
630 def delete(index, last=None)
631 @menu.delete(index, last)
632 self
633 end
634 def xposition(index)
635 @menu.xposition(index)
636 end
637 def yposition(index)
638 @menu.yposition(index)
639 end
640 def menu
641 @menu
642 end
643 def menucget(key)
644 @menu.cget(key)
645 end
646 def menucget_strict(key)
647 @menu.cget_strict(key)
648 end
649 def menuconfigure(key, val=None)
650 @menu.configure(key, val)
651 self
652 end
653 def menuconfiginfo(key=nil)
654 @menu.configinfo(key)
655 end
656 def current_menuconfiginfo(key=nil)
657 @menu.current_configinfo(key)
658 end
659 def entrycget(index, key)
660 @menu.entrycget(index, key)
661 end
662 def entrycget_strict(index, key)
663 @menu.entrycget_strict(index, key)
664 end
665 def entryconfigure(index, key, val=None)
666 @menu.entryconfigure(index, key, val)
667 self
668 end
669 def entryconfiginfo(index, key=nil)
670 @menu.entryconfiginfo(index, key)
671 end
672 def current_entryconfiginfo(index, key=nil)
673 @menu.current_entryconfiginfo(index, key)
674 end
675 end
676
677 Tk::OptionMenuButton = Tk::OptionMenubutton
678 #TkOptionMenubutton = Tk::OptionMenubutton unless Object.const_defined? :TkOptionMenubutton
679 #TkOptionMenuButton = Tk::OptionMenuButton unless Object.const_defined? :TkOptionMenuButton
680 Tk.__set_toplevel_aliases__(:Tk, Tk::OptionMenubutton,
681 :TkOptionMenubutton, :TkOptionMenuButton)