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