mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
287a34ae0d
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@22784 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
983 lines
28 KiB
Ruby
983 lines
28 KiB
Ruby
#!/usr/bin/env ruby
|
|
#
|
|
# Demo for 'tile' package.
|
|
#
|
|
require 'tk'
|
|
|
|
demodir = File.dirname($0)
|
|
themesdir = File.join(demodir, 'themes')
|
|
Tk::AUTO_PATH.lappend('.', demodir, themesdir)
|
|
|
|
Dir.foreach(themesdir){|name|
|
|
next if name == '.' || name == '..'
|
|
dir = File.join(themesdir, name)
|
|
Tk::AUTO_PATH.lappend(dir) if File.directory?(dir)
|
|
}
|
|
|
|
require 'tkextlib/tile'
|
|
|
|
def version?(ver)
|
|
TkPackage.vcompare(Tk::Tile.package_version, ver) >= 0
|
|
end
|
|
|
|
# define Tcl/Tk procedures for compatibility
|
|
Tk::Tile.__define_LoadImages_proc_for_compatibility__!
|
|
Tk::Tile::Style.__define_wrapper_proc_for_compatibility__!
|
|
|
|
unless Tk::Tile::Style.theme_names.include?('step')
|
|
Tk::Tile::Style.theme_create('step')
|
|
end
|
|
|
|
Tk.load_tclscript(File.join(demodir, 'toolbutton.tcl'))
|
|
Tk.load_tclscript(File.join(demodir, 'repeater.tcl'))
|
|
|
|
# This forces an update of the available packages list. It's required
|
|
# for package names to find the themes in demos/themes/*.tcl
|
|
## Tk.tk_call(TkPackage.unknown_proc, 'Tcl', TkPackage.provide('Tcl'))
|
|
## --> This doesn't work.
|
|
## Because, unknown_proc may be "command + some arguments".
|
|
Tk.ip_eval("#{TkPackage.unknown_proc} Tcl #{TkPackage.provide('Tcl')}")
|
|
|
|
TkRoot.new{
|
|
title 'Tile demo'
|
|
iconname 'Tile demo'
|
|
}
|
|
|
|
# The descriptive names of the builtin themes.
|
|
$THEMELIST = [
|
|
['default', 'Default'],
|
|
['classic', 'Classic'],
|
|
['alt', 'Revitalized'],
|
|
['winnative', 'Windows native'],
|
|
['xpnative', 'XP Native'],
|
|
['aqua', 'Aqua'],
|
|
]
|
|
|
|
$V = TkVariable.new_hash(:THEME => 'default',
|
|
:COMPOUND => 'top',
|
|
:CONSOLE => false,
|
|
:MENURADIO1 => 'One',
|
|
:MENUCHECK1 => true,
|
|
:PBMODE => 'determinate',
|
|
:SELECTED => true,
|
|
:CHOICE => 2)
|
|
|
|
# Add in any available loadable themes.
|
|
TkPackage.names.find_all{|n| n =~ /^(tile|ttk)::theme::/}.each{|pkg|
|
|
name = pkg.split('::')[-1]
|
|
unless $THEMELIST.assoc(name)
|
|
$THEMELIST << [name, Tk.tk_call('string', 'totitle', name)]
|
|
end
|
|
}
|
|
|
|
# Add theme definition written by ruby
|
|
$RUBY_THEMELIST = []
|
|
begin
|
|
load(File.join(demodir, 'themes', 'kroc.rb'), true)
|
|
rescue => e
|
|
raise e
|
|
$RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', false]
|
|
else
|
|
$RUBY_THEMELIST << ['kroc-rb', 'Kroc (by Ruby)', true]
|
|
end
|
|
|
|
def makeThemeControl(parent)
|
|
c = Tk::Tile::Labelframe.new(parent, :text=>'Theme')
|
|
$THEMELIST.each{|theme, name|
|
|
b = Tk::Tile::Radiobutton.new(c, :text=>name, :value=>theme,
|
|
:variable=>$V.ref(:THEME),
|
|
:command=>proc{setTheme(theme)})
|
|
b.grid(:sticky=>:ew)
|
|
unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/})
|
|
b.ttk_state(:disabled)
|
|
end
|
|
}
|
|
$RUBY_THEMELIST.each{|theme, name, available|
|
|
b = Tk::Tile::Radiobutton.new(c, :text=>name, :value=>theme,
|
|
:variable=>$V.ref(:THEME),
|
|
:command=>proc{setTheme(theme)})
|
|
b.grid(:sticky=>:ew)
|
|
b.ttk_state(:disabled) unless available
|
|
}
|
|
c
|
|
end
|
|
|
|
def makeThemeMenu(parent)
|
|
m = TkMenu.new(parent)
|
|
$THEMELIST.each{|theme, name|
|
|
m.add(:radiobutton, :label=>name, :variable=>$V.ref(:THEME),
|
|
:value=>theme, :command=>proc{setTheme(theme)})
|
|
unless (TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/})
|
|
m.entryconfigure(:end, :state=>:disabled)
|
|
end
|
|
}
|
|
$RUBY_THEMELIST.each{|theme, name, available|
|
|
m.add(:radiobutton, :label=>name, :variable=>$V.ref(:THEME),
|
|
:value=>theme, :command=>proc{setTheme(theme)})
|
|
m.entryconfigure(:end, :state=>:disabled) unless available
|
|
}
|
|
m
|
|
end
|
|
|
|
def setTheme(theme)
|
|
if (pkg = TkPackage.names.find{|n| n =~ /(tile|ttk)::theme::#{theme}/})
|
|
unless Tk::Tile::Style.theme_names.find{|n| n == theme}
|
|
TkPackage.require(pkg)
|
|
end
|
|
end
|
|
Tk::Tile::Style.theme_use(theme)
|
|
end
|
|
|
|
#
|
|
# Load icons...
|
|
#
|
|
$BUTTONS = ['open', 'new', 'save']
|
|
$CHECKBOXES = ['bold', 'italic']
|
|
$ICON = {}
|
|
|
|
def loadIcons(file)
|
|
Tk.load_tclscript(file)
|
|
img_data = TkVarAccess.new('ImgData')
|
|
img_data.keys.each{|icon|
|
|
$ICON[icon] = TkPhotoImage.new(:data=>img_data[icon])
|
|
}
|
|
end
|
|
|
|
loadIcons(File.join(demodir, 'iconlib.tcl'))
|
|
|
|
#
|
|
# Utilities:
|
|
#
|
|
def foreachWidget(wins, cmd)
|
|
wins.each{|w|
|
|
cmd.call(w)
|
|
foreachWidget(w.winfo_children, cmd)
|
|
}
|
|
end
|
|
|
|
# sbstub
|
|
# Used as the :command option for a scrollbar,
|
|
# updates the scrollbar's position.
|
|
#
|
|
def sbstub(sb, cmd, num, units = 'units')
|
|
num = TkComm.number(num)
|
|
case cmd.to_s
|
|
when 'moveto'
|
|
sb.set(num, num+0.5)
|
|
|
|
when 'scroll'
|
|
if units.to_s == 'pages'
|
|
delta = 0.2
|
|
else
|
|
delta = 0.05
|
|
end
|
|
current = sb.get
|
|
sb.set(current[0] + delta * num, current[1] + delta * num)
|
|
end
|
|
end
|
|
|
|
# ... for debugging:
|
|
TkBindTag::ALL.bind('ButtonPress-3', proc{|w| $W = w}, '%W')
|
|
TkBindTag::ALL.bind('Control-ButtonPress-3', proc{|w| w.set_focus}, '%W')
|
|
|
|
def showHelp()
|
|
Tk.messageBox(:message=>'No help yet...')
|
|
end
|
|
|
|
#
|
|
# See toolbutton.tcl.
|
|
TkOption.add('*Toolbar.relief', :groove)
|
|
TkOption.add('*Toolbar.borderWidth', 2)
|
|
|
|
TkOption.add('*Toolbar.Button.Pad', 2)
|
|
|
|
$ROOT = Tk.root
|
|
$BASE = $ROOT
|
|
Tk.destroy(*($ROOT.winfo_children))
|
|
|
|
$TOOLBARS = []
|
|
|
|
#
|
|
# Toolbar button standard vs. tile comparison:
|
|
#
|
|
def makeToolbars
|
|
#
|
|
# Tile toolbar:
|
|
#
|
|
tb = Tk::Tile::Frame.new($BASE, :class=>'Toolbar')
|
|
$TOOLBARS << tb
|
|
i = 0
|
|
$BUTTONS.each{|icon|
|
|
i += 1
|
|
Tk::Tile::Button.new(tb, :text=>icon, :image=>$ICON[icon],
|
|
:compound=>$V[:COMPOUND],
|
|
:style=>:Toolbutton).grid(:row=>0, :column=>i,
|
|
:sticky=>:news)
|
|
}
|
|
$CHECKBOXES.each{|icon|
|
|
i += 1
|
|
Tk::Tile::Checkbutton.new(tb, :text=>icon, :image=>$ICON[icon],
|
|
:variable=>$V.ref(icon),
|
|
:compound=>$V[:COMPOUND],
|
|
:style=>:Toolbutton).grid(:row=>0, :column=>i,
|
|
:sticky=>:news)
|
|
}
|
|
|
|
mb = Tk::Tile::Menubutton.new(tb, :text=>'toolbar', :image=>$ICON['file'],
|
|
:compound=>$V[:COMPOUND])
|
|
mb.configure(:menu=>makeCompoundMenu(mb))
|
|
i += 1
|
|
mb.grid(:row=>0, :column=>i, :sticky=>:news)
|
|
|
|
i += 1
|
|
tb.grid_columnconfigure(i, :weight=>1)
|
|
|
|
#
|
|
# Standard toolbar:
|
|
#
|
|
tb = TkFrame.new($BASE, :class=>'Toolbar')
|
|
$TOOLBARS << tb
|
|
i = 0
|
|
$BUTTONS.each{|icon|
|
|
i += 1
|
|
TkButton.new(tb, :text=>icon, :image=>$ICON[icon],
|
|
:compound=>$V[:COMPOUND], :relief=>:flat,
|
|
:overrelief=>:raised).grid(:row=>0, :column=>i,
|
|
:sticky=>:news)
|
|
}
|
|
$CHECKBOXES.each{|icon|
|
|
i += 1
|
|
TkCheckbutton.new(tb, :text=>icon, :image=>$ICON[icon],
|
|
:variable=>$V.ref(icon), :compound=>$V[:COMPOUND],
|
|
:indicatoron=>false, :selectcolor=>'', :relief=>:flat,
|
|
:overrelief=>:raised).grid(:row=>0, :column=>i,
|
|
:sticky=>:news)
|
|
}
|
|
|
|
mb = TkMenubutton.new(tb, :text=>'toolbar', :image=>$ICON['file'],
|
|
:compound=>$V[:COMPOUND])
|
|
mb.configure(:menu=>makeCompoundMenu(mb))
|
|
i += 1
|
|
mb.grid(:row=>0, :column=>i, :sticky=>:news)
|
|
|
|
i += 1
|
|
tb.grid_columnconfigure(i, :weight=>1)
|
|
end
|
|
|
|
#
|
|
# Toolbar :compound control:
|
|
#
|
|
def makeCompoundMenu(mb)
|
|
menu = TkMenu.new(mb)
|
|
%w(text image none top bottom left right center).each{|str|
|
|
menu.add(:radiobutton, :label=>Tk.tk_call('string', 'totitle', str),
|
|
:variable=>$V.ref(:COMPOUND), :value=>str,
|
|
:command=>proc{ changeToolbars() })
|
|
}
|
|
menu
|
|
end
|
|
|
|
makeToolbars()
|
|
|
|
## CONTROLS
|
|
control = Tk::Tile::Frame.new($BASE)
|
|
|
|
#
|
|
# Overall theme control:
|
|
#
|
|
makeThemeControl(control).grid(:sticky=>:news, :padx=>6, :ipadx=>6)
|
|
control.grid_rowconfigure(99, :weight=>1)
|
|
|
|
def changeToolbars
|
|
foreachWidget($TOOLBARS,
|
|
proc{|w|
|
|
begin
|
|
w.compound($V[:COMPOUND])
|
|
rescue
|
|
end
|
|
})
|
|
end
|
|
|
|
def scrolledWidget(parent, klass, themed, *args)
|
|
if themed
|
|
f = Tk::Tile::Frame.new(parent)
|
|
t = klass.new(f, *args)
|
|
vs = Tk::Tile::Scrollbar.new(f)
|
|
hs = Tk::Tile::Scrollbar.new(f)
|
|
else
|
|
f = TkFrame.new(parent)
|
|
t = klass.new(f, *args)
|
|
vs = TkScrollbar.new(f)
|
|
hs = TkScrollbar.new(f)
|
|
end
|
|
t.yscrollbar(vs)
|
|
t.xscrollbar(hs)
|
|
|
|
TkGrid.configure(t, vs, :sticky=>:news)
|
|
TkGrid.configure(hs, 'x', :sticky=>:news)
|
|
TkGrid.rowconfigure(f, 0, :weight=>1)
|
|
TkGrid.columnconfigure(f, 0, :weight=>1)
|
|
|
|
[f, t]
|
|
end
|
|
|
|
#
|
|
# Notebook demonstration:
|
|
#
|
|
def makeNotebook
|
|
nb = Tk::Tile::Notebook.new($BASE, :padding=>6)
|
|
nb.enable_traversal
|
|
client = Tk::Tile::Frame.new(nb)
|
|
nb.add(client, :text=>'Demo', :underline=>0)
|
|
nb.select(client)
|
|
|
|
scales = Tk::Tile::Frame.new(nb)
|
|
nb.add(scales, :text=>'Scales')
|
|
combo = Tk::Tile::Frame.new(nb)
|
|
nb.add(combo, :text=>'Combobox', :underline=>7)
|
|
tree = Tk::Tile::Frame.new(nb)
|
|
nb.add(tree, :text=>'Tree')
|
|
others = Tk::Tile::Frame.new(nb)
|
|
nb.add(others, :text=>'Others', :underline=>4)
|
|
|
|
[nb, client, scales, combo, tree, others]
|
|
end
|
|
|
|
nb, client, scales, combo, tree, others = makeNotebook()
|
|
|
|
#
|
|
# Side-by side check, radio, and menu button comparison:
|
|
#
|
|
def fillMenu(menu)
|
|
%w(above below left right flush).each{|dir|
|
|
menu.add(:command, :label=>Tk.tk_call('string', 'totitle', dir),
|
|
:command=>proc{ menu.winfo_parent.direction(dir) })
|
|
}
|
|
menu.add(:cascade, :label=>'Submenu', :menu=>(submenu = TkMenu.new(menu)))
|
|
submenu.add(:command, :label=>'Subcommand 1')
|
|
submenu.add(:command, :label=>'Subcommand 2')
|
|
submenu.add(:command, :label=>'Subcommand 3')
|
|
|
|
menu.add(:separator)
|
|
menu.add(:command, :label=>'Quit', :command=>proc{Tk.root.destroy})
|
|
end
|
|
|
|
l = Tk::Tile::Labelframe.new(client, :text=>'Themed', :padding=>6)
|
|
r = TkLabelframe.new(client, :text=>'Standard', :padx=>6, :pady=>6)
|
|
|
|
## Styled frame
|
|
cb = Tk::Tile::Checkbutton.new(l, :text=>'Checkbutton',
|
|
:variable=>$V.ref(:SELECTED), :underline=>2)
|
|
rb1 = Tk::Tile::Radiobutton.new(l, :text=>'One', :variable=>$V.ref(:CHOICE),
|
|
:value=>1, :underline=>0)
|
|
rb2 = Tk::Tile::Radiobutton.new(l, :text=>'Two', :variable=>$V.ref(:CHOICE),
|
|
:value=>2)
|
|
rb3 = Tk::Tile::Radiobutton.new(l, :text=>'Three',
|
|
:variable=>$V.ref(:CHOICE),
|
|
:value=>3, :underline=>0)
|
|
btn = Tk::Tile::Button.new(l, :text=>'Button', :underline=>0)
|
|
|
|
mb = Tk::Tile::Menubutton.new(l, :text=>'Menubutton', :underline=>2)
|
|
m = TkMenu.new(mb)
|
|
mb.menu(m)
|
|
fillMenu(m)
|
|
|
|
$entryText = TkVariable.new('Entry widget')
|
|
e = Tk::Tile::Entry.new(l, :textvariable=>$entryText)
|
|
e.selection_range(6, :end)
|
|
|
|
ltext_f, ltext = scrolledWidget(l, TkText, true,
|
|
:width=>12, :height=>5, :wrap=>:none)
|
|
# NOTE TO MAINTAINERS:
|
|
# The checkbuttons are -sticky ew / -expand x on purpose:
|
|
# it demonstrates one of the differences between TCheckbuttons
|
|
# and standard checkbuttons.
|
|
#
|
|
Tk.grid(cb, :sticky=>:ew)
|
|
Tk.grid(rb1, :sticky=>:ew)
|
|
Tk.grid(rb2, :sticky=>:ew)
|
|
Tk.grid(rb3, :sticky=>:ew)
|
|
Tk.grid(btn, :sticky=>:ew, :padx=>2, :pady=>2)
|
|
Tk.grid(mb, :sticky=>:ew, :padx=>2, :pady=>2)
|
|
Tk.grid(e, :sticky=>:ew, :padx=>2, :pady=>2)
|
|
Tk.grid(ltext_f, :sticky=>:news)
|
|
|
|
TkGrid.columnconfigure(l, 0, :weight=>1)
|
|
TkGrid.rowconfigure(l, 7, :weight=>1) # text widget (grid is a PITA)
|
|
|
|
## Orig frame
|
|
cb = TkCheckbutton.new(r, :text=>'Checkbutton', :variable=>$V.ref(:SELECTED))
|
|
rb1 = TkRadiobutton.new(r, :text=>'One',
|
|
:variable=>$V.ref(:CHOICE), :value=>1)
|
|
rb2 = TkRadiobutton.new(r, :text=>'Two', :variable=>$V.ref(:CHOICE),
|
|
:value=>2, :underline=>1)
|
|
rb3 = TkRadiobutton.new(r, :text=>'Three',
|
|
:variable=>$V.ref(:CHOICE), :value=>3)
|
|
btn = TkButton.new(r, :text=>'Button')
|
|
|
|
mb = TkMenubutton.new(r, :text=>'Menubutton', :underline=>3, :takefocus=>true)
|
|
m = TkMenu.new(mb)
|
|
mb.menu(m)
|
|
$V[:rmbIndicatoron] = mb.indicatoron
|
|
m.add(:checkbutton, :label=>'Indicator?', #'
|
|
:variable=>$V.ref(:rmbIndicatoron),
|
|
:command=>proc{mb.indicatoron($V[:rmbIndicatoron])})
|
|
m.add(:separator)
|
|
fillMenu(m)
|
|
|
|
e = TkEntry.new(r, :textvariable=>$entryText)
|
|
|
|
rtext_f, rtext = scrolledWidget(r, TkText, false,
|
|
:width=>12, :height=>5, :wrap=>:none)
|
|
|
|
Tk.grid(cb, :sticky=>:ew)
|
|
Tk.grid(rb1, :sticky=>:ew)
|
|
Tk.grid(rb2, :sticky=>:ew)
|
|
Tk.grid(rb3, :sticky=>:ew)
|
|
Tk.grid(btn, :sticky=>:ew, :padx=>2, :pady=>2)
|
|
Tk.grid(mb, :sticky=>:ew, :padx=>2, :pady=>2)
|
|
Tk.grid(e, :sticky=>:ew, :padx=>2, :pady=>2)
|
|
Tk.grid(rtext_f, :sticky=>:news)
|
|
|
|
TkGrid.columnconfigure(l, 0, :weight=>1)
|
|
TkGrid.rowconfigure(l, 7, :weight=>1) # text widget (grid is a PITA)
|
|
|
|
Tk.grid(l, r, :sticky=>:news, :padx=>6, :pady=>6)
|
|
TkGrid.rowconfigure(client, 0, :weight=>1)
|
|
TkGrid.columnconfigure(client, [0, 1], :weight=>1)
|
|
|
|
#
|
|
# Add some text to the text boxes:
|
|
#
|
|
msgs = [
|
|
"The cat crept into the crypt, crapped and crept out again",
|
|
"Peter Piper picked a peck of pickled peppers",
|
|
"How much wood would a woodchuck chuck if a woodchuck could chuck wood",
|
|
"He thrusts his fists against the posts and still insists he sees the ghosts",
|
|
"Who put the bomb in the bom-b-bom-b-bom,",
|
|
"Is this your sister's sixth zither, sir?",
|
|
"Who put the ram in the ramalamadingdong?",
|
|
"I am not the pheasant plucker, I'm the pheasant plucker's mate."
|
|
]
|
|
|
|
nmsgs = msgs.size
|
|
(0...50).each{|n|
|
|
msg = msgs[n % nmsgs]
|
|
ltext.insert(:end, "#{n}: #{msg}\n")
|
|
rtext.insert(:end, "#{n}: #{msg}\n")
|
|
}
|
|
#
|
|
# Scales and sliders pane:
|
|
#
|
|
l = Tk::Tile::Labelframe.new(scales, :text=>'Themed', :padding=>6)
|
|
r = TkLabelframe.new(scales, :text=>'Standard', :padx=>6, :pady=>6)
|
|
|
|
if version?('0.6')
|
|
|
|
# thremed frame
|
|
scale = Tk::Tile::Scale.new(l, :orient=>:horizontal, :from=>0, :to=>100,
|
|
:variable=>$V.ref(:SCALE))
|
|
vscale = Tk::Tile::Scale.new(l, :orient=>:vertical, :from=>0, :to=>100,
|
|
:variable=>$V.ref(:VSCALE))
|
|
progress = Tk::Tile::Progressbar.new(l, :orient=>:horizontal, :maximum=>100)
|
|
vprogress = Tk::Tile::Progressbar.new(l, :orient=>:vertical, :maximum=>100)
|
|
|
|
if true
|
|
def progress.inverted(w, value)
|
|
if w.mode == 'indeterminate'
|
|
w.value(value)
|
|
else
|
|
w.value(w.maximum - value)
|
|
end
|
|
end
|
|
scale.command {|value| progress.value(value)}
|
|
vscale.command {|value| progress.inverted(vprogress, value) }
|
|
else
|
|
# This would also work, but the Tk scale widgets
|
|
# in the right hand pane cause some interference when
|
|
# in autoincrement/indeterminate mode.
|
|
#
|
|
progress.variable $V.ref(:SCALE)
|
|
vprogress.variable $V.ref(:VSCALE)
|
|
end
|
|
|
|
scale.set(50)
|
|
vscale.set(50)
|
|
|
|
lmode = Tk::Tile::Label.new(l, :text=>'Progress bar mode')
|
|
pbmode0 = Tk::Tile::Radiobutton.new(l, :variable=>$V.ref(:PBMODE),
|
|
:text=>'determinate', :value=>'determinate',
|
|
:command=>proc{pbMode(progress, vprogress)})
|
|
pbmode1 = Tk::Tile::Radiobutton.new(l, :variable=>$V.ref(:PBMODE),
|
|
:text=>'indeterminate', :value=>'indeterminate',
|
|
:command=>proc{pbMode(progress, vprogress)})
|
|
def pbMode(progress, vprogress)
|
|
if vprogress.mode != $V[:PBMODE]
|
|
vprogress.value(vprogress.maximum - vprogress.value)
|
|
end
|
|
|
|
progress.mode $V[:PBMODE]
|
|
vprogress.mode $V[:PBMODE]
|
|
end
|
|
|
|
start = Tk::Tile::Button.new(l, :text=>"Start",
|
|
:command=>proc{pbStart(progress, vprogress)})
|
|
def pbStart(progress, vprogress)
|
|
# $V[:PBMODE] = 'indeterminate'
|
|
pbMode(progress, vprogress)
|
|
progress.start 10
|
|
vprogress.start
|
|
end
|
|
|
|
stop = Tk::Tile::Button.new(l, :text=>'Stop',
|
|
:command=>proc{pbStop(progress, vprogress)})
|
|
def pbStop(progress, vprogress)
|
|
progress.stop
|
|
vprogress.stop
|
|
end
|
|
|
|
Tk.grid(scale, :columnspan=>2, :sticky=>'ew')
|
|
Tk.grid(progress, :columnspan=>2, :sticky=>'ew')
|
|
Tk.grid(vscale, vprogress, :sticky=>'nws')
|
|
|
|
Tk.grid(lmode, :sticky=>'we', :columnspan=>2)
|
|
Tk.grid(pbmode0, :sticky=>'we', :columnspan=>2)
|
|
Tk.grid(pbmode1, :sticky=>'we', :columnspan=>2)
|
|
Tk.grid(start, :sticky=>'we', :columnspan=>2)
|
|
Tk.grid(stop, :sticky=>'we', :columnspan=>2)
|
|
|
|
l.grid_columnconfigure(0, :weight=>1)
|
|
l.grid_columnconfigure(1, :weight=>1)
|
|
l.grid_rowconfigure(99, :weight=>1)
|
|
|
|
# standard frame
|
|
TkScale.new(r, :orient=>:horizontal, :from=>0, :to=>100,
|
|
:variable=>$V.ref(:SCALE)).grid(:sticky=>'news')
|
|
TkScale.new(r, :orient=>:vertical, :from=>0, :to=>100,
|
|
:variable=>$V.ref(:VSCALE)).grid(:sticky=>'nws')
|
|
|
|
r.grid_columnconfigure(0, :weight=>1)
|
|
r.grid_columnconfigure(1, :weight=>1)
|
|
r.grid_rowconfigure(99, :weight=>1)
|
|
|
|
else # tile 0.5 or earlier
|
|
|
|
# themed frame
|
|
scale = Tk::Tile::Scale.new(l, :variable=>$V.ref(:SCALE),
|
|
:orient=>:horizontal, :from=>0, :to=>100)
|
|
vscale = Tk::Tile::Scale.new(l, :variable=>$V.ref(:VSCALE),
|
|
:orient=>:vertical, :from=>-25, :to=>25)
|
|
|
|
progress = Tk::Tile::Progress.new(l,
|
|
:orient=>:horizontal, :from=>0, :to=>100)
|
|
vprogress = Tk::Tile::Progress.new(l,
|
|
:orient=>:vertical, :from=>-25, :to=>25)
|
|
|
|
if true
|
|
scale.command{|value| progress.set(value)}
|
|
vscale.command{|value| vprogress.set(value)}
|
|
else # this would also work. (via TkVariable#trace)
|
|
v1 = scale.variable
|
|
v2 = vscale.variable
|
|
v1.trace('w', proc{ progress.set(v1.value) })
|
|
v2.trace('w', proc{ vprogress.set(v2.value) })
|
|
end
|
|
|
|
Tk.grid(scale, :columnspan=>2, :sticky=>:ew)
|
|
Tk.grid(progress, :columnspan=>2, :sticky=>:ew)
|
|
Tk.grid(vscale, vprogress, :sticky=>:nws)
|
|
TkGrid.columnconfigure(l, 0, :weight=>1)
|
|
TkGrid.columnconfigure(l, 1, :weight=>1)
|
|
|
|
# standard frame
|
|
TkScale.new(r, :variable=>$V.ref(:SCALE),
|
|
:orient=>:horizontal, :from=>0, :to=>100).grid(:sticky=>'news')
|
|
TkScale.new(r, :variable=>$V.ref(:VSCALE),
|
|
:orient=>:vertical, :from=>-25, :to=>25).grid(:sticky=>'nws')
|
|
|
|
TkGrid.columnconfigure(r, 0, :weight=>1)
|
|
TkGrid.columnconfigure(r, 1, :weight=>1)
|
|
end
|
|
|
|
# layout frames
|
|
Tk.grid(l, r, :sticky=>'nwes', :padx=>6, :pady=>6)
|
|
scales.grid_columnconfigure(0, :weight=>1)
|
|
scales.grid_columnconfigure(1, :weight=>1)
|
|
scales.grid_rowconfigure(0, :weight=>1)
|
|
|
|
#
|
|
# Command box:
|
|
#
|
|
cmd = Tk::Tile::Frame.new($BASE)
|
|
b_close = Tk::Tile::Button.new(cmd, :text=>'Close',
|
|
:underline=>0, :default=>:normal,
|
|
:command=>proc{Tk.root.destroy})
|
|
b_help = Tk::Tile::Button.new(cmd, :text=>'Help', :underline=>0,
|
|
:default=>:normal, :command=>proc{showHelp()})
|
|
Tk.grid('x', b_close, b_help, :pady=>[6, 4], :padx=>4)
|
|
TkGrid.columnconfigure(cmd, 0, :weight=>1)
|
|
|
|
#
|
|
# Set up accelerators:
|
|
#
|
|
$ROOT.bind('KeyPress-Escape', proc{Tk.event_generate(b_close, '<Invoke>')})
|
|
$ROOT.bind('<Help>', proc{Tk.event_generate(b_help, '<Invoke>')})
|
|
Tk::Tile::KeyNav.enableMnemonics($ROOT)
|
|
Tk::Tile::KeyNav.defaultButton(b_help)
|
|
|
|
Tk.grid($TOOLBARS[0], '-', :sticky=>:ew)
|
|
Tk.grid($TOOLBARS[1], '-', :sticky=>:ew)
|
|
Tk.grid(control, nb, :sticky=>:news)
|
|
Tk.grid(cmd, '-', :sticky=>:ew)
|
|
TkGrid.columnconfigure($ROOT, 1, :weight=>1)
|
|
TkGrid.rowconfigure($ROOT, 2, :weight=>1)
|
|
|
|
#
|
|
# Add a menu
|
|
#
|
|
menu = TkMenu.new($BASE)
|
|
$ROOT.menu(menu)
|
|
m_file = TkMenu.new(menu, :tearoff=>0)
|
|
menu.add(:cascade, :label=>'File', :underline=>0, :menu=>m_file)
|
|
m_file.add(:command, :label=>'Open', :underline=>0,
|
|
:compound=>:left, :image=>$ICON['open'])
|
|
m_file.add(:command, :label=>'Save', :underline=>0,
|
|
:compound=>:left, :image=>$ICON['save'])
|
|
m_file.add(:separator)
|
|
m_f_test = TkMenu.new(menu, :tearoff=>0)
|
|
m_file.add(:cascade, :label=>'Test submenu', :underline=>0, :menu=>m_f_test)
|
|
m_file.add(:checkbutton, :label=>'Text check', :underline=>5,
|
|
:variable=>$V.ref(:MENUCHECK1))
|
|
m_file.insert(:end, :separator)
|
|
|
|
if Tk.windowingsystem != 'x11'
|
|
TkConsole.create
|
|
m_file.insert(:end, :checkbutton, :label=>'Console', :underline=>5,
|
|
:variable=>$V.ref(:CONSOLE), :command=>proc{toggle_console()})
|
|
def toggle_console
|
|
if TkComm.bool($V[:CONSOLE])
|
|
TkConsole.show
|
|
else
|
|
TkConsole.hide
|
|
end
|
|
end
|
|
end
|
|
|
|
m_file.add(:command, :label=>'Exit', :underline=>1,
|
|
:command=>proc{Tk.event_generate(b_close, '<Invoke>')})
|
|
|
|
%w(One Two Three Four).each{|lbl|
|
|
m_f_test.add(:radiobutton, :label=>lbl, :variable=>$V.ref(:MENURADIO1))
|
|
}
|
|
|
|
# Add Theme menu.
|
|
#
|
|
menu.add(:cascade, :label=>'Theme', :underline=>3,
|
|
:menu=>makeThemeMenu(menu))
|
|
|
|
setTheme($V[:THEME])
|
|
|
|
#
|
|
# Combobox demo pane:
|
|
#
|
|
values = %w(list abc def ghi jkl mno pqr stu vwx yz)
|
|
2.times {|i|
|
|
cb = Tk::Tile::Combobox.new(
|
|
combo, :values=>values, :textvariable=>$V.ref(:COMBO))
|
|
cb.pack(:side=>:top, :padx=>2, :pady=>2, :expand=>false, :fill=>:x)
|
|
if i == 1
|
|
cb.ttk_state :readonly
|
|
begin
|
|
cb.current = 3 # ignore if unsupported (tile0.4)
|
|
rescue
|
|
end
|
|
end
|
|
}
|
|
|
|
#
|
|
# Treeview widget demo pane:
|
|
#
|
|
if version?('0.5')
|
|
|
|
treeview = nil # avoid 'undefined' error
|
|
scrollbar = Tk::Tile::Scrollbar.new(tree,
|
|
:command=>proc{|*args| treeview.yview(*args)})
|
|
treeview = Tk::Tile::Treeview.new(tree, :columns=>%w(Class), :padding=>4,
|
|
:yscrollcommand=>proc{|*args| scrollbar.set(*args)})
|
|
|
|
Tk.grid(treeview, scrollbar, :sticky=>'news')
|
|
tree.grid_columnconfigure(0, :weight=>1)
|
|
tree.grid_rowconfigure(0, :weight=>1)
|
|
tree.grid_propagate(0)
|
|
|
|
# Add initial tree node:
|
|
# Later nodes will be added in <<TreeviewOpen>> binding.
|
|
treeview.insert('', 0, :id=>'.', :text=>'Main Window', :open=>false,
|
|
:values=>[TkWinfo.classname('.')])
|
|
treeview.headingconfigure('#0', :text=>'Widget')
|
|
treeview.headingconfigure('Class', :text=>'Class')
|
|
treeview.bind('<TreeviewOpen>', proc{fillTree(treeview)})
|
|
|
|
def fillTree(treeview)
|
|
id = treeview.focus_item
|
|
unless TkWinfo.exist?(id)
|
|
treeview.delete(id)
|
|
end
|
|
# Replace tree item children with current list of child windows.
|
|
treeview.delete(treeview.children(id))
|
|
for child in TkWinfo.children(id)
|
|
treeview.insert(id, :end, :id=>child, :text=>TkWinfo.appname(child),
|
|
:open=>false, :values=>[TkWinfo.classname(child)])
|
|
unless TkWinfo.children(child).empty?
|
|
# insert dummy child to show [+] indicator
|
|
treeview.insert(child, :end)
|
|
end
|
|
end
|
|
end
|
|
|
|
else
|
|
Tk::Tile::Label.new(tree,
|
|
:text=>'Treeview is supported on tile 0.5 or later...').pack
|
|
end
|
|
|
|
#
|
|
# Other demos:
|
|
#
|
|
$Timers = {:StateMonitor=>nil, :FocusMonitor=>nil}
|
|
|
|
begin
|
|
msg = Tk::Tile::Label.new(others, :justify=>:left, :wraplength=>300)
|
|
rescue
|
|
msg = TkMessage.new(others, :aspect=>200)
|
|
end
|
|
|
|
$Desc = {}
|
|
|
|
showDescription = TkBindTag.new
|
|
showDescription.bind('Enter', proc{|w| msg.text($Desc[w.path])}, '%W')
|
|
showDescription.bind('Leave', proc{|w| msg.text('')}, '%W')
|
|
|
|
[
|
|
[ :trackStates, "Widget states...",
|
|
"Display/modify widget state bits" ],
|
|
|
|
[ :scrollbarResizeDemo, "Scrollbar resize behavior...",
|
|
"Shows how Tile and standard scrollbars differ when they're sized too large" ],
|
|
|
|
[ :trackFocus, "Track keyboard focus..." ,
|
|
"Display the name of the widget that currently has focus" ],
|
|
|
|
[ :repeatDemo, "Repeating buttons...",
|
|
"Demonstrates custom classes (see demos/repeater.tcl)" ]
|
|
|
|
].each{|demo_cmd, label, description|
|
|
b = Tk::Tile::Button.new(others, :text=>label,
|
|
:command=>proc{ self.__send__(demo_cmd) })
|
|
$Desc[b.path] = description
|
|
b.bindtags <<= showDescription
|
|
|
|
b.pack(:side=>:top, :expand=>false, :fill=>:x, :padx=>6, :pady=>6)
|
|
}
|
|
|
|
msg.pack(:side=>:bottom, :expand=>true, :fill=>:both)
|
|
|
|
|
|
#
|
|
# Scrollbar resize demo:
|
|
#
|
|
$scrollbars = nil
|
|
|
|
def scrollbarResizeDemo
|
|
if $scrollbars
|
|
begin
|
|
$scrollbars.destroy
|
|
rescue
|
|
end
|
|
end
|
|
$scrollbars = TkToplevel.new(:title=>'Scrollbars', :geometry=>'200x200')
|
|
f = TkFrame.new($scrollbars, :height=>200)
|
|
tsb = Tk::Tile::Scrollbar.new(f, :command=>proc{|*args| sbstub(tsb, *args)})
|
|
sb = TkScrollbar.new(f, :command=>proc{|*args| sbstub(sb, *args)})
|
|
Tk.grid(tsb, sb, :sticky=>:news)
|
|
|
|
sb.set(0, 0.5) # prevent backwards-compatibility mode for old SB
|
|
|
|
f.grid_columnconfigure(0, :weight=>1)
|
|
f.grid_columnconfigure(1, :weight=>1)
|
|
f.grid_rowconfigure(0, :weight=>1)
|
|
|
|
f.pack(:expand=>true, :fill=>:both)
|
|
end
|
|
|
|
#
|
|
# Track focus demo:
|
|
#
|
|
$FocusInf = TkVariable.new_hash
|
|
$focus = nil
|
|
|
|
def trackFocus
|
|
if $focus
|
|
begin
|
|
$focus.destroy
|
|
rescue
|
|
end
|
|
end
|
|
$focus = TkToplevel.new(:title=>'Keyboard focus')
|
|
i = 0
|
|
[
|
|
["Focus widget:", :Widget],
|
|
["Class:", :WidgetClass],
|
|
["Next:", :WidgetNext],
|
|
["Grab:", :Grab],
|
|
["Status:", :GrabStatus]
|
|
].each{|label, var_index|
|
|
Tk.grid(Tk::Tile::Label.new($focus, :text=>label, :anchor=>:e),
|
|
Tk::Tile::Label.new($focus,
|
|
:textvariable=>$FocusInf.ref(var_index),
|
|
:width=>40, :anchor=>:w, :relief=>:groove),
|
|
:sticky=>:ew)
|
|
i += 1
|
|
}
|
|
$focus.grid_columnconfigure(1, :weight=>1)
|
|
$focus.grid_rowconfigure(i, :weight=>1)
|
|
|
|
$focus.bind('Destroy', proc{Tk.after_cancel($Timers[:FocusMonitor])})
|
|
focusMonitor
|
|
end
|
|
|
|
def focusMonitor
|
|
$FocusInf[:Widget] = focus_win = Tk.focus
|
|
if focus_win
|
|
$FocusInf[:WidgetClass] = focus_win.winfo_classname
|
|
$FocusInf[:WidgetNext] = Tk.focus_next(focus_win)
|
|
else
|
|
$FocusInf[:WidgetClass] = $FocusInf[:WidgetNext] = ''
|
|
end
|
|
|
|
$FocusInf[:Grab] = grab_wins = Tk.current_grabs
|
|
unless grab_wins.empty?
|
|
$FocusInf[:GrabStatus] = grab_wins[0].grab_status
|
|
else
|
|
$FocusInf[:GrabStatus] = ''
|
|
end
|
|
|
|
$Timers[:FocusMonitor] = Tk.after(200, proc{ focusMonitor() })
|
|
end
|
|
|
|
#
|
|
# Widget state demo:
|
|
#
|
|
$Widget = TkVariable.new
|
|
|
|
TkBindTag::ALL.bind('Control-Shift-ButtonPress-1',
|
|
proc{|w|
|
|
$Widget.value = w
|
|
updateStates()
|
|
Tk.callback_break
|
|
}, '%W')
|
|
$states_list = %w(active disabled focus pressed selected
|
|
background indeterminate invalid default)
|
|
$states_btns = {}
|
|
$states = nil
|
|
|
|
$State = TkVariable.new_hash
|
|
|
|
def trackStates
|
|
if $states
|
|
begin
|
|
$state.destroy
|
|
rescue
|
|
end
|
|
end
|
|
$states = TkToplevel.new(:title=>'Widget states')
|
|
|
|
l_inf = Tk::Tile::Label.new($states, :text=>"Press Control-Shift-Button-1 on any widget")
|
|
|
|
l_lw = Tk::Tile::Label.new($states, :text=>'Widget:',
|
|
:anchor=>:e, :relief=>:groove)
|
|
l_w = Tk::Tile::Label.new($states, :textvariable=>$Widget,
|
|
:anchor=>:w, :relief=>:groove)
|
|
|
|
Tk.grid(l_inf, '-', :sticky=>:ew, :padx=>6, :pady=>6)
|
|
Tk.grid(l_lw, l_w, :sticky=>:ew)
|
|
|
|
$states_list.each{|st|
|
|
cb = Tk::Tile::Checkbutton.new($states, :text=>st,
|
|
:variable=>$State.ref(st),
|
|
:command=>proc{ changeState(st) })
|
|
$states_btns[st] = cb
|
|
Tk.grid('x', cb, :sticky=>:nsew)
|
|
}
|
|
|
|
$states.grid_columnconfigure(1, :weight=>1)
|
|
|
|
f_cmd = Tk::Tile::Frame.new($states)
|
|
Tk.grid('x', f_cmd, :sticky=>:nse)
|
|
|
|
b_close = Tk::Tile::Button.new(f_cmd, :text=>'Close',
|
|
:command=>proc{ $states.destroy })
|
|
Tk.grid('x', b_close, :padx=>4, :pady=>[6,4])
|
|
f_cmd.grid_columnconfigure(0, :weight=>1)
|
|
|
|
$states.bind('KeyPress-Escape', proc{Tk.event_generate(b_close, '<Invoke>')})
|
|
|
|
$states.bind('Destroy', proc{Tk.after_cancel($Timers[:StateMonitor])})
|
|
stateMonitor()
|
|
end
|
|
|
|
def stateMonitor
|
|
updateStates() if $Widget.value != ''
|
|
$Timers[:StateMonitor] = Tk.after(200, proc{ stateMonitor() })
|
|
end
|
|
|
|
def updateStates
|
|
$states_list.each{|st|
|
|
begin
|
|
$State[st] = $Widget.window.ttk_instate(st)
|
|
rescue
|
|
$states_btns[st].ttk_state('disabled')
|
|
else
|
|
$states_btns[st].ttk_state('!disabled')
|
|
end
|
|
}
|
|
end
|
|
|
|
def changeState(st)
|
|
if $Widget.value != ''
|
|
if $State.bool_element(st)
|
|
$Widget.window.ttk_state(st)
|
|
else
|
|
$Widget.window.ttk_state("!#{st}")
|
|
end
|
|
end
|
|
end
|
|
|
|
#
|
|
# Repeating buttons demo:
|
|
#
|
|
def repeatDemo
|
|
if defined?($repeatDemo) && $repeatDemo.exist?
|
|
$repeatDemo.deiconify; return
|
|
end
|
|
$repeatDemo = TkToplevel.new(:title=>'Repeating button')
|
|
|
|
f = Tk::Tile::Frame.new($repeatDemo)
|
|
b = Tk::Tile::Button.new(f, :class=>'Repeater', :text=>'Press and hold')
|
|
if version?('0.6')
|
|
p = Tk::Tile::Progressbar.new(f, :orient=>:horizontal, :maximum=>10)
|
|
else # progressbar is not supported
|
|
p = Tk::Tile::Progress.new(f, :orient=>:horizontal, :from=>0, :to=>10)
|
|
def p.step
|
|
i = self.get + 1
|
|
i = self.from if i > self.to
|
|
self.set(i)
|
|
end
|
|
end
|
|
b.command {p.step}
|
|
|
|
b.pack(:side=>:left, :expand=>false, :fill=>:none, :padx=>6, :pady=>6)
|
|
p.pack(:side=>:right, :expand=>true, :fill=>:x, :padx=>6, :pady=>6)
|
|
f.pack(:expand=>true, :fill=>:both)
|
|
end
|
|
|
|
Tk.mainloop
|