mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
913 lines
24 KiB
Ruby
913 lines
24 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
|
||
|
|
||
|
# virtical scrollbar
|
||
|
@v_scroll = TkScrollbar.new(@frame, 'highlightthickness'=>@h_l_thick,
|
||
|
'borderwidth'=>@scrbar_border,
|
||
|
'orient'=>'vertical', 'width'=>@scrbar_width)
|
||
|
|
||
|
# horizontal scrollbar
|
||
|
@h_scroll = TkScrollbar.new(@frame, 'highlightthickness'=>@h_l_thick,
|
||
|
'borderwidth'=>@scrbar_border,
|
||
|
'orient'=>'horizontal', '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
|
||
|
@hscr_list << TkScrollbar.new(f, 'orient'=>'horizontal',
|
||
|
'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])
|
||
|
|
||
|
@lbox_list[idx].xscrollcommand proc{|first, last|
|
||
|
@hscr_list[idx].set first, last
|
||
|
}
|
||
|
@hscr_list[idx].command proc{|*args| @lbox_list[idx].xview *args}
|
||
|
|
||
|
# 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
|
||
|
@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} }
|
||
|
|
||
|
# set control procedure for horizoncal scroll
|
||
|
@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
|
||
|
}
|
||
|
|
||
|
# binding for listboxes
|
||
|
@mode = {}
|
||
|
@mode['browse'] = browse_mode_bindtag
|
||
|
@mode['single'] = single_mode_bindtag
|
||
|
@mode['extended'] = extended_mode_bindtag
|
||
|
@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(@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 - [ @mode[@current_mode] ]
|
||
|
l.bindtags(tags.unshift(@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
|