1# 2# tkextlib/blt/tabset.rb 3# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) 4# 5 6require 'tk' 7require 'tkextlib/blt.rb' 8 9module Tk::BLT 10 class Tabset < TkWindow 11 class Tab < TkObject 12 include TkTreatItemFont 13 14 TabID_TBL = TkCore::INTERP.create_table 15 16 (TabsetTab_ID = ['blt_tabset_tab'.freeze, TkUtil.untrust('00000')]).instance_eval{ 17 @mutex = Mutex.new 18 def mutex; @mutex; end 19 freeze 20 } 21 22 TkCore::INTERP.init_ip_env{ 23 TabID_TBL.mutex.synchronize{ TabID_TBL.clear } 24 } 25 26 def self.id2obj(tabset, id) 27 tpath = tabset.path 28 TabID_TBL.mutex.synchronize{ 29 if TabID_TBL[tpath] 30 TabID_TBL[tpath][id]? TabID_TBL[tpath][id]: id 31 else 32 id 33 end 34 } 35 end 36 37 def self.new(parent, pos=nil, name=nil, keys={}) 38 if pos.kind_of?(Hash) 39 keys = pos 40 name = nil 41 pos = nil 42 end 43 if name.kind_of?(Hash) 44 keys = name 45 name = nil 46 end 47 obj = nil 48 TabID_TBL.mutex.synchronize{ 49 if name && TabID_TBL[parent.path] && TabID_TBL[parent.path][name] 50 obj = TabID_TBL[parent.path][name] 51 if pos 52 if pos.to_s == 'end' 53 obj.move_after('end') 54 else 55 obj.move_before(pos) 56 end 57 end 58 obj.configure if keys && ! keys.empty? 59 else 60 (obj = self.allocate).instance_eval{ 61 initialize(parent, pos, name, keys) 62 TabID_TBL[@tpath] = {} unless TabID_TBL[@tpath] 63 TabID_TBL[@tpath][@id] = self 64 } 65 end 66 } 67 obj 68 end 69 70 def initialize(parent, pos, name, keys) 71 @t = parent 72 @tpath = parent.path 73 if name 74 @path = @id = name 75 unless (list(tk_call(@tpath, 'tab', 'names', @id)).empty?) 76 if pos 77 idx = tk_call(@tpath, 'index', '-name', @id) 78 if pos.to_s == 'end' 79 tk_call(@tpath, 'move', idx, 'after', 'end') 80 else 81 tk_call(@tpath, 'move', idx, 'before', pos) 82 end 83 end 84 tk_call(@tpath, 'tab', 'configure', @id, keys) 85 else 86 pos = 'end' unless pos 87 tk_call(@tpath, 'insert', pos, @id, keys) 88 end 89 else 90 pos = 'end' unless pos 91 TabsetTab_ID.mutex.synchronize{ 92 @path = @id = TabsetTab_ID.join(TkCore::INTERP._ip_id_) 93 TabsetTab_ID[1].succ! 94 } 95 tk_call(@tpath, 'insert', pos, @id, keys) 96 end 97 end 98 99 #def bind(context, cmd=Proc.new, *args) 100 # @t.tab_bind(@id, context, cmd, *args) 101 # self 102 #end 103 def bind(context, *args) 104 # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 105 if TkComm._callback_entry?(args[0]) || !block_given? 106 cmd = args.shift 107 else 108 cmd = Proc.new 109 end 110 @t.tab_bind(@id, context, cmd, *args) 111 self 112 end 113 #def bind_append(context, cmd=Proc.new, *args) 114 # @t.tab_bind_append(@id, context, cmd, *args) 115 # self 116 #end 117 def bind_append(context, *args) 118 # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 119 if TkComm._callback_entry?(args[0]) || !block_given? 120 cmd = args.shift 121 else 122 cmd = Proc.new 123 end 124 @t.tab_bind_append(@id, context, cmd, *args) 125 self 126 end 127 def bind_remove(context) 128 @t.tab_bind_remove(@id, context) 129 self 130 end 131 def bindinfo(context=nil) 132 @t.tab_bindinfo(@id, context) 133 end 134 135 def cget_tkstring(*args) 136 @t.tab_cget_tkstring(@id, *args) 137 end 138 def cget(*args) 139 @t.tab_cget(@id, *args) 140 end 141 def cget_strict(*args) 142 @t.tab_cget_strict(@id, *args) 143 end 144 def configure(*args) 145 @t.tab_configure(@id, *args) 146 end 147 def configinfo(*args) 148 @t.tab_configinfo(@id, *args) 149 end 150 def current_configinfo(*args) 151 @t.current_tab_configinfo(@id, *args) 152 end 153 154 def delete() 155 @t.delete(@id) 156 TabID_TBL.mutex.synchronize{ 157 TabID_TBL[@tpath].delete(@id) 158 } 159 self 160 end 161 162 def get_name() 163 @id.dup 164 end 165 166 def focus() 167 @t.focus(self.index) 168 end 169 170 def index() 171 @t.index_name(@id) 172 end 173 174 def invoke() 175 @t.invoke(self.index) 176 end 177 178 def move_before(idx) 179 @t.move_before(self.index, idx) 180 end 181 def move_after(idx) 182 @t.move_after(self.index, idx) 183 end 184 185 def perforation_highlight(mode) 186 @t.perforation_highlight(self.index, mode) 187 end 188 def perforation_invoke() 189 @t.perforation_invoke(self.index) 190 end 191 192 def see() 193 @t.see(self.index) 194 end 195 196 def tearoff(name=None) 197 @t.tab_tearoff(self.index, *args) 198 end 199 end 200 201 ######################################## 202 203 class NamedTab < Tab 204 def self.new(parent, name) 205 super(parent, nil, name, {}) 206 end 207 end 208 209 ######################################## 210 211 include X_Scrollable 212 include TkItemConfigMethod 213 214 TkCommandNames = ['::blt::tabset'.freeze].freeze 215 WidgetClassName = 'Tabset'.freeze 216 WidgetClassNames[WidgetClassName] ||= self 217 218 def __destroy_hook__ 219 Tk::BLT::Tabset::Tab::TabID_TBL.mutex.synchronize{ 220 Tk::BLT::Tabset::Tab::TabID_TBL.delete(@path) 221 } 222 end 223 224 ######################################## 225 226 def __boolval_optkeys 227 super() << 'samewidth' << 'tearoff' 228 end 229 private :__strval_optkeys 230 231 def __strval_optkeys 232 super() << 'tabbackground' << 'tabforeground' 233 end 234 private :__strval_optkeys 235 236 def __item_cget_cmd(id) 237 [self.path, 'tab', 'cget', id] 238 end 239 private :__item_cget_cmd 240 241 def __item_config_cmd(id) 242 [self.path, 'tab', 'configure', id] 243 end 244 private :__item_config_cmd 245 246 def __item_pathname(tagOrId) 247 if tagOrId.kind_of?(Tk::BLT::Tabset::Tab) 248 self.path + ';' + tagOrId.id.to_s 249 else 250 self.path + ';' + tagOrId.to_s 251 end 252 end 253 private :__item_pathname 254 255 alias tab_cget_tkstring itemcget_tkstring 256 alias tab_cget itemcget 257 alias tab_cget_strict itemcget_strict 258 alias tab_configure itemconfigure 259 alias tab_configinfo itemconfiginfo 260 alias current_tab_configinfo current_itemconfiginfo 261 262 def __item_strval_optkeys(id) 263 super(id) << 'shadow' 264 end 265 private :__item_strval_optkeys 266 267 def tagid(tab) 268 if tab.kind_of?(Tk::BLT::Tabset::Tab) 269 tab.id 270 else 271 tab 272 end 273 end 274 275 def tagindex(tab) 276 if tab.kind_of?(Tk::BLT::Tabset::Tab) 277 tab.index 278 else 279 tab 280 end 281 end 282 283 ######################################## 284 285 def activate(index) 286 tk_send('activate', tagindex(index)) 287 self 288 end 289 alias highlight activate 290 291 #def tabbind(tag, context, cmd=Proc.new, *args) 292 # _bind([path, "bind", tagid(tag)], context, cmd, *args) 293 # self 294 #end 295 def tabbind(tag, context, *args) 296 # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 297 if TkComm._callback_entry?(args[0]) || !block_given? 298 cmd = args.shift 299 else 300 cmd = Proc.new 301 end 302 _bind([path, "bind", tagid(tag)], context, cmd, *args) 303 self 304 end 305 #def tabbind_append(tag, context, cmd=Proc.new, *args) 306 # _bind_append([path, "bind", tagid(tag)], context, cmd, *args) 307 # self 308 #end 309 def tabbind_append(tag, context, *args) 310 # if args[0].kind_of?(Proc) || args[0].kind_of?(Method) 311 if TkComm._callback_entry?(args[0]) || !block_given? 312 cmd = args.shift 313 else 314 cmd = Proc.new 315 end 316 _bind_append([path, "bind", tagid(tag)], context, cmd, *args) 317 self 318 end 319 def tabbind_remove(tag, context) 320 _bind_remove([path, "bind", tagid(tag)], context) 321 self 322 end 323 def tabbindinfo(tag, context=nil) 324 _bindinfo([path, "bind", tagid(tag)], context) 325 end 326 327 def delete(first, last=None) 328 tk_send('delete', tagindex(first), tagindex(last)) 329 if first.kind_of?(Tk::BLT::Tabset::Tab) 330 TabID_TBL.mutex.synchronize{ 331 TabID_TBL[@path].delete(first.id) 332 } 333 end 334 # middle tabs of the range are unknown 335 if last.kind_of?(Tk::BLT::Tabset::Tab) 336 TabID_TBL.mutex.synchronize{ 337 TabID_TBL[@path].delete(last.id) 338 } 339 end 340 self 341 end 342 343 def focus(index) 344 tk_send('focus', tagindex(index)) 345 self 346 end 347 348 def get_tab(index) 349 if (idx = tk_send_without_enc('get', tagindex(index))).empty? 350 nil 351 else 352 Tk::BLT::Tabset::Tab.id2obj(self, idx) 353 end 354 end 355 def get_tabobj(index) 356 if (idx = tk_send_without_enc('get', tagindex(index))).empty? 357 nil 358 else 359 Tk::BLT::Tabset::Tab.new(self, nil, name, {}) 360 end 361 end 362 363 def index(str) 364 num_or_str(tk_send('index', str)) 365 end 366 def index_name(tab) 367 num_or_str(tk_send('index', '-name', tagid(tab))) 368 end 369 370 def insert(pos, tab, keys={}) 371 pos = 'end' if pos.nil? 372 Tk::BLT::Tabset::Tab.new(self, tagindex(pos), tagid(tab), keys) 373 end 374 def insert_tabs(pos, *tabs) 375 pos = 'end' if pos.nil? 376 if tabs[-1].kind_of?(Hash) 377 keys = tabs.pop 378 else 379 keys = {} 380 end 381 fail ArgumentError, 'no tabs is given' if tabs.empty? 382 tabs.map!{|tab| tagid(tab)} 383 tk_send('insert', tagindex(pos), *(tabs + [keys])) 384 tabs.collect{|tab| Tk::BLT::Tabset::Tab.new(self, nil, tagid(tab))} 385 end 386 387 def invoke(index) 388 tk_send('invoke', tagindex(index)) 389 end 390 391 def move_before(index, base_idx) 392 tk_send('move', tagindex(index), 'before', tagindex(base_idx)) 393 self 394 end 395 def move_after(index, base_idx) 396 tk_send('move', tagindex(index), 'after', tagindex(base_idx)) 397 self 398 end 399 400 def nearest(x, y) 401 Tk::BLT::Tabset::Tab.id2obj(self, num_or_str(tk_send_without_enc('nearest', x, y))) 402 end 403 404 def perforation_activate(mode) 405 tk_send('perforation', 'activate', mode) 406 self 407 end 408 def perforation_highlight(index, *args) 409 if args.empty? 410 # index --> mode 411 tk_send('perforation', 'highlight', index) 412 elsif args.size == 1 413 # args[0] --> mode 414 tk_send('perforation', 'highlight', tagindex(index), args[0]) 415 else # Error: call to get Tcl's error message 416 tk_send('perforation', 'highlight', tagindex(index), *args) 417 end 418 self 419 end 420 def perforation_invoke(index=nil) 421 if index 422 tk_send('perforation', 'invoke', tagindex(index)) 423 else 424 tk_send('perforation', 'invoke') 425 end 426 end 427 428 def scan_mark(x, y) 429 tk_send_without_enc('scan', 'mark', x, y) 430 self 431 end 432 def scan_dragto(x, y) 433 tk_send_without_enc('scan', 'dragto', x, y) 434 self 435 end 436 437 def see(index) 438 tk_send('see', tagindex(index)) 439 self 440 end 441 442 def size() 443 number(tk_send_without_enc('size')) 444 end 445 446 def select(index) 447 tk_send('select', tagindex(index)) 448 self 449 end 450 451 def tab_dockall 452 tk_send('tab', 'dockall') 453 self 454 end 455 456 def tab_names(pat=None) 457 simplelist(tk_send('tab', 'names', pat)).collect{|name| 458 Tk::BLT::Tabset::Tab.id2obj(self, name) 459 } 460 end 461 462 def tab_objs(pat=None) 463 simplelist(tk_send('tab', 'names', pat)).collect{|name| 464 Tk::BLT::Tabset::Tab.new(self, nil, name, {}) 465 } 466 end 467 468 def tab_ids(pat=None) 469 simplelist(tk_send('tab', 'names', pat)) 470 end 471 472 def tab_pageheight 473 number(tk_send('tab', 'pageheight')) 474 end 475 476 def tab_pagewidth 477 number(tk_send('tab', 'pagewidth')) 478 end 479 480 def tab_tearoff(index, parent=None) 481 window(tk_send('tab', 'tearoff', tagindex(index), parent)) 482 end 483 484 def xscrollcommand(cmd=Proc.new) 485 configure_cmd 'scrollcommand', cmd 486 self 487 end 488 alias scrollcommand xscrollcommand 489 490 def xview(*index) 491 if index.empty? 492 list(tk_send_without_enc('view')) 493 else 494 tk_send_without_enc('view', *index) 495 self 496 end 497 end 498 alias view xview 499 alias view_moveto xview_moveto 500 alias view_scroll xview_scroll 501 502 alias scrollbar xscrollbar 503 end 504end 505