mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 287a34ae0d
			
		
	
	
		287a34ae0d
		
	
	
	
	
		
			
			git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22784 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			940 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			940 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| #
 | |
| # tkmultilistframe.rb : multiple listbox widget on scrollable frame
 | |
| #                       by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
 | |
| #
 | |
| require 'tk'
 | |
| 
 | |
| class TkMultiListFrame < TkListbox
 | |
|   include TkComposite
 | |
| 
 | |
|   #   lbox_height : height of listboxes (pixel)
 | |
|   #   title_info  : array [ [<title_string>,<init_width>], ... ]
 | |
|   #   keys        : hash {<option>=><value>, ... }
 | |
|   def initialize_composite(lbox_height, title_info, keys={})
 | |
|     # argument check
 | |
|     if (! title_info.kind_of? Array) or (title_info.size < 2)
 | |
|       raise
 | |
|     end
 | |
| 
 | |
|     # mode
 | |
|     @keep_minsize = true
 | |
|     @show_each_hscr = true
 | |
|     @show_win_hscr = true
 | |
| 
 | |
|     # init arrays
 | |
|     @base_list  = []
 | |
|     @rel_list   = []
 | |
|     @title_list = []
 | |
|     @title_cmd  = []
 | |
|     @lbox_list  = []
 | |
|     @hscr_list  = []
 | |
| 
 | |
|     # decide total width
 | |
|     @lbox_total = title_info.size
 | |
|     @width_total = 0
 | |
|     title_info.each{|title, width, cmd|
 | |
|       @width_total += width.to_f
 | |
|       @title_cmd << cmd
 | |
|     }
 | |
| 
 | |
|     # rel-table of label=>index
 | |
|     @name_index = {}
 | |
| 
 | |
|     # size definition
 | |
|     @window_width = @width_total
 | |
|     @sash = 5
 | |
|     @scrbar_width = 15
 | |
|     @scrbar_border = 3
 | |
|     @lbox_border = 1
 | |
|     @title_border = 3
 | |
|     @h_l_thick = 0
 | |
| 
 | |
|     # init status
 | |
|     @mode = :title
 | |
| 
 | |
|     # virtical scrollbar
 | |
| =begin
 | |
|     @v_scroll = TkScrollbar.new(@frame, 'highlightthickness'=>@h_l_thick,
 | |
|                                 'borderwidth'=>@scrbar_border,
 | |
|                                 'orient'=>'vertical', 'width'=>@scrbar_width)
 | |
| =end
 | |
|     @v_scroll = TkYScrollbar.new(@frame, 'highlightthickness'=>@h_l_thick,
 | |
|                                  'borderwidth'=>@scrbar_border,
 | |
|                                  'width'=>@scrbar_width)
 | |
| 
 | |
|     # horizontal scrollbar
 | |
| =begin
 | |
|     @h_scroll = TkScrollbar.new(@frame, 'highlightthickness'=>@h_l_thick,
 | |
|                                 'borderwidth'=>@scrbar_border,
 | |
|                                 'orient'=>'horizontal', 'width'=>@scrbar_width)
 | |
| =end
 | |
|     @h_scroll = TkXScrollbar.new(@frame, 'highlightthickness'=>@h_l_thick,
 | |
|                                  'borderwidth'=>@scrbar_border,
 | |
|                                  'width'=>@scrbar_width)
 | |
| 
 | |
|     # create base flames
 | |
|     @c_title = TkCanvas.new(@frame, 'highlightthickness'=>@h_l_thick,
 | |
|                             'width'=>@window_width)
 | |
|     @f_title = TkFrame.new(@c_title, 'width'=>@width_total)
 | |
|     @w_title = TkcWindow.new(@c_title, 0, 0,
 | |
|                              'window'=>@f_title, 'anchor'=>'nw')
 | |
| 
 | |
|     @c_lbox  = TkCanvas.new(@frame, 'highlightthickness'=>@h_l_thick,
 | |
|                             'width'=>@window_width)
 | |
|     @f_lbox  = TkFrame.new(@c_lbox, 'width'=>@width_total)
 | |
|     @w_lbox  = TkcWindow.new(@c_lbox, 0, 0, 'window'=>@f_lbox, 'anchor'=>'nw')
 | |
| 
 | |
|     @c_hscr  = TkCanvas.new(@frame, 'highlightthickness'=>@h_l_thick,
 | |
|                             'width'=>@window_width)
 | |
|     @f_hscr  = TkFrame.new(@c_hscr, 'width'=>@width_total)
 | |
|     @w_hscr  = TkcWindow.new(@c_hscr, 0, 0, 'window'=>@f_hscr, 'anchor'=>'nw')
 | |
| 
 | |
|     # create each listbox
 | |
|     sum = 0.0
 | |
|     @rel_list << sum/@width_total
 | |
|     title_info.each_with_index{|(label, width), idx|
 | |
|       # set relation between label and index
 | |
|       if @name_index.include?(label)
 | |
|         @name_index[label] << idx
 | |
|       else
 | |
|         @name_index[label] = [idx]
 | |
|       end
 | |
| 
 | |
|       # calculate relative positioning
 | |
|       sum += width
 | |
|       @rel_list << sum/@width_total
 | |
| 
 | |
|       # title field
 | |
|       f = TkFrame.new(@f_title, 'width'=>width)
 | |
|       base = [f]
 | |
| 
 | |
|       title = TkLabel.new(f, 'text'=>label, 'borderwidth'=>@title_border,
 | |
|                           'relief'=>'raised', 'highlightthickness'=>@h_l_thick)
 | |
|       title_binding(title, idx)
 | |
|       title.pack('fill'=>'x')
 | |
| 
 | |
|       @title_list << title
 | |
| 
 | |
|       f.place('relx'=>@rel_list[idx], 'y'=>0, 'anchor'=>'nw', 'width'=>1,
 | |
|               'relheight'=>1.0,
 | |
|               'relwidth'=>@rel_list[idx+1] - @rel_list[idx])
 | |
| 
 | |
|       # listbox field
 | |
|       f = TkFrame.new(@f_lbox, 'width'=>width)
 | |
|       base << f
 | |
|       @lbox_list << TkListbox.new(f, 'highlightthickness'=>@h_l_thick,
 | |
|                                   'borderwidth'=>@lbox_border
 | |
|                                   ).pack('fill'=>'both', 'expand'=>true)
 | |
|       f.place('relx'=>@rel_list[idx], 'y'=>0, 'anchor'=>'nw', 'width'=>1,
 | |
|               'relwidth'=>@rel_list[idx+1] - @rel_list[idx], 'relheight'=>1.0)
 | |
| 
 | |
|       # scrollbar field
 | |
|       f = TkFrame.new(@f_hscr, 'width'=>width)
 | |
|       base << f
 | |
| =begin
 | |
|       @hscr_list << TkScrollbar.new(f, 'orient'=>'horizontal',
 | |
|                                     'width'=>@scrbar_width,
 | |
|                                     'borderwidth'=>@scrbar_border,
 | |
|                                     'highlightthickness'=>@h_l_thick
 | |
|                                     ).pack('fill'=>'x', 'anchor'=>'w')
 | |
| =end
 | |
|       @hscr_list << TkXScrollbar.new(f, 'width'=>@scrbar_width,
 | |
|                                      'borderwidth'=>@scrbar_border,
 | |
|                                      'highlightthickness'=>@h_l_thick
 | |
|                                     ).pack('fill'=>'x', 'anchor'=>'w')
 | |
|       f.place('relx'=>@rel_list[idx], 'y'=>0, 'anchor'=>'nw', 'width'=>1,
 | |
|               'relwidth'=>@rel_list[idx+1] - @rel_list[idx])
 | |
| 
 | |
| =begin
 | |
|       @lbox_list[idx].xscrollcommand proc{|first, last|
 | |
|         @hscr_list[idx].set first, last
 | |
|       }
 | |
|       @hscr_list[idx].command proc{|*args| @lbox_list[idx].xview *args}
 | |
| =end
 | |
|       @lbox_list[idx].xscrollbar(@hscr_list[idx])
 | |
| 
 | |
|       # add new base
 | |
|       @base_list << base
 | |
|     }
 | |
| 
 | |
|     # pad
 | |
|     # @f_title_pad = TkFrame.new(@frame)
 | |
|     @f_title_pad = TkFrame.new(@frame, 'relief'=>'raised',
 | |
|                                'borderwidth'=>@title_border,
 | |
|                                'highlightthickness'=>@h_l_thick)
 | |
| 
 | |
|     @f_scr_pad = TkFrame.new(@frame, 'relief'=>'sunken',
 | |
|                              'borderwidth'=>1,
 | |
|                              'highlightthickness'=>@h_l_thick)
 | |
| 
 | |
|     # height check
 | |
|     title_height = 0
 | |
|     @title_list.each{|w|
 | |
|       h = w.winfo_reqheight
 | |
|       title_height = h if title_height < h
 | |
|     }
 | |
| 
 | |
|     hscr_height = 0
 | |
|     @hscr_list.each{|w|
 | |
|       h = w.winfo_reqheight
 | |
|       hscr_height = h if hscr_height < h
 | |
|     }
 | |
| 
 | |
|     @f_title.height title_height
 | |
|     @f_lbox.height lbox_height
 | |
|     @f_hscr.height hscr_height
 | |
| 
 | |
|     # set control procedure for virtical scroll
 | |
| =begin
 | |
|     @lbox_list.each{|lbox|
 | |
|       lbox.yscrollcommand proc{|first, last|
 | |
|         @v_scroll.set first, last
 | |
|       }
 | |
|     }
 | |
|     @v_scroll.command proc{|*args| @lbox_list.each{|lbox| lbox.yview *args} }
 | |
| =end
 | |
|     @v_scroll.assign(*@lbox_list)
 | |
| 
 | |
|     # set control procedure for horizoncal scroll
 | |
| =begin
 | |
|     @c_title.xscrollcommand proc{|first, last|
 | |
|       @h_scroll.set first, last
 | |
|     }
 | |
|     @c_lbox.xscrollcommand proc{|first, last|
 | |
|       @h_scroll.set first, last
 | |
|     }
 | |
|     @c_hscr.xscrollcommand proc{|first, last|
 | |
|       @h_scroll.set first, last
 | |
|     }
 | |
|     @h_scroll.command proc{|*args|
 | |
|       @c_title.xview *args
 | |
|       @c_lbox.xview *args
 | |
|       @c_hscr.xview *args if @show_each_hscr
 | |
|     }
 | |
| =end
 | |
|     @h_scroll.assign(@c_title, @c_lbox, @c_hscr)
 | |
| 
 | |
|     # binding for listboxes
 | |
|     @lbox_mode = {}
 | |
|     @lbox_mode['browse']   = browse_mode_bindtag
 | |
|     @lbox_mode['single']   = single_mode_bindtag
 | |
|     @lbox_mode['extended'] = extended_mode_bindtag
 | |
|     @lbox_mode['multiple'] = multiple_mode_bindtag
 | |
|     @current_mode = 'browse'
 | |
|     @lbox_list.each_with_index{|l, idx|
 | |
|       l.bind('Shift-Key-Left',
 | |
|              proc{|w| focus_shift(w, -1); Tk.callback_break}, '%W')
 | |
|       l.bind('Shift-Key-Right',
 | |
|              proc{|w| focus_shift(w, 1); Tk.callback_break}, '%W')
 | |
| 
 | |
|       l.bind('Button-2', proc{|x, y|
 | |
|                @lbox_mark_x = x
 | |
|                @lbox_list.each{|lbox| lbox.scan_mark(x, y)}
 | |
|              }, '%x %y')
 | |
|       l.bind('B2-Motion', proc{|x, y|
 | |
|                @lbox_list.each{|lbox| lbox.scan_dragto(@lbox_mark_x, y)}
 | |
|                l.scan_dragto(x, y)
 | |
|              }, '%x %y')
 | |
| 
 | |
|       l.bindtags(l.bindtags.unshift(@lbox_mode[@current_mode]))
 | |
|     }
 | |
| 
 | |
|     bbox = @w_title.bbox
 | |
|     @c_title.height(bbox[3])
 | |
|     @c_title.scrollregion(bbox)
 | |
| 
 | |
|     bbox = @w_lbox.bbox
 | |
|     @c_lbox.height(bbox[3])
 | |
|     @c_lbox.scrollregion(bbox)
 | |
| 
 | |
|     if @show_each_hscr
 | |
|       bbox = @w_hscr.bbox
 | |
|       @c_hscr.height(bbox[3])
 | |
|       @c_hscr.scrollregion(bbox)
 | |
|     end
 | |
| 
 | |
|     # alignment
 | |
|     TkGrid.rowconfigure(@frame, 0, 'weight'=>0)
 | |
|     TkGrid.rowconfigure(@frame, 1, 'weight'=>1)
 | |
|     TkGrid.rowconfigure(@frame, 2, 'weight'=>0)
 | |
|     TkGrid.rowconfigure(@frame, 3, 'weight'=>0)
 | |
|     TkGrid.columnconfigure(@frame, 0, 'weight'=>1)
 | |
|     TkGrid.columnconfigure(@frame, 1, 'weight'=>0)
 | |
|     TkGrid.columnconfigure(@frame, 2, 'weight'=>0)
 | |
|     @v_scroll.grid('row'=>1, 'column'=>2, 'sticky'=>'ns')
 | |
|     @c_title.grid('row'=>0, 'column'=>0, 'sticky'=>'news')
 | |
|     @f_title_pad.grid('row'=>0, 'column'=>2, 'sticky'=>'news')
 | |
|     @c_lbox.grid('row'=>1, 'column'=>0, 'sticky'=>'news')
 | |
|     @c_hscr.grid('row'=>2, 'column'=>0, 'sticky'=>'ew') if @show_each_hscr
 | |
|     @h_scroll.grid('row'=>3, 'column'=>0, 'sticky'=>'ew') if @show_win_hscr
 | |
|     @f_scr_pad.grid('row'=>2, 'rowspan'=>2, 'column'=>2, 'sticky'=>'news')
 | |
| 
 | |
|     # binding for 'Configure' event
 | |
|     @c_lbox.bind('Configure',
 | |
|                  proc{|height, width| reconstruct(height, width)},
 | |
|                  '%h %w')
 | |
| 
 | |
|     # set default receiver of method calls
 | |
|     @path = @lbox_list[0].path
 | |
| 
 | |
|     # configure options
 | |
|     keys = {} unless keys
 | |
|     keys = _symbolkey2str(keys)
 | |
| 
 | |
|     # 'mode' option of listboxes
 | |
|     sel_mode = keys.delete('mode')
 | |
|     mode(sel_mode) if sel_mode
 | |
| 
 | |
|     # 'scrollbarwidth' option == 'width' option of scrollbars
 | |
|     width = keys.delete('scrollbarwidth')
 | |
|     scrollbarwidth(width) if width
 | |
| 
 | |
|     # options for listbox titles
 | |
|     title_font = keys.delete('titlefont')
 | |
|     titlefont(title_font) if title_font
 | |
| 
 | |
|     title_fg = keys.delete('titleforeground')
 | |
|     titleforeground(title_fg) if title_fg
 | |
| 
 | |
|     title_bg = keys.delete('titlebackground')
 | |
|     titlebackground(title_bg) if title_bg
 | |
| 
 | |
|     # set receivers for configure methods
 | |
|     delegate('DEFAULT', *@lbox_list)
 | |
|     delegate('activebackground', @v_scroll, @h_scroll, *@hscr_list)
 | |
|     delegate('troughcolor', @v_scroll, @h_scroll, *@hscr_list)
 | |
|     delegate('repeatdelay', @v_scroll, @h_scroll, *@hscr_list)
 | |
|     delegate('repeatinterval', @v_scroll, @h_scroll, *@hscr_list)
 | |
|     delegate('borderwidth', @frame)
 | |
|     delegate('width', @c_lbox, @c_title, @c_hscr)
 | |
|     delegate('relief', @frame)
 | |
| 
 | |
|     # configure
 | |
|     configure(keys) if keys.size > 0
 | |
|   end
 | |
|   private :initialize_composite
 | |
| 
 | |
|   # set 'mode' option of listboxes
 | |
|   def mode(sel_mode)
 | |
|     @lbox_list.each{|l|
 | |
|       tags = l.bindtags
 | |
|       tags = tags - [ @lbox_mode[@current_mode] ]
 | |
|       l.bindtags(tags.unshift(@lbox_mode[sel_mode]))
 | |
|       @current_mode = sel_mode
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   # keep_minsize?
 | |
|   def keep_minsize?
 | |
|     @keep_minsize
 | |
|   end
 | |
|   def keep_minsize(bool)
 | |
|     @keep_minsize = bool
 | |
|   end
 | |
| 
 | |
|   # each hscr
 | |
|   def show_each_hscr
 | |
|     @show_each_hscr = true
 | |
|     @c_hscr.grid('row'=>2, 'column'=>0, 'sticky'=>'ew')
 | |
|   end
 | |
|   def hide_each_hscr
 | |
|     @show_each_hscr = false
 | |
|     @c_hscr.ungrid
 | |
|   end
 | |
| 
 | |
|   # window hscroll
 | |
|   def show_win_hscr
 | |
|     @show_win_hscr = true
 | |
|     @h_scroll.grid('row'=>3, 'column'=>0, 'sticky'=>'ew')
 | |
|   end
 | |
|   def hide_win_hscr
 | |
|     @show_each_hscr = false
 | |
|     @h_scroll.ungrid
 | |
|   end
 | |
| 
 | |
|   # set scrollbar width
 | |
|   def scrollbarwidth(width)
 | |
|     @scrbar_width = width
 | |
|     @v_scroll['width'] = @scrbar_width
 | |
|     @h_scroll['width'] = @scrbar_width
 | |
|     @hscr_list.each{|hscr| hscr['width'] = @scrbar_width}
 | |
|     self
 | |
|   end
 | |
| 
 | |
|   # set scrollbar border
 | |
|   def scrollbarborder(width)
 | |
|     @scrbar_border = width
 | |
|     @v_scroll['border'] = @scrbar_border
 | |
|     @h_scroll['border'] = @scrbar_border
 | |
|     @hscr_list.each{|hscr| hscr['border'] = @scrbar_border}
 | |
|     self
 | |
|   end
 | |
| 
 | |
|   # set listbox borders
 | |
|   def listboxborder(width)
 | |
|     @lbox_border = width
 | |
|     @lbox_list.each{|w| w['border'] = @lbox_border}
 | |
|     self
 | |
|   end
 | |
| 
 | |
|   # set listbox relief
 | |
|   def listboxrelief(relief)
 | |
|     @lbox_list.each{|w| w['relief'] = relief}
 | |
|     self
 | |
|   end
 | |
| 
 | |
|   # set title borders
 | |
|   def titleborder(width)
 | |
|     @title_border = width
 | |
|     @f_title_pad['border'] = @title_border
 | |
|     @title_list.each{|label| label['border'] = @title_border}
 | |
|     self
 | |
|   end
 | |
| 
 | |
|   # set title font
 | |
|   def titlefont(font)
 | |
|     @title_list.each{|label| label['font'] = font}
 | |
|     title_height = 0
 | |
|     @title_list.each{|w|
 | |
|       h = w.winfo_reqheight
 | |
|       title_height = h if title_height < h
 | |
|     }
 | |
|     @f_title.height title_height
 | |
|     bbox = @w_title.bbox
 | |
|     @c_title.height(bbox[3])
 | |
|     @c_title.scrollregion(bbox)
 | |
|     self
 | |
|   end
 | |
| 
 | |
|   # set title foreground color
 | |
|   def titleforeground(fg)
 | |
|     @title_list.each{|label| label['foreground'] = fg}
 | |
|     self
 | |
|   end
 | |
| 
 | |
|   # set title background color
 | |
|   def titlebackground(bg)
 | |
|     @f_title_pad['background'] = bg
 | |
|     @title_list.each{|label| label['background'] = bg}
 | |
|     self
 | |
|   end
 | |
| 
 | |
|   # set title cmds
 | |
|   def titlecommand(idx, cmd=Proc.new)
 | |
|     @title_cmd[idx] = cmd
 | |
|   end
 | |
| 
 | |
|   # call title cmds
 | |
|   def titleinvoke(idx)
 | |
|     @title_cmd[idx].call if @title_cmd[idx]
 | |
|   end
 | |
| 
 | |
|   # get label widgets of listbox titles
 | |
|   def titlelabels(*indices)
 | |
|     @title_list[*indices]
 | |
|   end
 | |
| 
 | |
|   # get listbox widgets
 | |
|   def columns(*indices)
 | |
|     @lbox_list[*indices]
 | |
|   end
 | |
| 
 | |
|   def activate(idx)
 | |
|     @lbox_list.each{|lbox| lbox.activate(idx)}
 | |
|   end
 | |
| 
 | |
|   def bbox(idx)
 | |
|     @lbox_list.collect{|lbox| lbox.bbox(idx)}
 | |
|   end
 | |
| 
 | |
|   def delete(*idx)
 | |
|     @lbox_list.collect{|lbox| lbox.delete(*idx)}
 | |
|   end
 | |
| 
 | |
|   def get(*idx)
 | |
|     if idx.size == 1
 | |
|       @lbox_list.collect{|lbox| lbox.get(*idx)}
 | |
|     else
 | |
|       list = @lbox_list.collect{|lbox| lbox.get(*idx)}
 | |
|       result = []
 | |
|       list[0].each_with_index{|line, index|
 | |
|         result << list.collect{|lines| lines[index]}
 | |
|       }
 | |
|       result
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def _line_array_to_hash(line)
 | |
|     result = {}
 | |
|     @name_index.each_pair{|label, indices|
 | |
|       if indices.size == 1
 | |
|         result[label] = line[indices[0]]
 | |
|       else
 | |
|         result[label] = indices.collect{|index| line[index]}
 | |
|       end
 | |
|     }
 | |
|     result
 | |
|   end
 | |
|   private :_line_array_to_hash
 | |
| 
 | |
|   def get_by_hash(*idx)
 | |
|     get_result = get(*idx)
 | |
|     if idx.size == 1
 | |
|       _line_array_to_hash(get_result)
 | |
|     else
 | |
|       get_result.collect{|line| _line_array_to_hash(line)}
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def insert(idx, *lines)
 | |
|     lbox_ins = []
 | |
|     (0..@lbox_list.size).each{lbox_ins << []}
 | |
| 
 | |
|     lines.each{|line|
 | |
|       if line.kind_of? Hash
 | |
|         array = []
 | |
|         @name_index.each_pair{|label, indices|
 | |
|           if indices.size == 1
 | |
|             array[indices[0]] = line[label]
 | |
|           else
 | |
|             if line[label].kind_of? Array
 | |
|               indices.each_with_index{|index, num|
 | |
|                 array[index] = line[label][num]
 | |
|               }
 | |
|             else
 | |
|               array[indices[0]] = line[label]
 | |
|             end
 | |
|           end
 | |
|         }
 | |
|         line = array
 | |
|       end
 | |
| 
 | |
|       @name_index.each_pair{|label, indices|
 | |
|         if indices.size == 1
 | |
|           lbox_ins[indices[0]] << line[indices[0]]
 | |
|         else
 | |
|           indices.each{|index| lbox_ins[index] << line[index]}
 | |
|         end
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     @lbox_list.each_with_index{|lbox, index|
 | |
|       lbox.insert(idx, *lbox_ins[index]) if lbox_ins[index]
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def selection_anchor(index)
 | |
|     @lbox_list.each{|lbox| lbox.selection_anchor(index)}
 | |
|   end
 | |
| 
 | |
|   def selection_clear(first, last=None)
 | |
|     @lbox_list.each{|lbox| lbox.selection_clear(first, last=None)}
 | |
|   end
 | |
| 
 | |
|   def selection_set(first, last=None)
 | |
|     @lbox_list.each{|lbox| lbox.selection_set(first, last=None)}
 | |
|   end
 | |
| 
 | |
|   ###########################################
 | |
|   private
 | |
| 
 | |
|   def reconstruct(height, width)
 | |
|     if @keep_minsize && width <= @width_total
 | |
|       @f_title.width(@width_total)
 | |
|       @f_lbox.width(@width_total)
 | |
|       @f_hscr.width(@width_total) if @show_each_hscr
 | |
|       @window_width = @width_total
 | |
|     else
 | |
|       @f_title.width(width)
 | |
|       @f_lbox.width(width)
 | |
|       @f_hscr.width(width) if @show_each_hscr
 | |
|       @window_width = width
 | |
|     end
 | |
| 
 | |
|     @f_lbox.height(height)
 | |
| 
 | |
|     @c_title.scrollregion(@w_title.bbox)
 | |
|     @c_lbox.scrollregion(@w_lbox.bbox)
 | |
|     @c_hscr.scrollregion(@w_hscr.bbox) if @show_each_hscr
 | |
| 
 | |
|     (0..(@rel_list.size - 2)).each{|idx|
 | |
|       title, lbox, hscr = @base_list[idx]
 | |
|       title.place('relwidth'=>@rel_list[idx+1] - @rel_list[idx])
 | |
|       lbox.place('relwidth'=>@rel_list[idx+1] - @rel_list[idx],
 | |
|                  'relheight'=>1.0)
 | |
|       hscr.place('relwidth'=>@rel_list[idx+1] - @rel_list[idx])
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def resize(x)
 | |
|     idx = @sel_sash
 | |
|     return if idx == 0
 | |
| 
 | |
|     # adjustment of relative positioning
 | |
|     delta = (x - @x) / @frame_width
 | |
|     if delta < @rel_list[idx-1] - @rel_list[idx] + (2*@sash/@frame_width)
 | |
|       delta = @rel_list[idx-1] - @rel_list[idx] + (2*@sash/@frame_width)
 | |
|     elsif delta > @rel_list[idx+1] - @rel_list[idx] - (2*@sash/@frame_width)
 | |
|       delta = @rel_list[idx+1] - @rel_list[idx] - (2*@sash/@frame_width)
 | |
|     end
 | |
|     @rel_list[idx] += delta
 | |
| 
 | |
|     # adjustment of leftside widget of the sash
 | |
|     title, lbox, hscr = @base_list[idx - 1]
 | |
|     title.place('relwidth'=>@rel_list[idx] - @rel_list[idx-1])
 | |
|     lbox.place('relwidth'=>@rel_list[idx] - @rel_list[idx-1], 'relheight'=>1.0)
 | |
|     hscr.place('relwidth'=>@rel_list[idx] - @rel_list[idx-1])
 | |
| 
 | |
|     # adjustment of rightside widget of the sash
 | |
|     title, lbox, hscr = @base_list[idx]
 | |
|     title.place('relwidth'=>@rel_list[idx+1] - @rel_list[idx],
 | |
|                 'relx'=>@rel_list[idx])
 | |
|     lbox.place('relwidth'=>@rel_list[idx+1] - @rel_list[idx],
 | |
|                'relx'=>@rel_list[idx], 'relheight'=>1.0)
 | |
|     hscr.place('relwidth'=>@rel_list[idx+1] - @rel_list[idx],
 | |
|                'relx'=>@rel_list[idx])
 | |
| 
 | |
|     # update reference position
 | |
|     @x = x
 | |
|   end
 | |
| 
 | |
|   def motion_cb(w, x, idx)
 | |
|     if x <= @sash && idx > 0
 | |
|       w.cursor 'sb_h_double_arrow'
 | |
|       @mode = :sash
 | |
|       @sel_sash = idx
 | |
|     elsif x >= w.winfo_width - @sash && idx < @lbox_total - 1
 | |
|       w.cursor 'sb_h_double_arrow'
 | |
|       @mode = :sash
 | |
|       @sel_sash = idx + 1
 | |
|     else
 | |
|       w.cursor ""
 | |
|       @mode = :title
 | |
|       @sel_sash = 0
 | |
|     end
 | |
|   end
 | |
| 
 | |
|   def title_binding(title, index)
 | |
|     title.bind('Motion', proc{|w, x, idx| motion_cb(w, x, idx.to_i)},
 | |
|                "%W %x #{index}")
 | |
| 
 | |
|     title.bind('Enter', proc{|w, x, idx| motion_cb(w, x, idx.to_i)},
 | |
|                "%W %x #{index}")
 | |
| 
 | |
|     title.bind('Leave', proc{|w| w.cursor ""}, "%W")
 | |
| 
 | |
|     title.bind('Button-1',
 | |
|                proc{|w, x|
 | |
|                  if @mode == :sash
 | |
|                    @x = x
 | |
|                    @frame_width = TkWinfo.width(@f_title).to_f
 | |
|                  else
 | |
|                    title.relief 'sunken'
 | |
|                  end
 | |
|                },
 | |
|                '%W %X')
 | |
| 
 | |
|     title.bind('ButtonRelease-1',
 | |
|                proc{|w, x, idx|
 | |
|                  i = idx.to_i
 | |
|                  if @mode == :title && @title_cmd[i].kind_of?(Proc)
 | |
|                    @title_cmd[i].call
 | |
|                  end
 | |
|                  title.relief 'raised'
 | |
|                  motion_cb(w,x,i)
 | |
|                },
 | |
|                "%W %x #{index}")
 | |
| 
 | |
|     title.bind('B1-Motion', proc{|x| resize(x) if @mode == :sash}, "%X")
 | |
|   end
 | |
| 
 | |
|   #################################
 | |
|   def browse_mode_bindtag
 | |
|     t = TkBindTag.new
 | |
|     t.bind('Button-1',
 | |
|            proc{|w, y| w.focus; select_line(w, w.nearest(y))}, '%W %y')
 | |
|     t.bind('B1-Motion', proc{|w, y| select_line(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Shift-Button-1',
 | |
|            proc{|w, y| active_line(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Key-Up', proc{|w| select_shift(w, -1)}, '%W')
 | |
|     t.bind('Key-Down', proc{|w| select_shift(w, 1)}, '%W')
 | |
| 
 | |
|     t.bind('Control-Home', proc{|w| select_line(w, 0)}, '%W')
 | |
|     t.bind('Control-End', proc{|w| select_line(w, 'end')}, '%W')
 | |
| 
 | |
|     t.bind('space', proc{|w| select_line(w, w.index('active').to_i)}, '%W')
 | |
|     t.bind('Select', proc{|w| select_line(w, w.index('active').to_i)}, '%W')
 | |
|     t.bind('Control-slash',
 | |
|            proc{|w| select_line(w, w.index('active').to_i)}, '%W')
 | |
| 
 | |
|     t
 | |
|   end
 | |
| 
 | |
|   ########################
 | |
|   def single_mode_bindtag
 | |
|     t = TkBindTag.new
 | |
|     t.bind('Button-1',
 | |
|            proc{|w, y| w.focus; select_only(w, w.nearest(y))}, '%W %y')
 | |
|     t.bind('ButtonRelease-1',
 | |
|            proc{|w, y| active_line(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Shift-Button-1',
 | |
|            proc{|w, y| active_line(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Key-Up', proc{|w| select_shift(w, -1)}, '%W')
 | |
|     t.bind('Key-Down', proc{|w| select_shift(w, 1)}, '%W')
 | |
| 
 | |
|     t.bind('Control-Home', proc{|w| select_line(w, 0)}, '%W')
 | |
|     t.bind('Control-End', proc{|w| select_line(w, 'end')}, '%W')
 | |
| 
 | |
|     t.bind('space', proc{|w| select_line(w, w.index('active').to_i)}, '%W')
 | |
|     t.bind('Select', proc{|w| select_line(w, w.index('active').to_i)}, '%W')
 | |
|     t.bind('Control-slash',
 | |
|            proc{|w| select_line(w, w.index('active').to_i)}, '%W')
 | |
|     t.bind('Control-backslash',
 | |
|            proc{@lbox_list.each{|l| l.selection_clear(0, 'end')}})
 | |
| 
 | |
|     t
 | |
|   end
 | |
| 
 | |
|   ########################
 | |
|   def extended_mode_bindtag
 | |
|     t = TkBindTag.new
 | |
|     t.bind('Button-1',
 | |
|            proc{|w, y| w.focus; select_only(w, w.nearest(y))}, '%W %y')
 | |
|     t.bind('B1-Motion', proc{|w, y| select_range(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('ButtonRelease-1',
 | |
|            proc{|w, y| active_line(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Shift-Button-1',
 | |
|            proc{|w, y| select_range(w, w.nearest(y))}, '%W %y')
 | |
|     t.bind('Shift-B1-Motion',
 | |
|            proc{|w, y| select_range(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Control-Button-1',
 | |
|            proc{|w, y| select_toggle(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Control-B1-Motion',
 | |
|            proc{|w, y| select_drag(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Key-Up', proc{|w| active_shift(w, -1)}, '%W')
 | |
|     t.bind('Key-Down', proc{|w| active_shift(w, 1)}, '%W')
 | |
| 
 | |
|     t.bind('Shift-Up', proc{|w| select_expand(w, -1)}, '%W')
 | |
|     t.bind('Shift-Down', proc{|w| select_expand(w, 1)}, '%W')
 | |
| 
 | |
|     t.bind('Control-Home', proc{|w| select_line2(w, 0)}, '%W')
 | |
|     t.bind('Control-End', proc{|w| select_line2(w, 'end')}, '%W')
 | |
| 
 | |
|     t.bind('Control-Shift-Home', proc{|w| select_range(w, 0)}, '%W')
 | |
|     t.bind('Control-Shift-End', proc{|w| select_range(w, 'end')}, '%W')
 | |
| 
 | |
|     t.bind('space', proc{|w| select_active(w)}, '%W')
 | |
|     t.bind('Select', proc{|w| select_active(w)}, '%W')
 | |
|     t.bind('Control-slash', proc{|w| select_all}, '%W')
 | |
|     t.bind('Control-backslash', proc{|w| clear_all}, '%W')
 | |
| 
 | |
|     t
 | |
|   end
 | |
| 
 | |
|   ########################
 | |
|   def multiple_mode_bindtag
 | |
|     t = TkBindTag.new
 | |
|     t.bind('Button-1',
 | |
|            proc{|w, y| w.focus; select_line3(w, w.nearest(y))}, '%W %y')
 | |
|     t.bind('ButtonRelease-1',
 | |
|            proc{|w, y| active_line(w, w.nearest(y))}, '%W %y')
 | |
| 
 | |
|     t.bind('Key-Up', proc{|w| active_shift(w, -1)}, '%W')
 | |
|     t.bind('Key-Down', proc{|w| active_shift(w, 1)}, '%W')
 | |
| 
 | |
|     t.bind('Control-Home', proc{|w| select_line2(w, 0)}, '%W')
 | |
|     t.bind('Control-End', proc{|w| select_line2(w, 'end')}, '%W')
 | |
| 
 | |
|     t.bind('Control-Shift-Home', proc{|w| active_line(w, 0)}, '%W')
 | |
|     t.bind('Control-Shift-End', proc{|w| active_line(w, 'end')}, '%W')
 | |
| 
 | |
|     t.bind('space', proc{|w| select_active(w)}, '%W')
 | |
|     t.bind('Select', proc{|w| select_active(w)}, '%W')
 | |
|     t.bind('Control-slash', proc{|w| select_all}, '%W')
 | |
|     t.bind('Control-backslash', proc{|w| clear_all}, '%W')
 | |
| 
 | |
|     t
 | |
|   end
 | |
| 
 | |
|   ########################
 | |
|   def active_line(w, idx)
 | |
|     @lbox_list.each{|l| l.activate(idx)}
 | |
|   end
 | |
| 
 | |
|   def select_only(w, idx)
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_clear(0, 'end')
 | |
|       l.selection_anchor(idx)
 | |
|       l.selection_set('anchor')
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_range(w, idx)
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_clear(0, 'end')
 | |
|       l.selection_set('anchor', idx)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_toggle(w, idx)
 | |
|     st = w.selection_includes(idx)
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_anchor(idx)
 | |
|       if st == 1
 | |
|         l.selection_clear(idx)
 | |
|       else
 | |
|         l.selection_set(idx)
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_drag(w, idx)
 | |
|     st = w.selection_includes('anchor')
 | |
|     @lbox_list.each{|l|
 | |
|       if st == 1
 | |
|         l.selection_set('anchor', idx)
 | |
|       else
 | |
|         l.selection_clear('anchor', idx)
 | |
|       end
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_line(w, idx)
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_clear(0, 'end')
 | |
|       l.activate(idx)
 | |
|       l.selection_anchor(idx)
 | |
|       l.selection_set('anchor')
 | |
|     }
 | |
|     w.selection_set('anchor')
 | |
|   end
 | |
| 
 | |
|   def select_line2(w, idx)
 | |
|     @lbox_list.each{|l|
 | |
|       l.activate(idx)
 | |
|       l.selection_anchor(idx)
 | |
|       l.selection_set('anchor')
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_line3(w, idx)
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_set(idx)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_active(w)
 | |
|     idx = l.activate(idx)
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_set(idx)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_expand(w, dir)
 | |
|     idx = w.index('active').to_i + dir
 | |
|     if idx < 0
 | |
|       idx = 0
 | |
|     elsif idx >= w.size
 | |
|       idx = w.size - 1
 | |
|     end
 | |
|     @lbox_list.each{|l|
 | |
|       l.activate(idx)
 | |
|       l.selection_set(idx)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def active_shift(w, dir)
 | |
|     idx = w.index('active').to_i + dir
 | |
|     if idx < 0
 | |
|       idx = 0
 | |
|     elsif idx >= w.size
 | |
|       idx = w.size - 1
 | |
|     end
 | |
|     @lbox_list.each{|l|
 | |
|       l.activate(idx)
 | |
|       l.selection_anchor(idx)
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_shift(w, dir)
 | |
|     idx = w.index('anchor').to_i + dir
 | |
|     if idx < 0
 | |
|       idx = 0
 | |
|     elsif idx >= w.size
 | |
|       idx = w.size - 1
 | |
|     end
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_clear(0, 'end')
 | |
|       l.activate(idx)
 | |
|       l.selection_anchor(idx)
 | |
|       l.selection_set('anchor')
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def select_all
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_set(0, 'end')
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def clear_all
 | |
|     @lbox_list.each{|l|
 | |
|       l.selection_clear(0, 'end')
 | |
|     }
 | |
|   end
 | |
| 
 | |
|   def focus_shift(w, dir)
 | |
|     idx = @lbox_list.index(w) + dir
 | |
|     return if idx < 0
 | |
|     return if idx >= @lbox_list.size
 | |
|     @lbox_list[idx].focus
 | |
|   end
 | |
|   ########################
 | |
| end
 | |
| 
 | |
| ################################################
 | |
| # test
 | |
| ################################################
 | |
| if __FILE__ == $0
 | |
|   l = TkMultiListFrame.new(nil, 200,
 | |
|                            [ ['L1', 200, proc{p 'click L1'}],
 | |
|                              ['L2', 100],
 | |
|                              ['L3', 200] ],
 | |
|                            'width'=>350,
 | |
|                            #'titleforeground'=>'yellow',
 | |
|                            'titleforeground'=>'white',
 | |
|                            #'titlebackground'=>'navy',
 | |
|                            'titlebackground'=>'blue',
 | |
|                            'titlefont'=>'courier'
 | |
|                            ).pack('fill'=>'both', 'expand'=>true)
 | |
|   l.insert('end', [1,2,3])
 | |
|   l.insert('end', [4,5,6])
 | |
|   l.insert('end', [4,5,6], [4,5,6])
 | |
|   l.insert('end', ['aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
 | |
|                    'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb',
 | |
|                    'cccccccccccccccccccccccccccccccccccccccccccccccccccc'])
 | |
|   l.insert('end', [1,2,3])
 | |
|   l.insert('end', [4,5,6], [4,5,6])
 | |
|   l.insert('end', ['aaaaaaaaaaaaaaa','bbbbbbbbbbbbbb','ccccccccccccccccc'])
 | |
|   l.insert('end', [1,2,3])
 | |
|   l.insert('end', [4,5,6], [4,5,6])
 | |
|   l.insert('end', ['aaaaaaaaaaaaaaa','bbbbbbbbbbbbbb','ccccccccccccccccc'])
 | |
|   l.insert('end', [1,2,3])
 | |
|   l.insert('end', [4,5,6], [4,5,6])
 | |
|   l.insert('end', ['aaaaaaaaaaaaaaa','bbbbbbbbbbbbbb','ccccccccccccccccc'])
 | |
|   l.insert('end', [1,2,3])
 | |
|   l.insert('end', [4,5,6], [4,5,6])
 | |
|   p l.columns(1)
 | |
|   p l.columns(1..3)
 | |
|   p l.columns(1,2)
 | |
|   Tk.mainloop
 | |
| end
 |