File: tk/canvas.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: Tk
  class: Canvas#42
includes
  TkCanvasItemConfig   
  Scrollable ( Tk )
inherits from
  TkWindow   
has properties
constant: TkCommandNames #46
constant: WidgetClassName #47
method: __destroy_hook__ #50
method: __numval_optkeys #63
method: __boolval_optkeys #68
method: tagid / 1 #73
method: create / 2 #84
method: addtag / 3 #89
method: addtag_above / 2 #97
method: addtag_all / 1 #100
method: addtag_below / 2 #103
method: addtag_closest / 5 #106
method: addtag_enclosed / 5 #109
method: addtag_overlapping / 5 #112
method: addtag_withtag / 2 #115
method: bbox / 2 #119
method: itembind / 3 #128
method: itembind_append / 3 #143
method: itembind_remove / 2 #154
method: itembindinfo / 2 #159
method: canvasx / 2 #163
method: canvasy / 2 #167
alias: canvas_x canvasx #171
alias: canvas_y canvasy #172
method: coords / 2 #174
method: dchars / 3 #183
method: delete / 1 #189
alias: remove delete #208
method: dtag / 2 #210
alias: deltag dtag #214
method: find / 2 #216
method: find_above / 1 #221
method: find_all #224
method: find_below / 1 #227
method: find_closest / 4 #230
method: find_enclosed / 4 #233
method: find_overlapping / 4 #236
method: find_withtag / 1 #239
method: itemfocus / 1 #243
method: gettags / 1 #257
method: icursor / 2 #263
method: index / 2 #268
method: insert / 3 #272
method: lower / 2 #517
method: move / 3 #526
method: postscript / 1 #531
method: raise / 2 #535
method: scale / 5 #544
method: scan_mark / 2 #549
method: scan_dragto / 3 #553
method: select / 2 #558
method: select_adjust / 2 #562
method: select_clear #565
method: select_from / 2 #568
method: select_item #571
method: select_to / 2 #574
method: itemtype / 1 #578
  module: TkCanvasItemConfig#10
includes
  TkItemConfigMethod   
has properties
method: __item_strval_optkeys / 1 #13
method: __item_methodcall_optkeys / 1 #22
method: __item_val2ruby_optkeys / 1 #27
method: __item_pathname / 1 #32
  class: TkcItem#587
extends
  Tk   
  TkItemConfigOptkeys   
  TkItemFontOptkeys   
includes
  TkcTagAccess   
inherits from
  TkObject   
has properties
constant: CItemTypeName #593
constant: CItemTypeToClass #594
constant: CItemID_TBL #596
class method: type2class / 1 #602
class method: id2obj / 2 #606
class method: _parse_create_args / 1 #618
class method: create / 2 #674
method: initialize / 2 #686
method: create_self / 1 #699
method: id #704
method: exist? #708
method: delete #716
alias: remove delete #723
alias: destroy delete #724
  class: TkcArc#727
inherits from
  TkcItem   
has properties
constant: CItemTypeName #728
  class: TkcBitmap#732
inherits from
  TkcItem   
has properties
constant: CItemTypeName #733
  class: TkcImage#737
inherits from
  TkcItem   
has properties
constant: CItemTypeName #738
  class: TkcLine#742
inherits from
  TkcItem   
has properties
constant: CItemTypeName #743
  class: TkcOval#747
inherits from
  TkcItem   
has properties
constant: CItemTypeName #748
  class: TkcPolygon#752
inherits from
  TkcItem   
has properties
constant: CItemTypeName #753
  class: TkcRectangle#757
inherits from
  TkcItem   
has properties
constant: CItemTypeName #758
  class: TkcText#762
inherits from
  TkcItem   
has properties
constant: CItemTypeName #763
class method: create / 2 #765
  class: TkcWindow#776
inherits from
  TkcItem   
has properties
constant: CItemTypeName #777
class method: create / 2 #779

Class Hierarchy

Object ( Builtin-Module )
TkKernel
TkObject
TkWindow
  Canvas ( Tk ) #42
TkcItem#587
  TkcArc    #727
  TkcBitmap    #732
  TkcImage    #737
  TkcLine    #742
  TkcOval    #747
  TkcPolygon    #752
  TkcRectangle    #757
  TkcText    #762
  TkcWindow    #776

Code

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