1# 2# tk/canvas.rb - Tk canvas classes 3# by Yukihiro Matsumoto <matz@caelum.co.jp> 4# 5require 'tk' 6require 'tk/canvastag' 7require 'tk/itemconfig' 8require 'tk/scrollable' 9 10module TkCanvasItemConfig 11 include TkItemConfigMethod 12 13 def __item_strval_optkeys(id) 14 # maybe need to override 15 super(id) + [ 16 'fill', 'activefill', 'disabledfill', 17 'outline', 'activeoutline', 'disabledoutline' 18 ] 19 end 20 private :__item_strval_optkeys 21 22 def __item_methodcall_optkeys(id) 23 {'coords'=>'coords'} 24 end 25 private :__item_methodcall_optkeys 26 27 def __item_val2ruby_optkeys(id) # { key=>proc, ... } 28 super(id).update('window'=>proc{|i, v| window(v)}, 29 'tags'=>proc{|i, v| 30 simplelist(v).collect{|tag| TkcTag.id2obj(self, tag)} 31 }) 32 end 33 private :__item_val2ruby_optkeys 34 35 def __item_pathname(tagOrId) 36 if tagOrId.kind_of?(TkcItem) || tagOrId.kind_of?(TkcTag) 37 self.path + ';' + tagOrId.id.to_s 38 else 39 self.path + ';' + tagOrId.to_s 40 end 41 end 42 private :__item_pathname 43end 44 45class Tk::Canvas<TkWindow 46 include TkCanvasItemConfig 47 include Tk::Scrollable 48 49 TkCommandNames = ['canvas'.freeze].freeze 50 WidgetClassName = 'Canvas'.freeze 51 WidgetClassNames[WidgetClassName] ||= self 52 53 def __destroy_hook__ 54 TkcItem::CItemID_TBL.delete(@path) 55 end 56 57 #def create_self(keys) 58 # if keys and keys != None 59 # tk_call_without_enc('canvas', @path, *hash_kv(keys, true)) 60 # else 61 # tk_call_without_enc('canvas', @path) 62 # end 63 #end 64 #private :create_self 65 66 def __numval_optkeys 67 super() + ['closeenough'] 68 end 69 private :__numval_optkeys 70 71 def __boolval_optkeys 72 super() + ['confine'] 73 end 74 private :__boolval_optkeys 75 76 def tagid(tag) 77 if tag.kind_of?(TkcItem) || tag.kind_of?(TkcTag) 78 tag.id 79 else 80 tag # maybe an Array of configure paramters 81 end 82 end 83 private :tagid 84 85 86 # create a canvas item without creating a TkcItem object 87 def create(type, *args) 88 if type.kind_of?(Class) && type < TkcItem 89 # do nothing 90 elsif TkcItem.type2class(type.to_s) 91 type = TkcItem.type2class(type.to_s) 92 else 93 fail ArgumentError, "type must a subclass of TkcItem class, or a string in CItemTypeToClass" 94 end 95 type.create(self, *args) 96 end 97 98 def addtag(tag, mode, *args) 99 mode = mode.to_s 100 if args[0] && mode =~ /^(above|below|with(tag)?)$/ 101 args[0] = tagid(args[0]) 102 end 103 tk_send_without_enc('addtag', tagid(tag), mode, *args) 104 self 105 end 106 def addtag_above(tagOrId, target) 107 addtag(tagOrId, 'above', tagid(target)) 108 end 109 def addtag_all(tagOrId) 110 addtag(tagOrId, 'all') 111 end 112 def addtag_below(tagOrId, target) 113 addtag(tagOrId, 'below', tagid(target)) 114 end 115 def addtag_closest(tagOrId, x, y, halo=None, start=None) 116 addtag(tagOrId, 'closest', x, y, halo, start) 117 end 118 def addtag_enclosed(tagOrId, x1, y1, x2, y2) 119 addtag(tagOrId, 'enclosed', x1, y1, x2, y2) 120 end 121 def addtag_overlapping(tagOrId, x1, y1, x2, y2) 122 addtag(tagOrId, 'overlapping', x1, y1, x2, y2) 123 end 124 def addtag_withtag(tagOrId, tag) 125 addtag(tagOrId, 'withtag', tagid(tag)) 126 end 127 128 def bbox(tagOrId, *tags) 129 list(tk_send_without_enc('bbox', tagid(tagOrId), 130 *tags.collect{|t| tagid(t)})) 131 end 132 133 #def itembind(tag, context, cmd=Proc.new, *args) 134 # _bind([path, "bind", tagid(tag)], context, cmd, *args) 135 # self 136 #end 137 def itembind(tag, context, *args) 138 # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 139 if TkComm._callback_entry?(args[0]) || !block_given? 140 cmd = args.shift 141 else 142 cmd = Proc.new 143 end 144 _bind([path, "bind", tagid(tag)], context, cmd, *args) 145 self 146 end 147 148 #def itembind_append(tag, context, cmd=Proc.new, *args) 149 # _bind_append([path, "bind", tagid(tag)], context, cmd, *args) 150 # self 151 #end 152 def itembind_append(tag, context, *args) 153 # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 154 if TkComm._callback_entry?(args[0]) || !block_given? 155 cmd = args.shift 156 else 157 cmd = Proc.new 158 end 159 _bind_append([path, "bind", tagid(tag)], context, cmd, *args) 160 self 161 end 162 163 def itembind_remove(tag, context) 164 _bind_remove([path, "bind", tagid(tag)], context) 165 self 166 end 167 168 def itembindinfo(tag, context=nil) 169 _bindinfo([path, "bind", tagid(tag)], context) 170 end 171 172 def canvasx(screen_x, *args) 173 #tk_tcl2ruby(tk_send_without_enc('canvasx', screen_x, *args)) 174 number(tk_send_without_enc('canvasx', screen_x, *args)) 175 end 176 def canvasy(screen_y, *args) 177 #tk_tcl2ruby(tk_send_without_enc('canvasy', screen_y, *args)) 178 number(tk_send_without_enc('canvasy', screen_y, *args)) 179 end 180 alias canvas_x canvasx 181 alias canvas_y canvasy 182 183 def coords(tag, *args) 184 if args.empty? 185 tk_split_list(tk_send_without_enc('coords', tagid(tag))) 186 else 187 tk_send_without_enc('coords', tagid(tag), *(args.flatten)) 188 self 189 end 190 end 191 192 def dchars(tag, first, last=None) 193 tk_send_without_enc('dchars', tagid(tag), 194 _get_eval_enc_str(first), _get_eval_enc_str(last)) 195 self 196 end 197 198 def delete(*args) 199 tbl = nil 200 TkcItem::CItemID_TBL.mutex.synchronize{ 201 tbl = TkcItem::CItemID_TBL[self.path] 202 } 203 if tbl 204 args.each{|tag| 205 find('withtag', tag).each{|item| 206 if item.kind_of?(TkcItem) 207 TkcItem::CItemID_TBL.mutex.synchronize{ 208 tbl.delete(item.id) 209 } 210 end 211 } 212 } 213 end 214 tk_send_without_enc('delete', *args.collect{|t| tagid(t)}) 215 self 216 end 217 alias remove delete 218 219 def dtag(tag, tag_to_del=None) 220 tk_send_without_enc('dtag', tagid(tag), tagid(tag_to_del)) 221 self 222 end 223 alias deltag dtag 224 225 def find(mode, *args) 226 list(tk_send_without_enc('find', mode, *args)).collect!{|id| 227 TkcItem.id2obj(self, id) 228 } 229 end 230 def find_above(target) 231 find('above', tagid(target)) 232 end 233 def find_all 234 find('all') 235 end 236 def find_below(target) 237 find('below', tagid(target)) 238 end 239 def find_closest(x, y, halo=None, start=None) 240 find('closest', x, y, halo, start) 241 end 242 def find_enclosed(x1, y1, x2, y2) 243 find('enclosed', x1, y1, x2, y2) 244 end 245 def find_overlapping(x1, y1, x2, y2) 246 find('overlapping', x1, y1, x2, y2) 247 end 248 def find_withtag(tag) 249 find('withtag', tag) 250 end 251 252 def itemfocus(tagOrId=nil) 253 if tagOrId 254 tk_send_without_enc('focus', tagid(tagOrId)) 255 self 256 else 257 ret = tk_send_without_enc('focus') 258 if ret == "" 259 nil 260 else 261 TkcItem.id2obj(self, ret) 262 end 263 end 264 end 265 266 def gettags(tagOrId) 267 list(tk_send_without_enc('gettags', tagid(tagOrId))).collect{|tag| 268 TkcTag.id2obj(self, tag) 269 } 270 end 271 272 def icursor(tagOrId, index) 273 tk_send_without_enc('icursor', tagid(tagOrId), index) 274 self 275 end 276 277 def imove(tagOrId, idx, x, y) 278 tk_send_without_enc('imove', tagid(tagOrId), idx, x, y) 279 self 280 end 281 alias i_move imove 282 283 def index(tagOrId, idx) 284 number(tk_send_without_enc('index', tagid(tagOrId), idx)) 285 end 286 287 def insert(tagOrId, index, string) 288 tk_send_without_enc('insert', tagid(tagOrId), index, 289 _get_eval_enc_str(string)) 290 self 291 end 292 293=begin 294 def itemcget(tagOrId, option) 295 case option.to_s 296 when 'dash', 'activedash', 'disableddash' 297 conf = tk_send_without_enc('itemcget', tagid(tagOrId), "-#{option}") 298 if conf =~ /^[0-9]/ 299 list(conf) 300 else 301 conf 302 end 303 when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' 304 _fromUTF8(tk_send_without_enc('itemcget', tagid(tagOrId), "-#{option}")) 305 when 'font', 'kanjifont' 306 #fnt = tk_tcl2ruby(tk_send('itemcget', tagid(tagOrId), "-#{option}")) 307 fnt = tk_tcl2ruby(_fromUTF8(tk_send_with_enc('itemcget', tagid(tagOrId), '-font'))) 308 unless fnt.kind_of?(TkFont) 309 fnt = tagfontobj(tagid(tagOrId), fnt) 310 end 311 if option.to_s == 'kanjifont' && JAPANIZED_TK && TK_VERSION =~ /^4\.*/ 312 # obsolete; just for compatibility 313 fnt.kanji_font 314 else 315 fnt 316 end 317 else 318 tk_tcl2ruby(_fromUTF8(tk_send_without_enc('itemcget', tagid(tagOrId), 319 "-#{option}"))) 320 end 321 end 322 323 def itemconfigure(tagOrId, key, value=None) 324 if key.kind_of? Hash 325 key = _symbolkey2str(key) 326 coords = key.delete('coords') 327 self.coords(tagOrId, coords) if coords 328 329 if ( key['font'] || key['kanjifont'] \ 330 || key['latinfont'] || key['asciifont'] ) 331 tagfont_configure(tagid(tagOrId), key.dup) 332 else 333 _fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), 334 *hash_kv(key, true))) 335 end 336 337 else 338 if ( key == 'coords' || key == :coords ) 339 self.coords(tagOrId, value) 340 elsif ( key == 'font' || key == :font || 341 key == 'kanjifont' || key == :kanjifont || 342 key == 'latinfont' || key == :latinfont || 343 key == 'asciifont' || key == :asciifont ) 344 if value == None 345 tagfontobj(tagid(tagOrId)) 346 else 347 tagfont_configure(tagid(tagOrId), {key=>value}) 348 end 349 else 350 _fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), 351 "-#{key}", _get_eval_enc_str(value))) 352 end 353 end 354 self 355 end 356# def itemconfigure(tagOrId, key, value=None) 357# if key.kind_of? Hash 358# tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(key) 359# else 360# tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value 361# end 362# end 363# def itemconfigure(tagOrId, keys) 364# tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(keys) 365# end 366 367 def itemconfiginfo(tagOrId, key=nil) 368 if TkComm::GET_CONFIGINFO_AS_ARRAY 369 if key 370 case key.to_s 371 when 'coords' 372 return ['coords', '', '', '', self.coords(tagOrId)] 373 when 'dash', 'activedash', 'disableddash' 374 conf = tk_split_simplelist(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}")) 375 if conf[3] && conf[3] =~ /^[0-9]/ 376 conf[3] = list(conf[3]) 377 end 378 if conf[4] && conf[4] =~ /^[0-9]/ 379 conf[4] = list(conf[4]) 380 end 381 when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' 382 conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) 383 when 'font', 'kanjifont' 384 conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId),"-#{key}"))) 385 conf[4] = tagfont_configinfo(tagid(tagOrId), conf[4]) 386 else 387 conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) 388 end 389 conf[0] = conf[0][1..-1] 390 conf 391 else 392 ret = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId)))).collect{|conflist| 393 conf = tk_split_simplelist(conflist) 394 conf[0] = conf[0][1..-1] 395 case conf[0] 396 when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' 397 when 'dash', 'activedash', 'disableddash' 398 if conf[3] && conf[3] =~ /^[0-9]/ 399 conf[3] = list(conf[3]) 400 end 401 if conf[4] && conf[4] =~ /^[0-9]/ 402 conf[4] = list(conf[4]) 403 end 404 else 405 if conf[3] 406 if conf[3].index('{') 407 conf[3] = tk_split_list(conf[3]) 408 else 409 conf[3] = tk_tcl2ruby(conf[3]) 410 end 411 end 412 if conf[4] 413 if conf[4].index('{') 414 conf[4] = tk_split_list(conf[4]) 415 else 416 conf[4] = tk_tcl2ruby(conf[4]) 417 end 418 end 419 end 420 conf[1] = conf[1][1..-1] if conf.size == 2 # alias info 421 conf 422 } 423 424 fontconf = ret.assoc('font') 425 if fontconf 426 ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} 427 fontconf[4] = tagfont_configinfo(tagid(tagOrId), fontconf[4]) 428 ret.push(fontconf) 429 end 430 431 ret << ['coords', '', '', '', self.coords(tagOrId)] 432 end 433 else # ! TkComm::GET_CONFIGINFO_AS_ARRAY 434 if key 435 case key.to_s 436 when 'coords' 437 {'coords' => ['', '', '', self.coords(tagOrId)]} 438 when 'dash', 'activedash', 'disableddash' 439 conf = tk_split_simplelist(tk_send_without_enc('itemconfigure', 440 tagid(tagOrId), 441 "-#{key}")) 442 if conf[3] && conf[3] =~ /^[0-9]/ 443 conf[3] = list(conf[3]) 444 end 445 if conf[4] && conf[4] =~ /^[0-9]/ 446 conf[4] = list(conf[4]) 447 end 448 when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' 449 conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) 450 when 'font', 'kanjifont' 451 conf = tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId),"-#{key}"))) 452 conf[4] = tagfont_configinfo(tagid(tagOrId), conf[4]) 453 else 454 conf = tk_split_list(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId), "-#{key}"))) 455 end 456 key = conf.shift[1..-1] 457 { key => conf } 458 else 459 ret = {} 460 tk_split_simplelist(_fromUTF8(tk_send_without_enc('itemconfigure', tagid(tagOrId)))).each{|conflist| 461 conf = tk_split_simplelist(conflist) 462 key = conf.shift[1..-1] 463 case key 464 when 'text', 'label', 'show', 'data', 'file', 'maskdata', 'maskfile' 465 when 'dash', 'activedash', 'disableddash' 466 if conf[2] && conf[2] =~ /^[0-9]/ 467 conf[2] = list(conf[2]) 468 end 469 if conf[3] && conf[3] =~ /^[0-9]/ 470 conf[3] = list(conf[3]) 471 end 472 else 473 if conf[2] 474 if conf[2].index('{') 475 conf[2] = tk_split_list(conf[2]) 476 else 477 conf[2] = tk_tcl2ruby(conf[2]) 478 end 479 end 480 if conf[3] 481 if conf[3].index('{') 482 conf[3] = tk_split_list(conf[3]) 483 else 484 conf[3] = tk_tcl2ruby(conf[3]) 485 end 486 end 487 end 488 if conf.size == 1 489 ret[key] = conf[0][1..-1] # alias info 490 else 491 ret[key] = conf 492 end 493 } 494 495 fontconf = ret['font'] 496 if fontconf 497 ret.delete('font') 498 ret.delete('kanjifont') 499 fontconf[3] = tagfont_configinfo(tagid(tagOrId), fontconf[3]) 500 ret['font'] = fontconf 501 end 502 503 ret['coords'] = ['', '', '', self.coords(tagOrId)] 504 505 ret 506 end 507 end 508 end 509 510 def current_itemconfiginfo(tagOrId, key=nil) 511 if TkComm::GET_CONFIGINFO_AS_ARRAY 512 if key 513 conf = itemconfiginfo(tagOrId, key) 514 {conf[0] => conf[4]} 515 else 516 ret = {} 517 itemconfiginfo(tagOrId).each{|conf| 518 ret[conf[0]] = conf[4] if conf.size > 2 519 } 520 ret 521 end 522 else # ! TkComm::GET_CONFIGINFO_AS_ARRAY 523 ret = {} 524 itemconfiginfo(tagOrId, key).each{|k, conf| 525 ret[k] = conf[-1] if conf.kind_of?(Array) 526 } 527 ret 528 end 529 end 530=end 531 532 def lower(tag, below=nil) 533 if below 534 tk_send_without_enc('lower', tagid(tag), tagid(below)) 535 else 536 tk_send_without_enc('lower', tagid(tag)) 537 end 538 self 539 end 540 541 def move(tag, dx, dy) 542 tk_send_without_enc('move', tagid(tag), dx, dy) 543 self 544 end 545 546 def moveto(tag, x, y) 547 # Tcl/Tk 8.6 or later 548 tk_send_without_enc('moveto', tagid(tag), x, y) 549 self 550 end 551 alias move_to moveto 552 553 def postscript(keys) 554 tk_send("postscript", *hash_kv(keys)) 555 end 556 557 def raise(tag, above=nil) 558 if above 559 tk_send_without_enc('raise', tagid(tag), tagid(above)) 560 else 561 tk_send_without_enc('raise', tagid(tag)) 562 end 563 self 564 end 565 566 def rchars(tag, first, last, str_or_coords) 567 # Tcl/Tk 8.6 or later 568 str_or_coords = str_or_coords.flatten if str_or_coords.kinad_of? Array 569 tk_send_without_enc('rchars', tagid(tag), first, last, str_or_coords) 570 self 571 end 572 alias replace_chars rchars 573 alias replace_coords rchars 574 575 def scale(tag, x, y, xs, ys) 576 tk_send_without_enc('scale', tagid(tag), x, y, xs, ys) 577 self 578 end 579 580 def scan_mark(x, y) 581 tk_send_without_enc('scan', 'mark', x, y) 582 self 583 end 584 def scan_dragto(x, y, gain=None) 585 tk_send_without_enc('scan', 'dragto', x, y, gain) 586 self 587 end 588 589 def select(mode, *args) 590 r = tk_send_without_enc('select', mode, *args) 591 (mode == 'item')? TkcItem.id2obj(self, r): self 592 end 593 def select_adjust(tagOrId, index) 594 select('adjust', tagid(tagOrId), index) 595 end 596 def select_clear 597 select('clear') 598 end 599 def select_from(tagOrId, index) 600 select('from', tagid(tagOrId), index) 601 end 602 def select_item 603 select('item') 604 end 605 def select_to(tagOrId, index) 606 select('to', tagid(tagOrId), index) 607 end 608 609 def itemtype(tag) 610 TkcItem.type2class(tk_send('type', tagid(tag))) 611 end 612 613 def create_itemobj_from_id(idnum) 614 id = TkcItem.id2obj(self, idnum.to_i) 615 return id if id.kind_of?(TkcItem) 616 617 typename = tk_send('type', id) 618 unless type = TkcItem.type2class(typename) 619 (itemclass = typename.dup)[0,1] = typename[0,1].upcase 620 type = TkcItem.const_set(itemclass, Class.new(TkcItem)) 621 type.const_set("CItemTypeName", typename.freeze) 622 TkcItem::CItemTypeToClass[typename] = type 623 end 624 625 canvas = self 626 (obj = type.allocate).instance_eval{ 627 @parent = @c = canvas 628 @path = canvas.path 629 @id = id 630 TkcItem::CItemID_TBL.mutex.synchronize{ 631 TkcItem::CItemID_TBL[@path] = {} unless TkcItem::CItemID_TBL[@path] 632 TkcItem::CItemID_TBL[@path][@id] = self 633 } 634 } 635 end 636end 637 638#TkCanvas = Tk::Canvas unless Object.const_defined? :TkCanvas 639#Tk.__set_toplevel_aliases__(:Tk, Tk::Canvas, :TkCanvas) 640Tk.__set_loaded_toplevel_aliases__('tk/canvas.rb', :Tk, Tk::Canvas, :TkCanvas) 641 642 643class TkcItem<TkObject 644 extend Tk 645 include TkcTagAccess 646 extend TkItemFontOptkeys 647 extend TkItemConfigOptkeys 648 649 CItemTypeName = nil 650 CItemTypeToClass = {} 651 652 CItemID_TBL = TkCore::INTERP.create_table 653 654 TkCore::INTERP.init_ip_env{ 655 CItemID_TBL.mutex.synchronize{ CItemID_TBL.clear } 656 } 657 658 def TkcItem.type2class(type) 659 CItemTypeToClass[type] 660 end 661 662 def TkcItem.id2obj(canvas, id) 663 cpath = canvas.path 664 CItemID_TBL.mutex.synchronize{ 665 if CItemID_TBL[cpath] 666 CItemID_TBL[cpath][id]? CItemID_TBL[cpath][id]: id 667 else 668 id 669 end 670 } 671 end 672 673 ######################################## 674 def self._parse_create_args(args) 675 fontkeys = {} 676 methodkeys = {} 677 if args[-1].kind_of? Hash 678 keys = _symbolkey2str(args.pop) 679 if args.size == 0 680 args = keys.delete('coords') 681 unless args.kind_of?(Array) 682 fail "coords parameter must be given by an Array" 683 end 684 end 685 686 #['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key| 687 # fontkeys[key] = keys.delete(key) if keys.key?(key) 688 #} 689 __item_font_optkeys(nil).each{|key| 690 fkey = key.to_s 691 fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) 692 693 fkey = "kanji#{key}" 694 fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) 695 696 fkey = "latin#{key}" 697 fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) 698 699 fkey = "ascii#{key}" 700 fontkeys[fkey] = keys.delete(fkey) if keys.key?(fkey) 701 } 702 703 __item_optkey_aliases(nil).each{|alias_name, real_name| 704 alias_name = alias_name.to_s 705 if keys.has_key?(alias_name) 706 keys[real_name.to_s] = keys.delete(alias_name) 707 end 708 } 709 710 __item_methodcall_optkeys(nil).each{|key| 711 key = key.to_s 712 methodkeys[key] = keys.delete(key) if keys.key?(key) 713 } 714 715 __item_ruby2val_optkeys(nil).each{|key, method| 716 key = key.to_s 717 keys[key] = method.call(keys[key]) if keys.has_key?(key) 718 } 719 720 #args = args.flatten.concat(hash_kv(keys)) 721 args = args.flatten.concat(itemconfig_hash_kv(nil, keys)) 722 else 723 args = args.flatten 724 end 725 726 [args, fontkeys, methodkeys] 727 end 728 private_class_method :_parse_create_args 729 730 def self.create(canvas, *args) 731 unless self::CItemTypeName 732 fail RuntimeError, "#{self} is an abstract class" 733 end 734 args, fontkeys, methodkeys = _parse_create_args(args) 735 idnum = tk_call_without_enc(canvas.path, 'create', 736 self::CItemTypeName, *args) 737 canvas.itemconfigure(idnum, fontkeys) unless fontkeys.empty? 738 canvas.itemconfigure(idnum, methodkeys) unless methodkeys.empty? 739 idnum.to_i # 'canvas item id' is an integer number 740 end 741 ######################################## 742 743 def initialize(parent, *args) 744 #unless parent.kind_of?(Tk::Canvas) 745 # fail ArgumentError, "expect Tk::Canvas for 1st argument" 746 #end 747 @parent = @c = parent 748 @path = parent.path 749 750 @id = create_self(*args) # an integer number as 'canvas item id' 751 CItemID_TBL.mutex.synchronize{ 752 CItemID_TBL[@path] = {} unless CItemID_TBL[@path] 753 CItemID_TBL[@path][@id] = self 754 } 755 end 756 def create_self(*args) 757 self.class.create(@c, *args) # return an integer number as 'canvas item id' 758 end 759 private :create_self 760 761 def id 762 @id 763 end 764 765 def exist? 766 if @c.find_withtag(@id) 767 true 768 else 769 false 770 end 771 end 772 773 def delete 774 @c.delete @id 775 CItemID_TBL.mutex.synchronize{ 776 CItemID_TBL[@path].delete(@id) if CItemID_TBL[@path] 777 } 778 self 779 end 780 alias remove delete 781 alias destroy delete 782end 783 784class TkcArc<TkcItem 785 CItemTypeName = 'arc'.freeze 786 CItemTypeToClass[CItemTypeName] = self 787end 788 789class TkcBitmap<TkcItem 790 CItemTypeName = 'bitmap'.freeze 791 CItemTypeToClass[CItemTypeName] = self 792end 793 794class TkcImage<TkcItem 795 CItemTypeName = 'image'.freeze 796 CItemTypeToClass[CItemTypeName] = self 797end 798 799class TkcLine<TkcItem 800 CItemTypeName = 'line'.freeze 801 CItemTypeToClass[CItemTypeName] = self 802end 803 804class TkcOval<TkcItem 805 CItemTypeName = 'oval'.freeze 806 CItemTypeToClass[CItemTypeName] = self 807end 808 809class TkcPolygon<TkcItem 810 CItemTypeName = 'polygon'.freeze 811 CItemTypeToClass[CItemTypeName] = self 812end 813 814class TkcRectangle<TkcItem 815 CItemTypeName = 'rectangle'.freeze 816 CItemTypeToClass[CItemTypeName] = self 817end 818 819class TkcText<TkcItem 820 CItemTypeName = 'text'.freeze 821 CItemTypeToClass[CItemTypeName] = self 822 def self.create(canvas, *args) 823 if args[-1].kind_of?(Hash) 824 keys = _symbolkey2str(args.pop) 825 txt = keys['text'] 826 keys['text'] = _get_eval_enc_str(txt) if txt 827 args.push(keys) 828 end 829 super(canvas, *args) 830 end 831end 832 833class TkcWindow<TkcItem 834 CItemTypeName = 'window'.freeze 835 CItemTypeToClass[CItemTypeName] = self 836 def self.create(canvas, *args) 837 if args[-1].kind_of?(Hash) 838 keys = _symbolkey2str(args.pop) 839 win = keys['window'] 840 # keys['window'] = win.epath if win.kind_of?(TkWindow) 841 keys['window'] = _epath(win) if win 842 args.push(keys) 843 end 844 super(canvas, *args) 845 end 846end 847