diff options
author | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2003-11-22 13:52:48 +0000 |
---|---|---|
committer | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2003-11-22 13:52:48 +0000 |
commit | 615a54e77d00c0b456fe6a6f8b6d48203e25b3ac (patch) | |
tree | bf0ace3a2218c9f5558eb31073d899e90d51c360 /ext/tk/sample | |
parent | 448b1af751fed5976948d629d9b7028a7d044506 (diff) | |
download | ruby-615a54e77d00c0b456fe6a6f8b6d48203e25b3ac.tar.gz |
* ext/tk/lib/tk.rb: add Tk.grab_release and fix bug of TkComposite
* ext/tk/lib/tkafter.rb: bug fix
* ext/tk/sample/tkcombobox.rb: new sample script
* ext/tcltklib/tcltklib.c: add native thread check
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@5007 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/tk/sample')
-rw-r--r-- | ext/tk/sample/tkcombobox.rb | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/ext/tk/sample/tkcombobox.rb b/ext/tk/sample/tkcombobox.rb new file mode 100644 index 0000000000..08a2dd73a7 --- /dev/null +++ b/ext/tk/sample/tkcombobox.rb @@ -0,0 +1,418 @@ +# +# tkcombobox.rb : TkAutoScrollbox & TkCombobox +# +# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp) +# +require 'tk' + +class TkAutoScrollbox < TkListbox + include TkComposite + + @@up_bmp = TkBitmapImage.new(:data=><<EOD) +#define up_arrow_width 9 +#define up_arrow_height 9 +static unsigned char up_arrow_bits[] = { + 0x00, 0x00, 0x10, 0x00, 0x10, 0x00, 0x38, 0x00, 0x38, 0x00, 0x7c, 0x00, + 0x7c, 0x00, 0xfe, 0x00, 0x00, 0x00}; +EOD + + @@down_bmp = TkBitmapImage.new(:data=><<EOD) +#define up_arrow_width 9 +#define up_arrow_height 9 +static unsigned char down_arrow_bits[] = { + 0x00, 0x00, 0xfe, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x38, 0x00, + 0x10, 0x00, 0x10, 0x00, 0x00, 0x00}; +EOD + + def initialize_composite(keys={}) + keys = _symbolkey2str(keys) + + @initwait = keys.delete('startwait'){300} + @interval = keys.delete('interval'){150} + @initwait -= @interval + @initwait = 0 if @initwait < 0 + + @lbox = TkListbox.new(@frame, :borderwidth=>0) + @path = @lbox.path + TkPack.propagate(@lbox, false) + + @scr = TkScrollbar.new(@frame, :width=>10) + + @lbox.yscrollcommand(proc{|*args| @scr.set(*args); _config_proc}) + @scr.command(proc{|*args| @lbox.yview(*args); _config_proc}) + + @up_arrow = TkLabel.new(@lbox, :image=>@@up_bmp, + :relief=>:raised, :borderwidth=>1) + @down_arrow = TkLabel.new(@lbox, :image=>@@down_bmp, + :relief=>:raised, :borderwidth=>1) + + _init_binding + + @lbox.pack(:side=>:left, :fill=>:both, :expand=>:true) + + delegate('DEFAULT', @lbox) + delegate('background', @frame, @scr) + delegate('activebackground', @scr) + delegate('troughcolor', @scr) + delegate('repeatdelay', @scr) + delegate('repeatinterval', @scr) + delegate('relief', @frame) + delegate('borderwidth', @frame) + + scrollbar(keys.delete('scrollbar')){false} + + configure keys unless keys.empty? + end + + ############################ + private + ############################ + def _show_up_arrow + unless @up_arrow.winfo_mapped? + @up_arrow.pack(:side=>:top, :fill=>:x) + end + end + + def _show_down_arrow + unless @down_arrow.winfo_mapped? + @down_arrow.pack(:side=>:bottom, :fill=>:x) + end + end + + def _set_sel(idx) + @lbox.activate(idx) + @lbox.selection_clear(0, 'end') + @lbox.selection_set(idx) + end + + def _check_sel(cidx, tidx = nil, bidx = nil) + _set_sel(cidx) + unless tidx + tidx = @lbox.nearest(0) + tidx += 1 if tidx > 0 + end + unless bidx + bidx = @lbox.nearest(10000) + bidx -= 1 if bidx < @lbox.index('end') - 1 + end + if cidx > bidx + _set_sel(bidx) + end + if cidx < tidx + _set_sel(tidx) + end + end + + def _up_proc + cidx = @lbox.curselection[0] + idx = @lbox.nearest(0) + if idx >= 0 + @lbox.see(idx - 1) + _set_sel(idx) + @up_arrow.pack_forget if idx == 1 + @up_timer.stop if idx == 0 + _show_down_arrow if @lbox.bbox('end') == [] + end + if cidx && cidx > 0 && (idx == 0 || cidx == @lbox.nearest(10000)) + _set_sel(cidx - 1) + end + end + + def _down_proc + cidx = @lbox.curselection[0] + eidx = @lbox.index('end') - 1 + idx = @lbox.nearest(10000) + if idx <= eidx + @lbox.see(idx + 1) + _set_sel(cidx + 1) if cidx < eidx + @down_arrow.pack_forget if idx + 1 == eidx + @down_timer.stop if idx == eidx + _show_up_arrow if @lbox.bbox(0) == [] + end + if cidx && cidx < eidx && (eidx == idx || cidx == @lbox.nearest(0)) + _set_sel(cidx + 1) + end + end + + def _key_UP_proc + cidx = @lbox.curselection[0] + _set_sel(cidx = @lbox.index('activate')) unless cidx + cidx -= 1 + if cidx == 0 + @up_arrow.pack_forget + elsif cidx == @lbox.nearest(0) + @lbox.see(cidx - 1) + end + end + + def _key_DOWN_proc + cidx = @lbox.curselection[0] + _set_sel(cidx = @lbox.index('activate')) unless cidx + cidx += 1 + if cidx == @lbox.index('end') - 1 + @down_arrow.pack_forget + elsif cidx == @lbox.nearest(10000) + @lbox.see(cidx + 1) + end + end + + def _config_proc + if @lbox.size == 0 + @up_arrow.pack_forget + @down_arrow.pack_forget + return + end + tidx = @lbox.nearest(0) + bidx = @lbox.nearest(10000) + if tidx > 0 + _show_up_arrow + tidx += 1 + else + @up_arrow.pack_forget unless @up_timer.running? + end + if bidx < @lbox.index('end') - 1 + _show_down_arrow + bidx -= 1 + else + @down_arrow.pack_forget unless @down_timer.running? + end + cidx = @lbox.curselection[0] + _check_sel(cidx, tidx, bidx) if cidx + end + + def _init_binding + @up_timer = TkAfter.new(@interval, -1, proc{_up_proc}) + @down_timer = TkAfter.new(@interval, -1, proc{_down_proc}) + + @up_timer.set_start_proc(@initwait, proc{}) + @down_timer.set_start_proc(@initwait, proc{}) + + @up_arrow.bind('Enter', proc{@up_timer.start}) + @up_arrow.bind('Leave', proc{@up_timer.stop if @up_arrow.winfo_mapped?}) + @down_arrow.bind('Enter', proc{@down_timer.start}) + @down_arrow.bind('Leave', proc{@down_timer.stop if @down_arrow.winfo_mapped?}) + + @lbox.bind('Configure', proc{_config_proc}) + @lbox.bind('Enter', proc{|y| _set_sel(@lbox.nearest(y))}, '%y') + @lbox.bind('Motion', proc{|y| + @up_timer.stop if @up_timer.running? + @down_timer.stop if @down_timer.running? + _check_sel(@lbox.nearest(y)) + }, '%y') + + @lbox.bind('Up', proc{_key_UP_proc}) + @lbox.bind('Down', proc{_key_DOWN_proc}) + end + + ############################ + public + ############################ + def scrollbar(mode) + if mode + @scr.pack(:side=>:right, :fill=>:y) + else + @scr.pack_forget + end + end +end + +################################################ + +class TkCombobox < TkEntry + include TkComposite + + @@down_btn_bmp = TkBitmapImage.new(:data=><<EOD) +#define down_arrow_width 11 +#define down_arrow_height 11 +static unsigned char down_arrow_bits[] = { + 0x00, 0x00, 0xfe, 0x03, 0xfc, 0x01, 0xfc, 0x01, 0xf8, 0x00, 0xf8, 0x00, + 0x70, 0x00, 0x70, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00}; +EOD + + @@up_btn_bmp = TkBitmapImage.new(:data=><<EOD) +#define up_arrow_width 11 +#define up_arrow_height 11 +static unsigned char up_arrow_bits[] = { + 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x70, 0x00, 0x70, 0x00, 0xf8, 0x00, + 0xf8, 0x00, 0xfc, 0x01, 0xfc, 0x01, 0xfe, 0x03, 0x00, 0x00}; +EOD + + def _button_proc(dir = true) + @btn.relief(:sunken) + x = @frame.winfo_rootx + y = @frame.winfo_rooty + if dir + @top.geometry("+#{x}+#{y + @frame.winfo_height}") + else + @btn.image(@@up_btn_bmp) + @top.geometry("+#{x}+#{y - @top.winfo_reqheight}") + end + @top.deiconify + @lst.focus + + if (idx = values.index(@ent.value)) + @lst.see(idx - 1) + @lst.activate(idx) + @lst.selection_set(idx) + elsif @lst.size > 0 + @lst.see(0) + @lst.activate(0) + @lst.selection_set(0) + end + @top.grab + + begin + @var.tkwait + if (idx = @var.to_i) >= 0 + @ent.value = @lst.get(idx) + end + @top.withdraw + @btn.relief(:raised) + @btn.image(@@down_btn_bmp) + rescue + ensure + begin + @top.grab(:release) + @ent.focus + rescue + end + end + end + private :_button_proc + + def _init_bindings + @btn.bind('1', proc{_button_proc(true)}) + @btn.bind('3', proc{_button_proc(false)}) + + @lst.bind('1', proc{|y| @var.value = @lst.nearest(y)}, '%y') + @lst.bind('Return', proc{@var.value = @lst.curselection[0]}) + + cancel = TkVirtualEvent.new('2', '3', 'Escape') + @lst.bind(cancel, proc{@var.value = -1}) + end + private :_init_bindings + + def initialize_composite(keys={}) + keys = _symbolkey2str(keys) + + @btn = TkLabel.new(@frame, :relief=>:raised, :borderwidth=>3, + :image=>@@down_btn_bmp).pack(:side=>:right, + :ipadx=>2, :fill=>:y) + @ent = TkEntry.new(@frame).pack(:side=>:left) + @path = @ent.path + + @top = TkToplevel.new(@btn, :borderwidth=>1, :relief=>:raised) { + withdraw + transient + overrideredirect(true) + } + + startwait = keys.delete('startwait'){300} + interval = keys.delete('interval'){150} + @lst = TkAutoScrollbox.new(@top, + :startwait=>startwait, + :interval=>interval).pack(:fill=>:both, + :expand=>true) + @ent_list = [] + + @var = TkVariable.new + + _init_bindings + + delegate('DEFAULT', @ent) + delegate('height', @lst) + delegate('relief', @frame) + delegate('borderwidth', @frame) + + if mode = keys.delete('scrollbar') + scrollbar(mode) + end + + configure keys unless keys.empty? + end + + def scrollbar(mode) + @lst.scrollbar(mode) + end + + def _reset_width + len = @ent.width + @lst.get(0, 'end').each{|l| len = l.length if l.length > len} + @lst.width(len + 1) + end + private :_reset_width + + def add(ent) + ent = ent.to_s + unless @ent_list.index(ent) + @ent_list << ent + @lst.insert('end', ent) + end + _reset_width + self + end + + def remove(ent) + ent = ent.to_s + @ent_list.delete(ent) + if idx = @lst.get(0, 'end').index(ent) + @lst.delete(idx) + end + _reset_width + self + end + + def values(ary = nil) + if ary + @lst.delete(0, 'end') + @ent_list.clear + ary.each{|ent| add(ent)} + _reset_width + self + else + @lst.get(0, 'end') + end + end + + def see(idx) + @lst.see(@lst.index(idx) - 1) + end + + def list_index(idx) + @lst.index(idx) + end +end + + +################################################ +# test +################################################ +if __FILE__ == $0 + v = TkVariable.new + e = TkCombobox.new(:height=>7, :scrollbar=>true, :textvariable=>v, + :startwait=>400, :interval=>200).pack + e.values(%w(aa bb cc dd ee ff gg hh ii jj kk ll mm nn oo pp qq rr ss tt uu)) + #e.see(e.list_index('end') - 2) + e.value = 'cc' + TkFrame.new{|f| + fnt = TkFont.new('Helvetica 10') + TkLabel.new(f, :font=>fnt, :text=>'TkCombobox value :').pack(:side=>:left) + TkLabel.new(f, :font=>fnt, :textvariable=>v).pack(:side=>:left) + }.pack + + TkFrame.new(:relief=>:raised, :borderwidth=>2, + :height=>3).pack(:fill=>:x, :expand=>true, :padx=>5, :pady=>3) + + l = TkAutoScrollbox.new(nil, :relief=>:groove, :borderwidth=>4, + :width=>20).pack(:fill=>:both, :expand=>true) + (0..20).each{|i| l.insert('end', "line #{i}")} + + TkFrame.new(:relief=>:ridge, :borderwidth=>3){ + TkButton.new(self, :text=>'ON', + :command=>proc{l.scrollbar(true)}).pack(:side=>:left) + TkButton.new(self, :text=>'OFF', + :command=>proc{l.scrollbar(false)}).pack(:side=>:right) + pack(:fill=>:x) + } + Tk.mainloop +end |