mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
ed6ce8b43b
* ext/tk/*: Support new features of Tcl/Tk8.6b1 and minor bug fixes. ( [KNOWN BUG] Ruby/Tk on Ruby 1.9 will not work on Cygwin. ) * ext/tk/*: Unify sources between Ruby 1.8 & 1.9. Improve default_widget_set handling. * ext/tk/*: Multi-TkInterpreter (multi-tk.rb) works on Ruby 1.8 & 1.9. ( [KNOWN BUG] On Ruby 1.8, join to a long term Thread on Tk callbacks may freeze. On Ruby 1.9, cannot create a second master interpreter (creating slaves are OK); supported master interpreter is the default master interpreter only. ) * ext/tk/lib/tkextlib/*: Update supported versions of Tk extensions. Tcllib 1.8/Tklib 0.4.1 ==> Tcllib 1.11.1/Tklib 0.5 BWidgets 1.7 ==> BWidgets 1.8 TkTable 2.9 ==> TkTable 2.10 TkTreeCtrl 2005-12-02 ==> TkTreeCtrl 2.2.9 Tile 0.8.0/8.5.1 ==> Tile 0.8.3/8.6b1 IncrTcl 2005-02-14 ==> IncrTcl 2008-12-15 TclX 2005-02-07 ==> TclX 2008-12-15 Trofs 0.4.3 ==> Trofs 0.4.4 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@24063 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
449 lines
13 KiB
Ruby
449 lines
13 KiB
Ruby
#
|
|
# Tile theme engin (tile widget set) support
|
|
# by Hidetoshi NAGAI (nagai@ai.kyutech.ac.jp)
|
|
#
|
|
|
|
require 'tk'
|
|
require 'tk/ttk_selector'
|
|
|
|
# call setup script for general 'tkextlib' libraries
|
|
require 'tkextlib/setup.rb'
|
|
|
|
# library directory
|
|
require 'tkextlib/tile/setup.rb'
|
|
|
|
# load package
|
|
# TkPackage.require('tile', '0.4')
|
|
# TkPackage.require('tile', '0.6')
|
|
# TkPackage.require('tile', '0.7')
|
|
if Tk::TK_MAJOR_VERSION > 8 ||
|
|
(Tk::TK_MAJOR_VERSION == 8 && Tk::TK_MINOR_VERSION >= 5)
|
|
begin
|
|
TkPackage.require('tile') # for compatibility (version check of 'tile')
|
|
rescue RuntimeError
|
|
# ignore, even if cannot find package 'tile'
|
|
end
|
|
pkgname = 'Ttk'
|
|
else
|
|
pkgname = 'tile'
|
|
end
|
|
|
|
begin
|
|
verstr = TkPackage.require(pkgname)
|
|
rescue RuntimeError
|
|
# define dummy methods
|
|
module Tk
|
|
module Tile
|
|
CANNOT_FIND_PACKAGE = true
|
|
def self.const_missing(sym)
|
|
TkPackage.require(PACKAGE_NAME)
|
|
end
|
|
def self.method_missing(*args)
|
|
TkPackage.require(PACKAGE_NAME)
|
|
end
|
|
end
|
|
end
|
|
Tk.__cannot_find_tk_package_for_widget_set__(:Ttk, pkgname)
|
|
if pkgname == 'Ttk'
|
|
verstr = Tk::TK_PATCHLEVEL # dummy
|
|
else
|
|
verstr = '0.7' # dummy
|
|
end
|
|
end
|
|
|
|
ver = verstr.split('.')
|
|
if ver[0].to_i == 0
|
|
# Tile extension package
|
|
if ver[1].to_i <= 4
|
|
# version 0.4 or former
|
|
module Tk
|
|
module Tile
|
|
USE_TILE_NAMESPACE = true
|
|
USE_TTK_NAMESPACE = false
|
|
TILE_SPEC_VERSION_ID = 0
|
|
end
|
|
end
|
|
elsif ver[1].to_i <= 6
|
|
# version 0.5 -- version 0.6
|
|
module Tk
|
|
module Tile
|
|
USE_TILE_NAMESPACE = true
|
|
USE_TTK_NAMESPACE = true
|
|
TILE_SPEC_VERSION_ID = 5
|
|
end
|
|
end
|
|
elsif ver[1].to_i <= 7
|
|
module Tk
|
|
module Tile
|
|
USE_TILE_NAMESPACE = false
|
|
USE_TTK_NAMESPACE = true
|
|
TILE_SPEC_VERSION_ID = 7
|
|
end
|
|
end
|
|
else
|
|
# version 0.8 or later
|
|
module Tk
|
|
module Tile
|
|
USE_TILE_NAMESPACE = false
|
|
USE_TTK_NAMESPACE = true
|
|
TILE_SPEC_VERSION_ID = 8
|
|
end
|
|
end
|
|
end
|
|
|
|
module Tk::Tile
|
|
PACKAGE_NAME = 'tile'.freeze
|
|
end
|
|
else
|
|
# Ttk package merged Tcl/Tk core (Tcl/Tk 8.5+)
|
|
module Tk
|
|
module Tile
|
|
USE_TILE_NAMESPACE = false
|
|
USE_TTK_NAMESPACE = true
|
|
TILE_SPEC_VERSION_ID = 8
|
|
|
|
PACKAGE_NAME = 'Ttk'.freeze
|
|
end
|
|
end
|
|
end
|
|
|
|
# autoload
|
|
module Tk
|
|
module Tile
|
|
TkComm::TkExtlibAutoloadModule.unshift(self)
|
|
|
|
def self.package_name
|
|
PACKAGE_NAME
|
|
end
|
|
|
|
def self.package_version
|
|
begin
|
|
TkPackage.require(PACKAGE_NAME)
|
|
rescue
|
|
''
|
|
end
|
|
end
|
|
|
|
def self.__Import_Tile_Widgets__!
|
|
warn 'Warning: "Tk::Tile::__Import_Tile_Widgets__!" is obsolete.' <<
|
|
' To control default widget set, use "Tk.default_widget_set = :Ttk"'
|
|
Tk.tk_call('namespace', 'import', '-force', 'ttk::*')
|
|
end
|
|
|
|
def self.__define_LoadImages_proc_for_compatibility__!
|
|
# Ttk 8.5 (Tile 0.8) lost 'LoadImages' utility procedure.
|
|
# So, some old scripts doen't work, because those scripts use the
|
|
# procedure to define local styles.
|
|
# Of course, rewriting such Tcl/Tk scripts isn't difficult for
|
|
# Tcl/Tk users. However, it may be troublesome for Ruby/Tk users
|
|
# who use such Tcl/Tk scripts as it is.
|
|
# This method may help Ruby/Tk users who don't want to modify old
|
|
# Tcl/Tk scripts for the latest version of Ttk (Tile) extension.
|
|
# This method defines a comaptible 'LoadImages' procedure on the
|
|
# Tcl/Tk interpreter working under Ruby/Tk.
|
|
# Please give attention to use this method. It may conflict with
|
|
# some definitions on Tcl/Tk scripts.
|
|
klass_name = self.name
|
|
proc_name = 'LoadImages'
|
|
if Tk::Tile::USE_TTK_NAMESPACE
|
|
ns_list = ['::tile']
|
|
if Tk.info(:commands, "::ttk::#{proc_name}").empty?
|
|
ns_list << '::ttk'
|
|
end
|
|
else # Tk::Tile::USE_TILE_NAMESPACE
|
|
ns_list = ['::ttk']
|
|
if Tk.info(:commands, "::tile::#{proc_name}").empty?
|
|
ns_list << '::tile'
|
|
end
|
|
end
|
|
|
|
ns_list.each{|ns|
|
|
cmd = "#{ns}::#{proc_name}"
|
|
unless Tk.info(:commands, cmd).empty?
|
|
#fail RuntimeError, "can't define '#{cmd}' command (already exist)"
|
|
|
|
# do nothing !!!
|
|
warn "Warning: can't define '#{cmd}' command (already exist)" if $DEBUG
|
|
next
|
|
end
|
|
TkNamespace.eval(ns){
|
|
TkCore::INTERP.add_tk_procs(proc_name, 'imgdir {patterns {*.gif}}',
|
|
<<-'EOS')
|
|
foreach pattern $patterns {
|
|
foreach file [glob -directory $imgdir $pattern] {
|
|
set img [file tail [file rootname $file]]
|
|
if {![info exists images($img)]} {
|
|
set images($img) [image create photo -file $file]
|
|
}
|
|
}
|
|
}
|
|
return [array get images]
|
|
EOS
|
|
}
|
|
}
|
|
end
|
|
|
|
def self.load_images(imgdir, pat=nil)
|
|
if Tk::Tile::TILE_SPEC_VERSION_ID < 8
|
|
if Tk::Tile::USE_TTK_NAMESPACE
|
|
cmd = '::ttk::LoadImages'
|
|
else # Tk::Tile::USE_TILE_NAMESPACE
|
|
cmd = '::tile::LoadImages'
|
|
end
|
|
pat ||= TkComm::None
|
|
images = Hash[*TkComm.simplelist(Tk.tk_call(cmd, imgdir, pat))]
|
|
images.keys.each{|k|
|
|
images[k] = TkPhotoImage.new(:imagename=>images[k],
|
|
:without_creating=>true)
|
|
}
|
|
else ## TILE_SPEC_VERSION_ID >= 8
|
|
pat ||= '*.gif'
|
|
if pat.kind_of?(Array)
|
|
pat_list = pat
|
|
else
|
|
pat_list = [ pat ]
|
|
end
|
|
Dir.chdir(imgdir){
|
|
pat_list.each{|pat|
|
|
Dir.glob(pat).each{|f|
|
|
img = File.basename(f, '.*')
|
|
unless TkComm.bool(Tk.info('exists', "images(#{img})"))
|
|
Tk.tk_call('set', "images(#{img})",
|
|
Tk.tk_call('image', 'create', 'photo', '-file', f))
|
|
end
|
|
}
|
|
}
|
|
}
|
|
images = Hash[*TkComm.simplelist(Tk.tk_call('array', 'get', 'images'))]
|
|
images.keys.each{|k|
|
|
images[k] = TkPhotoImage.new(:imagename=>images[k],
|
|
:without_creating=>true)
|
|
}
|
|
end
|
|
|
|
images
|
|
end
|
|
|
|
def self.style(*args)
|
|
args.map!{|arg| TkComm._get_eval_string(arg)}.join('.')
|
|
end
|
|
|
|
def self.themes(glob_ptn = nil)
|
|
if TILE_SPEC_VERSION_ID < 8 && Tk.info(:commands, '::ttk::themes').empty?
|
|
fail RuntimeError, 'not support glob option' if glob_ptn
|
|
cmd = ['::tile::availableThemes']
|
|
else
|
|
glob_ptn = '*' unless glob_ptn
|
|
cmd = ['::ttk::themes', glob_ptn]
|
|
end
|
|
|
|
begin
|
|
TkComm.simplelist(Tk.tk_call_without_enc(*cmd))
|
|
rescue
|
|
TkComm.simplelist(Tk.tk_call('lsearch', '-all', '-inline',
|
|
Tk::Tile::Style.theme_names,
|
|
glob_ptn))
|
|
end
|
|
end
|
|
|
|
def self.set_theme(theme)
|
|
if TILE_SPEC_VERSION_ID < 8 && Tk.info(:commands, '::ttk::setTheme').empty?
|
|
cmd = '::tile::setTheme'
|
|
else
|
|
cmd = '::ttk::setTheme'
|
|
end
|
|
|
|
begin
|
|
Tk.tk_call_without_enc(cmd, theme)
|
|
rescue
|
|
Tk::Tile::Style.theme_use(theme)
|
|
end
|
|
end
|
|
|
|
module KeyNav
|
|
if Tk::Tile::TILE_SPEC_VERSION_ID < 8
|
|
def self.enableMnemonics(w)
|
|
Tk.tk_call('::keynav::enableMnemonics', w)
|
|
end
|
|
def self.defaultButton(w)
|
|
Tk.tk_call('::keynav::defaultButton', w)
|
|
end
|
|
else # dummy
|
|
def self.enableMnemonics(w)
|
|
""
|
|
end
|
|
def self.defaultButton(w)
|
|
""
|
|
end
|
|
end
|
|
end
|
|
|
|
module Font
|
|
Default = 'TkDefaultFont'
|
|
Text = 'TkTextFont'
|
|
Heading = 'TkHeadingFont'
|
|
Caption = 'TkCaptionFont'
|
|
Tooltip = 'TkTooltipFont'
|
|
|
|
Fixed = 'TkFixedFont'
|
|
Menu = 'TkMenuFont'
|
|
SmallCaption = 'TkSmallCaptionFont'
|
|
Icon = 'TkIconFont'
|
|
|
|
TkFont::SYSTEM_FONT_NAMES.add [
|
|
'TkDefaultFont', 'TkTextFont', 'TkHeadingFont',
|
|
'TkCaptionFont', 'TkTooltipFont', 'TkFixedFont',
|
|
'TkMenuFont', 'TkSmallCaptionFont', 'TkIconFont'
|
|
]
|
|
end
|
|
|
|
module ParseStyleLayout
|
|
def _style_layout(lst)
|
|
ret = []
|
|
until lst.empty?
|
|
sub = [lst.shift]
|
|
keys = {}
|
|
|
|
until lst.empty?
|
|
if lst[0][0] == ?-
|
|
k = lst.shift[1..-1]
|
|
children = lst.shift
|
|
children = _style_layout(children) if children.kind_of?(Array)
|
|
keys[k] = children
|
|
else
|
|
break
|
|
end
|
|
end
|
|
|
|
sub << keys unless keys.empty?
|
|
ret << sub
|
|
end
|
|
ret
|
|
end
|
|
private :_style_layout
|
|
end
|
|
|
|
module TileWidget
|
|
include Tk::Tile::ParseStyleLayout
|
|
|
|
def __val2ruby_optkeys # { key=>proc, ... }
|
|
# The method is used to convert a opt-value to a ruby's object.
|
|
# When get the value of the option "key", "proc.call(value)" is called.
|
|
super().update('style'=>proc{|v| _style_layout(list(v))})
|
|
end
|
|
private :__val2ruby_optkeys
|
|
|
|
def ttk_instate(state, script=nil, &b)
|
|
if script
|
|
tk_send('instate', state, script)
|
|
elsif b
|
|
tk_send('instate', state, Proc.new(&b))
|
|
else
|
|
bool(tk_send('instate', state))
|
|
end
|
|
end
|
|
alias tile_instate ttk_instate
|
|
|
|
def ttk_state(state=nil)
|
|
if state
|
|
tk_send('state', state)
|
|
else
|
|
list(tk_send('state'))
|
|
end
|
|
end
|
|
alias tile_state ttk_state
|
|
|
|
def ttk_identify(x, y)
|
|
ret = tk_send_without_enc('identify', x, y)
|
|
(ret.empty?)? nil: ret
|
|
end
|
|
alias tile_identify ttk_identify
|
|
|
|
# remove instate/state/identify method
|
|
# to avoid the conflict with widget options
|
|
if Tk.const_defined?(:USE_OBSOLETE_TILE_STATE_METHOD) && Tk::USE_OBSOLETE_TILE_STATE_METHOD
|
|
alias instate ttk_instate
|
|
alias state ttk_state
|
|
alias identify ttk_identify
|
|
end
|
|
end
|
|
|
|
######################################
|
|
|
|
autoload :TButton, 'tkextlib/tile/tbutton'
|
|
autoload :Button, 'tkextlib/tile/tbutton'
|
|
|
|
autoload :TCheckButton, 'tkextlib/tile/tcheckbutton'
|
|
autoload :CheckButton, 'tkextlib/tile/tcheckbutton'
|
|
autoload :TCheckbutton, 'tkextlib/tile/tcheckbutton'
|
|
autoload :Checkbutton, 'tkextlib/tile/tcheckbutton'
|
|
|
|
autoload :Dialog, 'tkextlib/tile/dialog'
|
|
|
|
autoload :TEntry, 'tkextlib/tile/tentry'
|
|
autoload :Entry, 'tkextlib/tile/tentry'
|
|
|
|
autoload :TCombobox, 'tkextlib/tile/tcombobox'
|
|
autoload :Combobox, 'tkextlib/tile/tcombobox'
|
|
|
|
autoload :TFrame, 'tkextlib/tile/tframe'
|
|
autoload :Frame, 'tkextlib/tile/tframe'
|
|
|
|
autoload :TLabelframe, 'tkextlib/tile/tlabelframe'
|
|
autoload :Labelframe, 'tkextlib/tile/tlabelframe'
|
|
autoload :TLabelFrame, 'tkextlib/tile/tlabelframe'
|
|
autoload :LabelFrame, 'tkextlib/tile/tlabelframe'
|
|
|
|
autoload :TLabel, 'tkextlib/tile/tlabel'
|
|
autoload :Label, 'tkextlib/tile/tlabel'
|
|
|
|
autoload :TMenubutton, 'tkextlib/tile/tmenubutton'
|
|
autoload :Menubutton, 'tkextlib/tile/tmenubutton'
|
|
autoload :TMenuButton, 'tkextlib/tile/tmenubutton'
|
|
autoload :MenuButton, 'tkextlib/tile/tmenubutton'
|
|
|
|
autoload :TNotebook, 'tkextlib/tile/tnotebook'
|
|
autoload :Notebook, 'tkextlib/tile/tnotebook'
|
|
|
|
autoload :TPaned, 'tkextlib/tile/tpaned'
|
|
autoload :Paned, 'tkextlib/tile/tpaned'
|
|
autoload :PanedWindow, 'tkextlib/tile/tpaned'
|
|
autoload :Panedwindow, 'tkextlib/tile/tpaned'
|
|
|
|
autoload :TProgressbar, 'tkextlib/tile/tprogressbar'
|
|
autoload :Progressbar, 'tkextlib/tile/tprogressbar'
|
|
|
|
autoload :TRadioButton, 'tkextlib/tile/tradiobutton'
|
|
autoload :RadioButton, 'tkextlib/tile/tradiobutton'
|
|
autoload :TRadiobutton, 'tkextlib/tile/tradiobutton'
|
|
autoload :Radiobutton, 'tkextlib/tile/tradiobutton'
|
|
|
|
autoload :TScale, 'tkextlib/tile/tscale'
|
|
autoload :Scale, 'tkextlib/tile/tscale'
|
|
autoload :TProgress, 'tkextlib/tile/tscale'
|
|
autoload :Progress, 'tkextlib/tile/tscale'
|
|
|
|
autoload :TScrollbar, 'tkextlib/tile/tscrollbar'
|
|
autoload :Scrollbar, 'tkextlib/tile/tscrollbar'
|
|
autoload :XScrollbar, 'tkextlib/tile/tscrollbar'
|
|
autoload :YScrollbar, 'tkextlib/tile/tscrollbar'
|
|
|
|
autoload :TSeparator, 'tkextlib/tile/tseparator'
|
|
autoload :Separator, 'tkextlib/tile/tseparator'
|
|
|
|
autoload :TSpinbox, 'tkextlib/tile/tspinbox'
|
|
autoload :Spinbox, 'tkextlib/tile/tspinbox'
|
|
|
|
autoload :TSquare, 'tkextlib/tile/tsquare'
|
|
autoload :Square, 'tkextlib/tile/tsquare'
|
|
|
|
autoload :SizeGrip, 'tkextlib/tile/sizegrip'
|
|
autoload :Sizegrip, 'tkextlib/tile/sizegrip'
|
|
|
|
autoload :Treeview, 'tkextlib/tile/treeview'
|
|
|
|
autoload :Style, 'tkextlib/tile/style'
|
|
end
|
|
end
|
|
|
|
Ttk = Tk::Tile
|