1# 2# Tk::RbWidget::Editable_Listbox class 3# 4# When "DoubleClick-1" on a listbox item, the entry box is opend on the 5# item. And when hit "Return" key on the entry box after modifying the 6# text, the entry box is closed and the item is changed. Or when hit 7# "Escape" key, the entry box is closed without modification. 8# 9# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) 10# 11require 'tk' 12 13module Tk 14 module RbWidget 15 class Editable_Listbox < TkListbox 16 end 17 end 18end 19 20 21class Tk::RbWidget::Editable_Listbox < TkListbox 22 #------------------------------------ 23 BindTag = TkBindTag.new_by_name(self.to_s.gsub(/::/, '#')) 24 25 BindTag.bind('FocusIn', :widget){|w| 26 w.instance_eval{ 27 if idx = @ebox.pos 28 see(idx) if bbox(idx).empty? 29 @ebox.focus(true) 30 end 31 } 32 } 33 34 BindTag.bind('Double-1', :widget, :y){|w, y| 35 w.instance_eval{ _ebox_placer(nearest(y)) } 36 } 37 38 BindTag.bind('Return', :widget){|w| 39 w.instance_eval{ 40 if idx = index(:active) 41 _ebox_placer(idx) 42 end 43 } 44 } 45 #------------------------------------ 46 47 def configure(*args) 48 ret = super 49 50 case cget(:state) 51 when 'normal' 52 # do nothing 53 when 'disabled' 54 _ebox_erase 55 else # unknown 56 # do nothing 57 58 end 59 60 ret 61 end 62 63 def _ebox_move(idx) 64 return nil if cget(:state) == 'disabled' 65 x, y, w, h = bbox(idx) 66 return nil unless y && h 67 @ebox.place(:x => 0, :relwidth => 1.0, 68 :y => y - selectborderwidth, 69 :height => h + 2 * selectborderwidth) 70 @ebox.pos = idx 71 @ebox.focus 72 end 73 74 def _ebox_placer(idx) 75 return nil unless _ebox_move(idx) 76 @ebox.value = listvariable.list[idx] 77 @ebox.xview_moveto(self.xview[0]) 78 end 79 80 def _ebox_erase 81 @ebox.place_forget 82 @ebox.pos = nil 83 end 84 private :_ebox_move, :_ebox_placer, :_ebox_erase 85 86 def _setup_ebox_bindings 87 # bindings for entry 88 @ebox.bind('Return'){ 89 list = listvariable.list 90 list[@ebox.pos] = @ebox.value if @ebox.pos 91 listvariable.value = list 92 _ebox_erase 93 focus 94 } 95 96 @ebox.bind('Escape'){ _ebox_erase } 97 end 98 def _setup_listbox_bindings 99 # bindings for listbox 100 tags = bindtags 101 bindtags(tags.insert(tags.index(self) + 1, self.class::BindTag)) 102 end 103 private :_setup_ebox_bindings, :_setup_listbox_bindings 104 105 def yview(*args) 106 if !@ebox.pos || bbox(@ebox.pos).empty? 107 @ebox.place_forget 108 else 109 _ebox_move(@ebox.pos) 110 end 111 super 112 end 113 114 def create_self(keys) 115 super(keys) 116 117 unless self.listvariable 118 self.listvariable = TkVariable.new(self.get(0, :end)) 119 end 120 121 @ebox = TkEntry.new(self){ 122 @pos = nil 123 def self.pos; @pos; end 124 def self.pos=(idx); @pos = idx; end 125 } 126 127 _setup_ebox_bindings 128 _setup_listbox_bindings 129 end 130end 131 132if $0 == __FILE__ 133 #lbox0 = TkListbox.new.pack(:side=>:left) 134 #lbox0.insert(:end, 0,1,2,3,4,5,6,7,8,9,0,1,2,3) 135 136 scr = TkScrollbar.new.pack(:side=>:right, :fill=>:y) 137 138 lbox1 = Tk::RbWidget::Editable_Listbox.new.pack(:side=>:left) 139 lbox2 = Tk::RbWidget::Editable_Listbox.new.pack(:side=>:left) 140 141 scr.assign(lbox1, lbox2) 142 143 lbox1.insert(:end, *%w(a b c d e f g h i j k l m n)) 144 lbox2.insert(:end, 0,1,2,3,4,5,6,7,8,9,0,1,2,3) 145 146 147 Tk.mainloop 148end 149