summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/cgi-lib.rb2
-rw-r--r--lib/complex.rb14
-rw-r--r--lib/matrix.rb230
-rw-r--r--lib/singleton.rb37
-rw-r--r--lib/telnet.rb200
-rw-r--r--lib/tk.rb472
-rw-r--r--lib/tkcanvas.rb33
-rw-r--r--lib/tkentry.rb6
-rw-r--r--lib/tkfont.rb556
-rw-r--r--lib/tktext.rb66
10 files changed, 1499 insertions, 117 deletions
diff --git a/lib/cgi-lib.rb b/lib/cgi-lib.rb
index 6a846b2017..c6c1caa98b 100644
--- a/lib/cgi-lib.rb
+++ b/lib/cgi-lib.rb
@@ -25,7 +25,7 @@ class CGI < SimpleDelegator
words = Shellwords.shellwords(if not ARGV.empty? then
ARGV.join(' ')
else
- STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDOUT.tty?
+ STDERR.print "(offline mode: enter name=value pairs on standard input)\n" if STDIN.tty?
readlines.join(' ').gsub(/\n/, '')
end.gsub(/\\=/, '%3D').gsub(/\\&/, '%26'))
diff --git a/lib/complex.rb b/lib/complex.rb
index 69437b01bb..59caad6ebc 100644
--- a/lib/complex.rb
+++ b/lib/complex.rb
@@ -1,8 +1,8 @@
#
# complex.rb -
# $Release Version: 0.5 $
-# $Revision: 1.1.1.1 $
-# $Date: 1998/01/16 04:05:49 $
+# $Revision: 1.3 $
+# $Date: 1998/07/08 10:05:28 $
# by Keiju ISHITSUKA(SHL Japan Inc.)
#
# --
@@ -59,6 +59,7 @@ def Complex(a, b = 0)
end
class Complex < Numeric
+ @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
def Complex.generic?(other)
other.kind_of?(Integer) or
@@ -284,6 +285,11 @@ class Complex < Numeric
@real ^ @image
end
+ def inspect
+ sprintf("Complex(%s, %s)", @real.inspect, @image.inspect)
+ end
+
+
I = Complex(0,1)
attr :real
@@ -396,7 +402,7 @@ module Math
cos!(z)
else
Complex(cos!(z.real)*cosh!(z.image),
- sin!(z.real)*sinh!(z.image))
+ -sin!(z.real)*sinh!(z.image))
end
end
@@ -405,7 +411,7 @@ module Math
sin!(z)
else
Complex(sin!(z.real)*cosh!(z.image),
- -cos!(z.real)*sinh!(z.image))
+ cos!(z.real)*sinh!(z.image))
end
end
diff --git a/lib/matrix.rb b/lib/matrix.rb
index 631b6547b3..6639fe72ea 100644
--- a/lib/matrix.rb
+++ b/lib/matrix.rb
@@ -1,8 +1,9 @@
+#!/usr/local/bin/ruby
#
# matrix.rb -
# $Release Version: 1.0$
-# $Revision: 1.0 $
-# $Date: 97/05/23 11:35:28 $
+# $Revision: 1.4 $
+# $Date: 1998/07/08 06:39:13 $
# Original Version from Smalltalk-80 version
# on July 23, 1985 at 8:37:17 am
# by Keiju ISHITSUKA
@@ -20,6 +21,150 @@
# column: 列
# row: 行
#
+# module ExceptionForMatrix::
+# Exceptions:
+# ErrDimensionMismatch
+# 行または列数が一致していない.
+# ErrNotRegular
+# 正則行列でない.
+# ErrOperationNotDefined
+# その演算子はまだ定義されていない.
+#
+# class Matrix
+# include ExceptionForMatrix
+#
+# Methods:
+# class methods:
+# Matrix.[](*rows)
+# rowsで渡された行列を生成する. rowsは配列の配列
+# Matrix[[11, 12], [21, 22]]
+# Matrix.rows(rows, copy = TRUE)
+# rowsを行ベクトルの集合として行列を生成する. copy=FALSE の
+# 時はその配列をそのまま用いる.
+# Matrix.columns(columns)
+# rowsを列ベクトルの集合として行列を生成する.
+# Matrix.diagonal(*values)
+# valuesを対角成分とした対角行列を生成する.
+# Matrix.scalar(n, value)
+# valueを対角成分とするn次ののスカラー行列を生成する.
+# Matrix.identity(n)
+# Matrix.unit(n)
+# Matrix.I(n)
+# n次の単位行列を生成する.
+# Matrix.zero(n)
+# n次の0-行列を生成する.
+# Matrix.row_vector(row)
+# rowを行ベクトルとする1-n行列を生成する. rowはVectorかArray
+# が可能.
+# Matrix.column_vector(column)
+# columnを列ベクトルとするn-1行列を生成する. rowはVectorかArray
+# が可能.
+# accessing:
+# [](i, j)
+# 行列の(i, j)成分を返す.
+# row_size
+# 行数を返す.
+# column_size
+# 列数を返す.
+# row(i)
+# i番目の行ベクトルを返す. イテレータとして使われた時は, 行
+# ベクトルを順番にイテーレータブロックに渡す.
+# column(j)
+# j番目の列ベクトルを返す. 列ベクトルを順番にイテーレータブ
+# ロックに渡す.
+# collect
+# map
+# 全ての要素をイテレートしその戻り値を値とする行列を新たに生
+# 成する.
+# minor(*param)
+# マイナー行列を返す. パラメータとしては, 以下のパターンがあ
+# る:
+# 1. from_row, row_size, from_col, size_col
+# 2. from_row..to_row, from_col..to_col
+# TESTING:
+# regular?
+# 正則かどうか?
+# singular?
+# 正則ではないかどうか?
+# square?
+# 正方行列かどうか?
+# ARITHMETIC:
+# *(m)
+# 乗法
+# +(m)
+# 加法
+# -(m)
+# 減法
+# /(m)
+# self * m.inv
+# inverse
+# inv
+# 逆行列
+# **
+# 冪乗
+# Matrix functions:
+# determinant
+# det
+# 行列式
+# rank
+# ランク
+# trace
+# tr
+# トレース
+# transpose
+# t
+# 転置行列
+# CONVERTING:
+# coerce(other)
+# row_vectors
+# rowベクトルの配列
+# column_vectors
+# columベクトルの配列
+# to_a
+# (2重)配列に変換
+# to_f
+# 各要素をFloatに変換
+# to_i
+# 各要素をIntegerに変換
+# to_r
+# 各要素をRationalに変換
+# PRINTING:
+# to_s
+# 文字列としての表現
+# inspect
+#
+# class Vector
+# include ExceptionForMatrix
+#
+# INSTANCE CREATION:
+# Vector.[](*array)
+# Vector.elements(array, copy = TRUE)
+# ACCSESSING:
+# [](i)
+# size
+# ENUMRATIONS:
+# each2(v)
+# collect2(v)
+# ARITHMETIC:
+# *(x) "is matrix or number"
+# +(v)
+# -(v)
+# VECTOR FUNCTIONS:
+# inner_product(v)
+# collect
+# map
+# map2(v)
+# r
+# CONVERTING:
+# covector
+# to_a
+# to_f
+# to_i
+# to_r
+# coerce(other)
+# PRINTING:
+# to_s
+# inspect
require "e2mmap.rb"
@@ -35,7 +180,7 @@ module ExceptionForMatrix
end
class Matrix
- RCS_ID='-$Header: matrix.rb,v 1.2 91/04/20 17:24:57 keiju Locked $-'
+ @RCS_ID='-$Id: matrix.rb,v 1.4 1998/07/08 06:39:13 keiju Exp keiju $-'
include ExceptionForMatrix
@@ -143,6 +288,7 @@ class Matrix
if iterator?
for e in @rows[i]
yield e
+
end
else
Vector.elements(@rows[i])
@@ -210,6 +356,38 @@ class Matrix
column_size == row_size
end
+ # COMPARING
+ def ==(other)
+ return FALSE unless Matrix === other
+
+ other.compare_by_row_vectors(@rows)
+ end
+ alias eqn? ==
+
+ def compare_by_row_vectors(rows)
+ return FALSE unless @rows.size == rows.size
+
+ 0.upto(@rows.size - 1) do
+ |i|
+ return FALSE unless @rows[i] == rows[i]
+ end
+ TRUE
+ end
+
+ def clone
+ Matrix.rows(@rows)
+ end
+
+ def hash
+ value = 0
+ for row in @rows
+ for e in row
+ value ^= e.hash
+ end
+ end
+ return value
+ end
+
# ARITHMETIC
def *(m) #is matrix or vector or number"
@@ -296,6 +474,25 @@ class Matrix
}
Matrix.rows(rows, FALSE)
end
+
+ def /(other)
+ case other
+ when Numeric
+ rows = @rows.collect {
+ |row|
+ row.collect {
+ |e|
+ e / other
+ }
+ }
+ return Matrix.rows(rows, FALSE)
+ when Matrix
+ return self * other.inverse
+ else
+ x, y = other.coerce(self)
+ rerurn x / y
+ end
+ end
def inverse
Matrix.fail ErrDimensionMismatch unless square?
@@ -319,7 +516,7 @@ class Matrix
end
for i in 0 .. size
- next if i == k
+ continue if i == k
q = a[i][k] / akk
a[i][k] = 0
@@ -424,7 +621,7 @@ class Matrix
break
end
end while a[i][k] == 0
- next if nothing
+ continue if nothing
a[i], a[k] = a[k], a[i]
akk = a[k][k]
end
@@ -596,7 +793,6 @@ end
#----------------------------------------------------------------------
class Vector
include ExceptionForMatrix
-
#INSTANCE CREATION
@@ -648,6 +844,26 @@ class Vector
end
end
+ # COMPARING
+ def ==(other)
+ return FALSE unless Vector === other
+
+ other.compare_by(@elements)
+ end
+ alias eqn? ==
+
+ def compare_by(elements)
+ @elements == elements
+ end
+
+ def clone
+ Vector.elements(@rows)
+ end
+
+ def hash
+ @elements.hash
+ end
+
# ARITHMETIC
def *(x) "is matrix or number"
@@ -732,7 +948,7 @@ class Vector
for e in @elements
v += e*e
end
- return v.sqrt
+ return Math.sqrt(v)
end
# CONVERTING
diff --git a/lib/singleton.rb b/lib/singleton.rb
new file mode 100644
index 0000000000..8167a01aa8
--- /dev/null
+++ b/lib/singleton.rb
@@ -0,0 +1,37 @@
+# Singleton module that ensures only one object to be allocated.
+#
+# Usage:
+# class SomeSingletonClass
+# include Singleton
+# #....
+# end
+# a = SomeSingletonClass.instance
+# b = SomeSingletonClass.instance # a and b are same object
+# p [a,b]
+# a = SomeSingletonClass.new # error (`new' is private)
+
+module Singleton
+ def Singleton.append_features(klass)
+ klass.private_class_method(:new)
+ klass.instance_eval %{
+ def instance
+ unless @__instance__
+ @__instance__ = new
+ end
+ return @__instance__
+ end
+ }
+ end
+end
+
+if __FILE__ == $0
+ class SomeSingletonClass
+ include Singleton
+ #....
+ end
+
+ a = SomeSingletonClass.instance
+ b = SomeSingletonClass.instance # a and b are same object
+ p [a,b]
+ a = SomeSingletonClass.new # error (`new' is private)
+end
diff --git a/lib/telnet.rb b/lib/telnet.rb
index 44fda9e41a..d9c72f65b2 100644
--- a/lib/telnet.rb
+++ b/lib/telnet.rb
@@ -1,65 +1,103 @@
#
# telnet.rb
-# ver0.11 1998/04/21
+# ver0.12 1998/06/01
# Wakou Aoyama <wakou@fsinet.or.jp>
#
# == make new Telnet object
-# host = Telnet.new("Binmode" => TRUE, default: TRUE
-# "Host" => "localhost", default: "localhost"
-# "Output_log" => "output_log", default: not output
-# "Port" => 23, default: 23
-# "Prompt" => /[$%#>] $/, default: /[$%#>] $/
-# "Telnetmode" => TRUE, default: TRUE
-# "Timeout" => 10) default: 10
+# host = Telnet.new({"Binmode" => TRUE, default: TRUE
+# "Host" => "localhost", default: "localhost"
+# "Output_log" => "output_log", default: not output
+# "Port" => 23, default: 23
+# "Prompt" => /[$%#>] $/, default: /[$%#>] $/
+# "Telnetmode" => TRUE, default: TRUE
+# "Timeout" => 10, default: 10
+# "Waittime" => 0}) default: 0
#
# if set "Telnetmode" option FALSE. not TELNET command interpretation.
+# "Waittime" is time to confirm "Prompt". There is a possibility that
+# the same character as "Prompt" is included in the data, and, when
+# the network or the host is very heavy, the value is enlarged.
#
# == wait for match
-# print host.waitfor(/match/)
-# print host.waitfor("Match" => /match/,
-# "String" => "string",
-# "Timeout" => secs)
+# line = host.waitfor(/match/)
+# line = host.waitfor({"Match" => /match/,
+# "String" => "string",
+# "Timeout" => secs})
# if set "String" option. Match = Regexp.new(quote(string))
#
# realtime output. of cource, set sync=TRUE or flush is necessary.
# host.waitfor(/match/){|c| print c }
-# host.waitfor("Match" => /match/,
-# "String" => "string",
-# "Timeout" => secs){|c| print c}
+# host.waitfor({"Match" => /match/,
+# "String" => "string",
+# "Timeout" => secs}){|c| print c}
#
# == send string and wait prompt
-# print host.cmd("string")
-# print host.cmd("String" => "string",
-# "Prompt" => /[$%#>] $//,
-# "Timeout" => 10)
+# line = host.cmd("string")
+# line = host.cmd({"String" => "string",
+# "Prompt" => /[$%#>] $//,
+# "Timeout" => 10})
#
# realtime output. of cource, set sync=TRUE or flush is necessary.
# host.cmd("string"){|c| print c }
-# host.cmd("String" => "string",
-# "Prompt" => /[$%#>] $//,
-# "Timeout" => 10){|c| print c }
+# host.cmd({"String" => "string",
+# "Prompt" => /[$%#>] $//,
+# "Timeout" => 10}){|c| print c }
#
# == login
# host.login("username", "password")
-# host.login("Name" => "username",
-# "Password" => "password",
-# "Prompt" => /[$%#>] $/,
-# "Timeout" => 10)
+# host.login({"Name" => "username",
+# "Password" => "password",
+# "Prompt" => /[$%#>] $/,
+# "Timeout" => 10})
+#
+# realtime output. of cource, set sync=TRUE or flush is necessary.
+# host.login("username", "password"){|c| print c }
+# host.login({"Name" => "username",
+# "Password" => "password",
+# "Prompt" => /[$%#>] $/,
+# "Timeout" => 10}){|c| print c }
#
# and Telnet object has socket class methods
#
# == sample
-# localhost = Telnet.new("Host" => "localhost",
-# "Timeout" => 10,
-# "Prompt" => /[$%#>] $/)
-# localhost.login("username", "password")
-# print localhost.cmd("command")
+# localhost = Telnet.new({"Host" => "localhost",
+# "Timeout" => 10,
+# "Prompt" => /[$%#>] $/})
+# localhost.login("username", "password"){|c| print c }
+# localhost.cmd("command"){|c| print c }
# localhost.close
require "socket"
require "delegate"
+require "thread"
+
+class TimeOut < Exception
+end
class Telnet < SimpleDelegator
+
+ def timeout(sec)
+ is_timeout = FALSE
+ begin
+ x = Thread.current
+ y = Thread.start {
+ sleep sec
+ if x.alive?
+ #print "timeout!\n"
+ x.raise TimeOut, "timeout"
+ end
+ }
+ begin
+ yield
+ rescue TimeOut
+ is_timeout = TRUE
+ end
+ ensure
+ Thread.kill y if y && y.alive?
+ end
+ is_timeout
+ end
+
# For those who are curious, here are some of the special characters
# interpretted by the telnet protocol:
# Name Octal Dec. Description
@@ -85,29 +123,41 @@ class Telnet < SimpleDelegator
# EOR = "\357" # 239 /* end of record (transparent mode) */
def initialize(options)
- @options = {}
- @options["Binmode"] = options["Binmode"] || TRUE
- @options["Dump_Log"] = options["Dump_Log"]
- @options["Errmode"] = options["Errmode"]
- @options["Fhopen"] = options["Fhopen"]
- @options["Host"] = options["Host"] || "localhost"
- @options["Input_log"] = options["Input_log"]
- @options["Input_record_separator"] = options["Input_record_separator"]
- @options["Output_log"] = options["Output_log"]
- @options["Output_record_separator"] = options["Output_record_separator"]
- @options["Port"] = options["Port"] || 23
- @options["Prompt"] = options["Prompt"] || /[$%#>] $/
- @options["Telnetmode"] = options["Telnetmode"] || TRUE
- @options["Timeout"] = options["Timeout"] || 10
+ @options = options
+ @options["Binmode"] = TRUE if not @options.include?("Binmode")
+ @options["Host"] = "localhost" if not @options.include?("Host")
+ @options["Port"] = 23 if not @options.include?("Port")
+ @options["Prompt"] = /[$%#>] $/ if not @options.include?("Prompt")
+ @options["Telnetmode"] = TRUE if not @options.include?("Telnetmode")
+ @options["Timeout"] = 10 if not @options.include?("Timeout")
+ @options["Waittime"] = 0 if not @options.include?("Waittime")
if @options.include?("Output_log")
@log = File.open(@options["Output_log"], 'a+')
@log.sync = TRUE
@log.binmode if @options["Binmode"]
end
- @sock = TCPsocket.open(@options["Host"], @options["Port"])
+
+ message = "Trying " + @options["Host"] + "...\n"
+ STDOUT << message
+ @log << message if @options.include?("Output_log")
+
+ is_timeout = timeout(@options["Timeout"]){
+ begin
+ @sock = TCPsocket.open(@options["Host"], @options["Port"])
+ rescue
+ @log << $! << "\n" if @options.include?("Output_log")
+ raise
+ end
+ }
+ raise TimeOut, "timed-out; opening of the host" if is_timeout
@sock.sync = TRUE
@sock.binmode if @options["Binmode"]
+
+ message = "Connected to " + @options["Host"] + ".\n"
+ STDOUT << message
+ @log << message if @options.include?("Output_log")
+
super(@sock)
end
@@ -133,48 +183,54 @@ class Telnet < SimpleDelegator
end
def waitfor(options)
- prompt = @options["Prompt"]
- timeout = @options["Timeout"]
+ timeout = @options["Timeout"]
+ waittime = @options["Waittime"]
+
if options.kind_of?(Hash)
- prompt = options["Prompt"] if options.include?("Prompt")
- timeout = options["Timeout"] if options.include?("Timeout")
- prompt = Regexp.new( Regexp.quote(options["String"]) ) if
+ prompt = options["Prompt"] if options.include?("Prompt")
+ timeout = options["Timeout"] if options.include?("Timeout")
+ waittime = options["Waittime"] if options.include?("Waittime")
+ prompt = Regexp.new( Regexp.quote(options["String"]) ) if
options.include?("String")
else
prompt = options
end
+
line = ''
- while (not prompt === line and not @sock.closed?)
- next if not select([@sock], nil, nil, timeout)
+ until(not select([@sock], nil, nil, waittime) and prompt === line)
+ raise TimeOut, "timed-out; wait for the next data" if
+ not select([@sock], nil, nil, timeout)
+ buf = ''
begin
buf = if @options["Telnetmode"]
preprocess( @sock.sysread(1024 * 1024) )
else
@sock.sysread(1024 * 1024)
end
- rescue
- buf = "\nConnection closed by foreign host.\n"
- @sock.close
- end
- @log.print(buf) if @options.include?("Output_log")
- if iterator?
- yield buf
+ rescue EOFError # End of file reached
+ break
+ ensure
+ @log.print(buf) if @options.include?("Output_log")
+ yield buf if iterator?
+ line += buf
end
- line += buf
end
line
end
def cmd(options)
- match = @options["Prompt"]
+ match = @options["Prompt"]
timeout = @options["Timeout"]
+
if options.kind_of?(Hash)
- string = options["String"]
- match = options["Match"] if options.include?("Match")
+ string = options["String"]
+ match = options["Match"] if options.include?("Match")
timeout = options["Timeout"] if options.include?("Timeout")
else
string = options
end
+
+ select(nil, [@sock])
@sock << string.gsub(/\n/, CR) << CR
if iterator?
waitfor({"Prompt" => match, "Timeout" => timeout}){|c| yield c }
@@ -183,7 +239,7 @@ class Telnet < SimpleDelegator
end
end
- def login(options, password = nil)
+ def login(options, password = '')
if options.kind_of?(Hash)
username = options["Name"]
password = options["Password"]
@@ -191,9 +247,17 @@ class Telnet < SimpleDelegator
username = options
end
- line = waitfor(/login[: ]*$/)
- line += cmd({"String" => username, "Match" => /Password[: ]*$/})
- line += cmd(password)
+ if iterator?
+ line = waitfor(/login[: ]*$/){|c| yield c }
+ line += cmd({"String" => username,
+ "Match" => /Password[: ]*$/}){|c| yield c }
+ line += cmd(password){|c| yield c }
+ else
+ line = waitfor(/login[: ]*$/)
+ line += cmd({"String" => username,
+ "Match" => /Password[: ]*$/})
+ line += cmd(password)
+ end
line
end
diff --git a/lib/tk.rb b/lib/tk.rb
index 287bda62af..34f42ac390 100644
--- a/lib/tk.rb
+++ b/lib/tk.rb
@@ -257,25 +257,67 @@ module TkComm
end
end
- def _bind(path, context, cmd, args=nil)
+ def tk_event_sequence(context)
context = context.join("><") if context.kind_of? Array
if /,/ =~ context
context = context.split(/\s*,\s*/).join("><")
+ else
+ context
end
+ end
+
+ def _bind_core(mode, path, context, cmd, args=nil)
id = install_bind(cmd, args)
begin
- tk_call 'bind', path, "<#{context}>", id
+ tk_call 'bind', path, "<#{tk_event_sequence(context)}>", mode + id
rescue
uninstall_cmd(id)
fail
end
end
- private :install_bind, :_bind
+
+ def _bind(path, context, cmd, args=nil)
+ _bind_core('', path, context, cmd, args=nil)
+ end
+
+ def _bind_append(path, context, cmd, args=nil)
+ _bind_core('+', path, context, cmd, args=nil)
+ end
+ private :install_bind, :tk_event_sequence, :_bind_core, :_bind, :_bind_append
def bind_all(context, cmd=Proc.new, args=nil)
_bind 'all', context, cmd, args
end
+ def bind_append_all(context, cmd=Proc.new, args=nil)
+ _bind_append 'all', context, cmd, args
+ end
+
+ def bind(tagOrClass, context, cmd=Proc.new, args=nil)
+ _bind tagOrClass, context, cmd, args
+ end
+
+ def bind_append(tagOrClass, context, cmd=Proc.new, args=nil)
+ _bind_append tagOrClass, context, cmd, args
+ end
+
+ def bindinfo(tagOrClass, context=nil)
+ if context
+ (tk_call('bind', tagOrClass,
+ "<#{tk_event_sequence(context)}>")).collect{|cmdline|
+ if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
+ [Tk_CMDTBL[$1], $2]
+ else
+ cmdline
+ end
+ }
+ else
+ tk_split_list(tk_call 'bind', tagOrClass).collect{|seq|
+ seq[1..-2].gsub(/></,',')
+ }
+ end
+ end
+
def pack(*args)
TkPack.configure *args
end
@@ -299,7 +341,16 @@ module TkCore
extend TkComm
INTERP = TclTkIp.new
- INTERP._invoke("proc", "rb_out", "args", "ruby [format \"TkCore.callback %%Q!%s!\" $args]")
+
+ INTERP._invoke("proc", "rb_out", "args", "if {[set st [catch {ruby [format \"TkCore.callback %%Q!%s!\" $args]} ret]] != 0} {return -code $st $ret} {return $ret}")
+
+ def callback_break
+ raise TkCallbackBreak, "Tk callback returns 'break' status"
+ end
+
+ def callback_continue
+ raise TkCallbackContinue, "Tk callback returns 'continue' status"
+ end
def after(ms, cmd=Proc.new)
myid = _curr_cmd_id
@@ -324,6 +375,39 @@ module TkCore
_get_eval_string(TkUtil.eval_cmd(Tk_CMDTBL[arg.shift], *arg))
end
+ def appname(name=None)
+ tk_call('tk', 'appname', name)
+ end
+
+ def appsend(interp, async, *args)
+ if async
+ tk_call('send', '-async', '--', interp, *args)
+ else
+ tk_call('send', '--', interp, *args)
+ end
+ end
+
+ def rb_appsend(interp, async, *args)
+ args.unshift('ruby {')
+ args.push('}')
+ appsend(interp, async, *args)
+ end
+
+ def appsend_displayof(interp, win, async, *args)
+ win = '.' if win == nil
+ if async
+ tk_call('send', '-async', '-displayof', win, '--', interp, *args)
+ else
+ tk_call('send', '-displayor', win, '--', interp, *args)
+ end
+ end
+
+ def rb_appsend_displayof(interp, win, async, *args)
+ args.unshift('ruby {')
+ args.push('}')
+ appsend_displayof(interp, win, async, *args)
+ end
+
def mainloop
TclTkLib.mainloop
end
@@ -478,8 +562,22 @@ end
class TkVariable
include Tk
+ extend TkCore
+ TkVar_CB_TBL = {}
Tk_VARIABLE_ID = ["v00000"]
+
+ INTERP._invoke("proc", "rb_var", "args", "ruby [format \"TkVariable.callback %%Q!%s!\" $args]")
+
+ def TkVariable.callback(args)
+ name1,name2,op = tk_split_list(args)
+ if TkVar_CB_TBL[name1]
+ _get_eval_string(TkVar_CB_TBL[name1].trace_callback(name2,op))
+ else
+ ''
+ end
+ end
+
def initialize(val="")
@id = Tk_VARIABLE_ID[0]
Tk_VARIABLE_ID[0] = Tk_VARIABLE_ID[0].succ
@@ -487,11 +585,13 @@ class TkVariable
INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)',
@id, @id, @id))
elsif val.kind_of?(Array)
- s = '"' + array2tk_list(val).gsub(/[][$"]/, '\\\\\&') + '"' #'
- INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
+ a = []
+ val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))}
+ s = '"' + a.join(" ").gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
elsif val.kind_of?(Hash)
s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
- ..gsub(/[][$"]/, '\\\\\&') + '"' #'
+ .gsub(/[][$"]/, '\\\\\&') + '"' #'
INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
else
s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' #'
@@ -514,14 +614,16 @@ class TkVariable
if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1"
raise
else
- INTERP._eval(format('global %s; array get %s', @id, @id))
+ Hash(*tk_tcl2ruby(INTERP._eval(format('global %s; array get %s',
+ @id, @id))))
end
end
end
def value=(val)
begin
- INTERP._eval(format('global %s; set %s %s', @id, @id, _get_eval_string(val)))
+ s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; set %s %s', @id, @id, s))
rescue
if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1"
raise
@@ -531,12 +633,16 @@ class TkVariable
INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)',
@id, @id, @id))
elsif val.kind_of?(Array)
- s = '"' + array2tk_list(val).gsub(/[][$"]/, '\\\\\&') + '"' #'
- INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
+ a = []
+ val.each_with_index{|e,i| a.push(i); a.push(array2tk_list(e))}
+ s = '"' + a.join(" ").gsub(/[][$"]/, '\\\\\&') + '"' #'
+ INTERP._eval(format('global %s; unset %s; array set %s %s',
+ @id, @id, @id, s))
elsif val.kind_of?(Hash)
s = '"' + val.to_a.collect{|e| array2tk_list(e)}.join(" ")\
.gsub(/[][$"]/, '\\\\\&') + '"' #'
- INTERP._eval(format('global %s; array set %s %s', @id, @id, s))
+ INTERP._eval(format('global %s; unset %s; array set %s %s',
+ @id, @id, @id, s))
else
raise
end
@@ -594,6 +700,147 @@ class TkVariable
def to_eval
@id
end
+
+ def unset(elem=nil)
+ if elem
+ INTERP._eval(format('global %s; unset %s(%s)',
+ @id, @id, tk_tcl2ruby(elem)))
+ else
+ INTERP._eval(format('global %s; unset %s', @id, @id))
+ end
+ end
+ alias remove unset
+
+ def trace_callback(elem, op)
+ if @trace_var.kind_of? Array
+ @trace_var.each{|m,e| e.call(self,elem,op) if m.index(op)}
+ end
+ if elem.kind_of? String
+ if @trace_elem[elem].kind_of? Array
+ @trace_elem[elem].each{|m,e| e.call(self,elem,op) if m.index(op)}
+ end
+ end
+ end
+
+ def trace(opts, cmd)
+ @trace_var = [] if @trace_var == nil
+ opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+ @trace_var.unshift([opts,cmd])
+ if @trace_opts == nil
+ TkVar_CB_TBL[@id] = self
+ @trace_opts = opts
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ else
+ newopts = @trace_opts.dup
+ opts.each_byte{|c| newopts += c.chr unless @newopts.index(c)}
+ if newopts != @trace_opts
+ Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
+ @trace_opts.replace(newopts)
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ end
+ end
+ end
+
+ def trace_element(elem, opts, cmd)
+ @trace_elem = {} if @trace_elem == nil
+ @trace_elem[elem] = [] if @trace_elem[elem] == nil
+ opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+ @trace_elem[elem].unshift([opts,cmd])
+ if @trace_opts == nil
+ TkVar_CB_TBL[@id] = self
+ @trace_opts = opts
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ else
+ newopts = @trace_opts.dup
+ opts.each_byte{|c| newopts += c.chr unless @newopts.index(c)}
+ if newopts != @trace_opts
+ Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
+ @trace_opts.replace(newopts)
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ end
+ end
+ end
+
+ def trace_vinfo
+ return [] unless @trace_var
+ @trace_var.dup
+ end
+ def trace_vinfo_for_element(elem)
+ return [] unless @trace_elem
+ return [] unless @trace_elem[elem]
+ @trace_elem[elem].dup
+ end
+
+ def trace_vdelete(opts,cmd)
+ return unless @trace_var.kind_of? Array
+ opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+ idx = -1
+ newopts = ''
+ @trace_var.each_with_index{|i,e|
+ if idx < 0 && e[0] == opts && e[1] == cmd
+ idx = i
+ continue
+ end
+ e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
+ }
+ if idx >= 0
+ @trace_var.delete_at(idx)
+ else
+ return
+ end
+
+ @trace_elem.each{|elem|
+ @trace_elem[elem].each{|e|
+ e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
+ }
+ }
+
+ newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('')
+ if newopts != @trace_opts
+ Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
+ @trace_opts.replace(newopts)
+ if @trace_opts != ''
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ end
+ end
+ end
+
+ def trace_vdelete_for_element(elem,opts,cmd)
+ return unless @trace_elem.kind_of? Hash
+ return unless @trace_elem[elem].kind_of? Array
+ opts = ['r','w','u'].find_all{|c| opts.index(c)}.join('')
+ idx = -1
+ @trace_elem[elem].each_with_index{|i,e|
+ if idx < 0 && e[0] == opts && e[1] == cmd
+ idx = i
+ continue
+ end
+ }
+ if idx >= 0
+ @trace_elem[elem].delete_at(idx)
+ else
+ return
+ end
+
+ newopts = ''
+ @trace_var.each{|e|
+ e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
+ }
+ @trace_elem.each{|elem|
+ @trace_elem[elem].each{|e|
+ e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
+ }
+ }
+
+ newopts = ['r','w','u'].find_all{|c| newopts.index(c)}.join('')
+ if newopts != @trace_opts
+ Tk.tk_call('trace', 'vdelete', @id, @trace_opts, 'rb_var')
+ @trace_opts.replace(newopts)
+ if @trace_opts != ''
+ Tk.tk_call('trace', 'variable', @id, @trace_opts, 'rb_var')
+ end
+ end
+ end
end
class TkVarAccess<TkVariable
@@ -633,6 +880,68 @@ module TkSelection
module_function :clear, :get
end
+module TkKinput
+ include Tk
+ extend Tk
+
+ def TkKinput.start(window, style=None)
+ tk_call 'kinput_start', window.path, style
+ end
+ def kinput_start(style=None)
+ TkKinput.start(self, style)
+ end
+
+ def TkKinput.send_spot(window)
+ tk_call 'kinput_send_spot', window.path
+ end
+ def kinput_send_spot
+ TkKinput.send_spot(self)
+ end
+
+ def TkKinput.input_start(window, keys=nil)
+ tk_call 'kanjiInput', 'start', window.path, *hash_kv(keys)
+ end
+ def kanji_input_start(keys=nil)
+ TkKinput.input_start(self, keys)
+ end
+
+ def TkKinput.attribute_config(window, slot, value=None)
+ if slot.kind_of? Hash
+ tk_call 'kanjiInput', 'attribute', window.path, *hash_kv(slot)
+ else
+ tk_call 'kanjiInput', 'attribute', window.path, "-#{slot}", value
+ end
+ end
+ def kinput_attribute_config(slot, value=None)
+ TkKinput.attribute_config(self, slot, value)
+ end
+
+ def TkKinput.attribute_info(window, slot=nil)
+ if slot
+ conf = tk_split_list(tk_call('kanjiInput', 'attribute',
+ window.path, "-#{slot}"))
+ conf[0] = conf[0][1..-1]
+ conf
+ else
+ tk_split_list(tk_call('kanjiInput', 'attribute',
+ window.path)).collect{|conf|
+ conf[0] = conf[0][1..-1]
+ conf
+ }
+ end
+ end
+ def kinput_attribute_info(slot=nil)
+ TkKinput.attribute_info(self, slot)
+ end
+
+ def TkKinput.input_end(window)
+ tk_call 'kanjiInput', 'end', window.path
+ end
+ def kanji_input_end
+ TkKinput.input_end(self)
+ end
+end
+
module TkWinfo
include Tk
extend Tk
@@ -690,7 +999,7 @@ module TkWinfo
number(tk_call('winfo', 'fpixels', window.path, number))
end
def winfo_fpixels(number)
- TkWinfo.fpixels self
+ TkWinfo.fpixels self, number
end
def TkWinfo.geometry(window)
list(tk_call('winfo', 'geometry', window.path))
@@ -710,6 +1019,29 @@ module TkWinfo
def winfo_id
TkWinfo.id self
end
+ def TkWinfo.interps(window=nil)
+ if window
+ tk_split_list(tk_call('winfo', '-displayof', window.path,
+ 'interps')).collect{|ip|
+ if ip.kind_of? Array
+ ip.flatten.join(' ')
+ else
+ ip
+ end
+ }
+ else
+ tk_split_list(tk_call('winfo', 'interps')).collect{|ip|
+ if ip.kind_of? Array
+ ip.flatten.join(' ')
+ else
+ ip
+ end
+ }
+ end
+ end
+ def winfo_interps
+ TkWinfo.interps self
+ end
def TkWinfo.mapped?(window)
bool(tk_call('winfo', 'ismapped', window.path))
end
@@ -1053,6 +1385,10 @@ class TkObject<TkKernel
_bind path, context, cmd, args
end
+ def bind_append(context, cmd=Proc.new, args=nil)
+ _bind_append path, context, cmd, args
+ end
+
def tk_trace_variable(v)
unless v.kind_of?(TkVariable)
fail ArgumentError, format("requires TkVariable given %s", v.type)
@@ -1066,7 +1402,28 @@ class TkObject<TkKernel
end
end
+module TkClassBind
+ WidgetClassNameTBL = {}
+
+ def TkClassBind.name2class(name)
+ WidgetClassNameTBL[name]
+ end
+
+ def bind(context, cmd=Proc.new, args=nil)
+ Tk.bind to_eval, context, cmd, args
+ end
+
+ def bind_append(context, cmd=Proc.new, args=nil)
+ Tk.bind_append to_eval, context, cmd, args
+ end
+
+ def bindinfo(context=nil)
+ Tk.bind to_eval, context
+ end
+end
+
class TkWindow<TkObject
+ extend TkClassBind
def initialize(parent=nil, keys=nil)
install_win(if parent then parent.path end)
@@ -1203,6 +1560,23 @@ class TkWindow<TkObject
def wait_destroy
tk_call 'tkwait', 'window', path
end
+
+ def bindtags(taglist=nil)
+ if taglist
+ fail unless taglist.kind_of? Array
+ tk_call('bindtags', path, taglist)
+ else
+ tk_split_list(tk_call('bindtags', path)).collect{|tag|
+ if tag == nil
+ '.'
+ elsif tag.kind_of?(String) && (cls = TkClassBind.name2class(tag))
+ cls
+ else
+ tag
+ end
+ }
+ end
+ end
end
class TkRoot<TkWindow
@@ -1214,6 +1588,13 @@ class TkRoot<TkWindow
ROOT[0] = new
Tk_WINDOWS["."] = new
end
+
+ WidgetClassName = 'Tk'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
def create_self
@path = '.'
end
@@ -1224,6 +1605,13 @@ end
class TkToplevel<TkWindow
include Wm
+
+ WidgetClassName = 'Toplevel'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
def initialize(parent=nil, screen=nil, classname=nil, keys=nil)
@screen = screen if screen
@classname = classname if classname
@@ -1236,15 +1624,29 @@ class TkToplevel<TkWindow
s.push "-class #@classname" if @classname
tk_call 'toplevel', path, *s
end
+
+ def specific_class
+ @classname
+ end
end
class TkFrame<TkWindow
+ WidgetClassName = 'Frame'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
def create_self
tk_call 'frame', @path
end
end
class TkLabel<TkWindow
+ WidgetClassName = 'Label'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
def create_self
tk_call 'label', @path
end
@@ -1254,6 +1656,12 @@ class TkLabel<TkWindow
end
class TkButton<TkLabel
+ WidgetClassName = 'Button'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+# def TkButton.to_eval
+ def self.to_eval
+ WidgetClassName
+ end
def create_self
tk_call 'button', @path
end
@@ -1266,6 +1674,11 @@ class TkButton<TkLabel
end
class TkRadioButton<TkButton
+ WidgetClassName = 'Radiobutton'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def TkRadioButton.to_eval
+ WidgetClassName
+ end
def create_self
tk_call 'radiobutton', @path
end
@@ -1281,6 +1694,10 @@ class TkRadioButton<TkButton
end
class TkCheckButton<TkRadioButton
+ TkClassBind::WidgetClassNameTBL['Checkbutton'] = self
+ def TkCheckButton.to_eval
+ 'Checkbutton'
+ end
def create_self
tk_call 'checkbutton', @path
end
@@ -1290,12 +1707,22 @@ class TkCheckButton<TkRadioButton
end
class TkMessage<TkLabel
+ TkClassBind::WidgetClassNameTBL['Message'] = self
+ def TkMessage.to_eval
+ 'Message'
+ end
def create_self
tk_call 'message', @path
end
end
class TkScale<TkWindow
+ WidgetClassName = 'Scale'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
def create_self
tk_call 'scale', path
end
@@ -1318,6 +1745,12 @@ class TkScale<TkWindow
end
class TkScrollbar<TkWindow
+ WidgetClassName = 'Scrollbar'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
def create_self
tk_call 'scrollbar', path
end
@@ -1380,6 +1813,10 @@ class TkTextWin<TkWindow
end
class TkListbox<TkTextWin
+ TkClassBind::WidgetClassNameTBL['Listbox'] = self
+ def TkListbox.to_eval
+ 'Listbox'
+ end
def create_self
tk_call 'listbox', path
end
@@ -1419,6 +1856,11 @@ class TkListbox<TkTextWin
end
class TkMenu<TkWindow
+ WidgetClassName = 'Menu'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
def create_self
tk_call 'menu', path
end
@@ -1461,6 +1903,10 @@ class TkMenu<TkWindow
end
class TkMenubutton<TkLabel
+ TkClassBind::WidgetClassNameTBL['Menubutton'] = self
+ def TkMenubutton.to_eval
+ 'Menubutton'
+ end
def create_self
tk_call 'menubutton', path
end
diff --git a/lib/tkcanvas.rb b/lib/tkcanvas.rb
index 1d4c4c583a..4ee0c3cd48 100644
--- a/lib/tkcanvas.rb
+++ b/lib/tkcanvas.rb
@@ -8,6 +8,12 @@
require "tk"
class TkCanvas<TkWindow
+ WidgetClassName = 'Canvas'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
def create_self
tk_call 'canvas', path
end
@@ -51,13 +57,9 @@ class TkCanvas<TkWindow
end
def itembind(tag, context, cmd=Proc.new, args=nil)
- context = context.join("><") if context.kind_of? Array
- if /,/ =~ context
- context = context.split(/\s*,\s*/).join("><")
- end
id = install_bind(cmd, args)
begin
- tk_send 'bind', tagid(tag), "<#{context}>", id
+ tk_send 'bind', tagid(tag), "<#{tk_event_sequence(context)}>", id
rescue
uninstall_cmd(cmd)
fail
@@ -65,6 +67,23 @@ class TkCanvas<TkWindow
# @cmdtbl.push id
end
+ def itembindinfo(tag, context=nil)
+ if context
+ (tk_send('bind', tagid(tag),
+ "<#{tk_event_sequence(context)}>")).collect{|cmdline|
+ if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
+ [Tk_CMDTBL[$1], $2]
+ else
+ cmdline
+ end
+ }
+ else
+ tk_split_list(tk_send 'bind', tagid(tag)).filter{|seq|
+ seq[1..-2].gsub(/></,',')
+ }
+ end
+ end
+
def canvasx(x, *args)
tk_tcl2ruby(tk_send 'canvasx', x, *args)
end
@@ -252,6 +271,10 @@ module TkcTagAccess
@c.itembind @id, seq, cmd, args
end
+ def bindinfo(seq=nil)
+ @c.itembindinfo @id, seq
+ end
+
def cget(option)
@c.itemcget @id, option
end
diff --git a/lib/tkentry.rb b/lib/tkentry.rb
index 645fc997b1..b834c455c6 100644
--- a/lib/tkentry.rb
+++ b/lib/tkentry.rb
@@ -6,6 +6,12 @@
require 'tk.rb'
class TkEntry<TkLabel
+ WidgetClassName = 'Entry'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
+
def create_self
tk_call 'entry', @path
end
diff --git a/lib/tkfont.rb b/lib/tkfont.rb
new file mode 100644
index 0000000000..5e20359523
--- /dev/null
+++ b/lib/tkfont.rb
@@ -0,0 +1,556 @@
+class TkFont
+ include Tk
+ extend TkCore
+
+ Tk_FontID = [0]
+ Tk_FontNameTBL = {}
+ Tk_FontUseTBL = {}
+
+ DEFAULT_LATIN_FONT_NAME = 'a14'.freeze
+ DEFAULT_KANJI_FONT_NAME = 'k14'.freeze
+
+ ###################################
+ # class methods
+ ###################################
+ def TkFont.families(window=nil)
+ case (Tk::TK_VERSION)
+ when /^4.*/
+ ['fixed']
+
+ when /^8.*/
+ if window
+ list(tk_call('font', 'families', '-displayof', window))
+ else
+ list(tk_call('font', 'families'))
+ end
+ end
+ end
+
+ def TkFont.names
+ r = []
+ case (Tk::TK_VERSION)
+ when /^4.*/
+ r += ['fixed', 'a14', 'k14']
+ Tk_FontNameTBL.each_value{|obj| r.push(obj)}
+ when /^8.*/
+ list(tk_call('font', 'names')).each{|f|
+ if f =~ /^(@font[0-9]+)(c|l|k)$/
+ r.push(Tk_FontNameTBL[$1]) if $2 == 'c'
+ else
+ r.push(f)
+ end
+ }
+ end
+ r
+ end
+
+ ###################################
+ private
+ ###################################
+ def initialize(ltn=nil, knj=nil, keys=nil)
+ @id = format("@font%.4d", Tk_FontID[0])
+ Tk_FontID[0] += 1
+ Tk_FontNameTBL[@id] = self
+
+ ltn = DEFAULT_LATIN_FONT_NAME unless ltn
+ create_latinfont(ltn)
+
+ knj = DEFAULT_KANJI_FONT_NAME unless knj
+ create_kanjifont(knj)
+
+ create_compoundfont(keys)
+ end
+
+ def _get_font_info_from_hash(font)
+ foundry = (info = font['foundry'] .to_s)? info: '*'
+ family = (info = font['family'] .to_s)? info: '*'
+ weight = (info = font['weight'] .to_s)? info: '*'
+ slant = (info = font['slant'] .to_s)? info: '*'
+ swidth = (info = font['swidth'] .to_s)? info: '*'
+ adstyle = (info = font['adstyle'] .to_s)? info: '*'
+ pixels = (info = font['pixels'] .to_s)? info: '*'
+ points = (info = font['points'] .to_s)? info: '*'
+ resx = (info = font['resx'] .to_s)? info: '*'
+ resy = (info = font['resy'] .to_s)? info: '*'
+ space = (info = font['space'] .to_s)? info: '*'
+ avgWidth = (info = font['avgWidth'].to_s)? info: '*'
+ charset = (info = font['charset'] .to_s)? info: '*'
+ encoding = (info = font['encoding'].to_s)? info: '*'
+
+ Array([foundry, family, weight, slant, swidth, adstyle,
+ pixels, points, resx, resy, space, avgWidth, charset, encoding])
+ end
+
+ def create_latinfont_tk4x(font=nil)
+ if font.kind_of? Hash
+ @latinfont = '-' + _get_font_info_from_hash(font).join('-') + '-'
+
+ elsif font.kind_of? Array
+ finfo = {}
+ finfo['family'] = font[0].to_s
+ if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/
+ if $1 == '-'
+ finfo['pixels'] = font[1].to_s
+ else
+ finfo['points'] = font[1].to_s
+ end
+ end
+ finfo[2..-1].each{|style|
+ case (style)
+ when 'normal'
+ finfo['weight'] = style
+ when 'bold'
+ finfo['weight'] = style
+ when 'roman'
+ finfo['slant'] = 'r'
+ when 'italic'
+ finfo['slant'] = 'i'
+ end
+ }
+
+ @latinfont = '-' + _get_font_info_from_hash(finfo).join('-') + '-'
+
+ elsif font.kind_of? TkFont
+ @latinfont = font.latin_font
+
+ else
+ @latinfont = font
+
+ end
+ end
+
+ def create_kanjifont_tk4x(font=nil)
+ if font.kind_of? Hash
+ @kanjifont = '-' + _get_font_info_from_hash(font).join('-') + '-'
+
+ elsif font.kind_of? Array
+ finfo = {}
+ finfo['family'] = font[0].to_s
+ if font[1] && font[1] != '0' && font[1] =~ /^(|\+|-)([0-9]+)$/
+ if $1 == '-'
+ finfo['pixels'] = $2
+ else
+ finfo['points'] = $2
+ end
+ else
+ finfo['points'] = '13'
+ end
+ finfo[2..-1].each{|style|
+ case (style)
+ when 'normal'
+ finfo['weight'] = style
+ when 'bold'
+ finfo['weight'] = style
+ when 'roman'
+ finfo['slant'] = 'r'
+ when 'italic'
+ finfo['slant'] = 'i'
+ end
+ }
+
+ @kanjifont = '-' + _get_font_info_from_hash(finfo).join('-') + '-'
+
+ elsif font.kind_of? TkFont
+ @kanjifont = font.kanji_font
+
+ else
+ @kanjifont = font
+
+ end
+ end
+
+ def create_compoundfont_tk4x(keys)
+ @compoundfont = [[@latinfont], [@kanjifont]]
+ @fontslot = {'font'=>@latinfont, 'kanjifont'=>@kanjifont}
+ end
+
+ def create_latinfont_tk80(font=nil)
+ @latinfont = @id + 'l'
+
+ if font.kind_of? Hash
+ tk_call('font', 'create', @latinfont, *hash_kv(font))
+ elsif font.kind_of? Array
+ tk_call('font', 'create', @latinfont, '-copy', array2tk_list(font))
+ elsif font.kind_of? TkFont
+ tk_call('font', 'create', @latinfont, '-copy', font.latin_font)
+ else
+ tk_call('font', 'create', @latinfont, '-copy', font)
+ end
+ end
+
+ def create_kanjifont_tk80(font=nil)
+ @kanjifont = @id + 'k'
+
+ if font.kind_of? Hash
+ if font['charset']
+ tk_call('font', 'create', @kanjifont, *hash_kv(font))
+ else
+ tk_call('font', 'create', @kanjifont,
+ '-charset', 'jisx0208.1983', *hash_kv(font))
+ end
+ elsif font.kind_of? Array
+ tk_call('font', 'create', @kanjifont, '-copy', array2tk_list(font))
+ tk_call('font', 'configure', @kanjifont, '-charset', 'jisx0208.1983')
+
+ elsif font.kind_of? TkFont
+ tk_call('font', 'create', @kanjifont, '-copy', font.kanji_font)
+
+ else
+ tk_call('font', 'create', @kanjifont, '-copy', font,
+ '-charset', 'jisx0208.1983')
+
+ end
+ end
+
+ def create_compoundfont_tk80(keys)
+ @compoundfont = @id + 'c'
+ @fontslot = {'font'=>@compoundfont}
+ tk_call('font', 'create', @compoundfont,
+ '-compound', "#{@latinfont} #{@kanjifont}", *hash_kv(keys))
+ end
+
+ def set_font_core_tk4x(window)
+ Tk_FontUseTBL[window.path] = @id
+ window.configure(@fontslot)
+ end
+
+ def set_font_core_tk80(window)
+ window.configure(@fontslot)
+ end
+
+ def actual_core_tk4x(font, window=nil, option=nil)
+ # dummy
+ if option
+ ""
+ else
+ Array([ ['family',[]], ['size',[]], ['weight',[]], ['slant',[]],
+ ['underline',[]], ['overstrike',[]], ['charset',[]],
+ ['pointadjust',[]] ])
+ end
+ end
+
+ def actual_core_tk80(font, window=nil, option=nil)
+ if option == 'compound'
+ ""
+ elsif option
+ if window
+ tk_call('font', 'actual', font, "-#{option}")
+ else
+ tk_call('font', 'actual', font, "-displayof", window, "-#{option}")
+ end
+ else
+ l = tk_split_list(if window
+ tk_call('font', 'actual', font, "-displayof", window)
+ else
+ tk_call('font', 'actual', font)
+ end)
+ r = []
+ while key=l.shift
+ if key == '-compound'
+ l.shift
+ else
+ r.push [key[1..-1], l.shift]
+ end
+ end
+ r
+ end
+ end
+
+ def configure_core_tk4x(font, slot, value=None)
+ ""
+ end
+
+ def configinfo_core_tk4x(font, option=nil)
+ # dummy
+ if option
+ ""
+ else
+ Array([ ['family',[]], ['size',[]], ['weight',[]], ['slant',[]],
+ ['underline',[]], ['overstrike',[]], ['charset',[]],
+ ['pointadjust',[]] ])
+ end
+ end
+
+ def configure_core_tk80(font, slot, value=None)
+ if slot.kind_of? Hash
+ tk_call 'font', 'configure', font, *hash_kv(slot)
+ else
+ tk_call 'font', 'configure', font, "-#{slot}", value
+ end
+ end
+
+ def configinfo_core_tk80(font, option=nil)
+ if option == 'compound'
+ ""
+ elsif option
+ tk_call('font', 'configure', font, "-#{option}")
+ else
+ l = tk_split_list(tk_call('font', 'configure', font))
+ r = []
+ while key=l.shift
+ if key == '-compound'
+ l.shift
+ else
+ r.push [key[1..-1], l.shift]
+ end
+ end
+ r
+ end
+ end
+
+ def latin_replace_core_tk4x(ltn)
+ create_latinfont_tk4x(ltn)
+ @compoundfont[0] = [@latinfont]
+ @fontslot['font'] = @latinfont
+ Tk_FontUseTBL.dup.each{|w, id|
+ if id == @id
+ begin
+ w.configure('font', @latinfont)
+ rescue
+ Tk_FontUseTBL[w] = nil
+ end
+ end
+ }
+ self
+ end
+
+ def kanji_replace_core_tk4x(knj)
+ create_kanjifont_tk4x(knj)
+ @compoundfont[1] = [@kanjifont]
+ @fontslot['kanjifont'] = @kanjifont
+ Tk_FontUseTBL.dup.each{|w, id|
+ if id == @id
+ begin
+ w.configure('kanjifont', @kanjifont)
+ rescue
+ Tk_FontUseTBL[w] = nil
+ end
+ end
+ }
+ self
+ end
+
+ def latin_replace_core_tk80(ltn)
+ tk_call('font', 'delete', @latinfont)
+ create_latinfont_tk80(ltn)
+ self
+ end
+
+ def kanji_replace_core_tk80(knj)
+ tk_call('font', 'delete', @kanjifont)
+ create_kanjifont_tk80(knj)
+ self
+ end
+
+ def measure_core_tk4x(window, text)
+ 0
+ end
+
+ def measure_core_tk80(window, text)
+ if window
+ number(tk_call('font', 'measure', @compoundfont,
+ '-displayof', window, text))
+ else
+ number(tk_call('font', 'measure', @compoundfont, text))
+ end
+ end
+
+ def metrics_core_tk4x(font, window, option=nil)
+ # dummy
+ if option
+ ""
+ else
+ Array([ ['ascent',[]], ['descent',[]], ['linespace',[]], ['fixed',[]] ])
+ end
+ end
+
+ def metrics_core_tk80(font, window, option=nil)
+ if option
+ if window
+ number(tk_call('font', 'metrics', font, "-#{option}"))
+ else
+ number(tk_call('font', 'metrics', font,
+ "-displayof", window, "-#{option}"))
+ end
+ else
+ l = tk_split_list(if window
+ tk_call('font','metrics',font,"-displayof",window)
+ else
+ tk_call('font','metrics',font)
+ end)
+ r = []
+ while key=l.shift
+ r.push [key[1..-1], l.shift.to_i]
+ end
+ r
+ end
+ end
+
+ ###################################
+ # private alias
+ ###################################
+ case (Tk::TK_VERSION)
+ when /^4.*/
+ alias create_latinfont create_latinfont_tk4x
+ alias create_kanjifont create_kanjifont_tk4x
+ alias create_compoundfont create_compoundfont_tk4x
+ alias set_font_core set_font_core_tk4x
+ alias actual_core actual_core_tk4x
+ alias configure_core configure_core_tk4x
+ alias configinfo_core configinfo_core_tk4x
+ alias latin_replace_core latin_replace_core_tk4x
+ alias kanji_replace_core kanji_replace_core_tk4x
+ alias measure_core measure_core_tk4x
+ alias metrics_core metrics_core_tk4x
+
+ when /^8\.0/
+ alias create_latinfont create_latinfont_tk80
+ alias create_kanjifont create_kanjifont_tk80
+ alias create_compoundfont create_compoundfont_tk80
+ alias set_font_core set_font_core_tk80
+ alias actual_core actual_core_tk80
+ alias configure_core configure_core_tk80
+ alias configinfo_core configinfo_core_tk80
+ alias latin_replace_core latin_replace_core_tk80
+ alias kanji_replace_core kanji_replace_core_tk80
+ alias measure_core measure_core_tk80
+ alias metrics_core metrics_core_tk80
+
+ end
+
+ ###################################
+ public
+ ###################################
+ def set_font(window)
+ set_font_core(window)
+ end
+
+ def latin_font
+ @latinfont
+ end
+
+ def kanji_font
+ @kanjifont
+ end
+
+ def actual(option=nil)
+ actual_core(@compoundfont, nil, option)
+ end
+
+ def actual_displayof(window, option=nil)
+ window = '.' unless window
+ actual_core(@compoundfont, window, option)
+ end
+
+ def latin_actual(option=nil)
+ actual_core(@latinfont, nil, option)
+ end
+
+ def latin_actual_displayof(window, option=nil)
+ window = '.' unless window
+ actual_core(@latinfont, window, option)
+ end
+
+ def kanji_actual(option=nil)
+ actual_core(@kanjifont, nil, option)
+ end
+
+ def kanji_actual_displayof(window, option=nil)
+ window = '.' unless window
+ actual_core(@kanjifont, window, option)
+ end
+
+ def [](slot)
+ configinfo slot
+ end
+
+ def []=(slot, val)
+ configure slot, val
+ end
+
+ def configure(slot, value=None)
+ configure_core(@compoundfont, slot, value)
+ end
+
+ def configinfo(slot=nil)
+ configinfo_core(@compoundfont, slot)
+ end
+
+ def latin_configure(slot, value=None)
+ configure_core(@latinfont, slot, value)
+ end
+
+ def latin_configinfo(slot=nil)
+ configinfo_core(@latinfont, slot)
+ end
+
+ def kanji_configure(slot, value=None)
+ configure_core(@kanjifont, slot, value)
+ end
+
+ def kanji_configinfo(slot=nil)
+ configinfo_core(@kanjifont, slot)
+ end
+
+ def replace(ltn, knj)
+ latin_replace(ltn)
+ kanji_replace(ltn)
+ end
+
+ def latin_replace(ltn)
+ latin_replace_core(ltn)
+ end
+
+ def kanji_replace(knj)
+ kanji_replace_core(knj)
+ end
+
+ def measure(text)
+ measure_core(nil, text)
+ end
+
+ def measure_displayof(window, text)
+ window = '.' unless window
+ measure_core(window, text)
+ end
+
+ def metrics(option=nil)
+ metrics_core(@compoundfont, nil, option)
+ end
+
+ def metrics_displayof(window, option=nil)
+ window = '.' unless window
+ metrics_core(@compoundfont, window, option)
+ end
+
+ def latin_metrics(option=nil)
+ metrics_core(@latinfont, nil, option)
+ end
+
+ def latin_metrics_displayof(window, option=nil)
+ window = '.' unless window
+ metrics_core(@latinfont, window, option)
+ end
+
+ def kanji_metrics(option=nil)
+ metrics_core(@kanjifont, nil, option)
+ end
+
+ def kanji_metrics_displayof(window, option=nil)
+ window = '.' unless window
+ metrics_core(@kanjifont, window, option)
+ end
+
+ ###################################
+ # public alias
+ ###################################
+ alias ascii_font latin_font
+ alias create_asciifont create_latinfont
+ alias ascii_actual latin_actual
+ alias ascii_actual_displayof latin_actual_displayof
+ alias ascii_configure latin_configure
+ alias ascii_configinfo latin_configinfo
+ alias ascii_replace latin_replace
+ alias ascii_metrics latin_metrics
+
+end
diff --git a/lib/tktext.rb b/lib/tktext.rb
index 74fec8c953..7b5cea5c72 100644
--- a/lib/tktext.rb
+++ b/lib/tktext.rb
@@ -6,6 +6,11 @@
require 'tk.rb'
class TkText<TkTextWin
+ WidgetClassName = 'Text'.freeze
+ TkClassBind::WidgetClassNameTBL[WidgetClassName] = self
+ def self.to_eval
+ WidgetClassName
+ end
include Scrollable
def create_self
tk_call 'text', @path
@@ -115,20 +120,36 @@ class TkText<TkTextWin
tk_send 'tag', 'add', tag, index1, index2
end
- def tag_bind(tag, seq, cmd=Proc.new, args=nil)
- seq = context.join("><") if seq.kind_of? Array
- if /,/ =~ seq
- seq = seq.split(/\s*,\s*/).join("><")
- end
+ def _tag_bind_core(mode, tag, seq, cmd=Proc.new, args=nil)
id = install_bind(cmd, args)
- tk_send 'tag', 'bind', tag, "<#{seq}>", id
+ tk_send 'tag', 'bind', tag, "<#{tk_event_sequence(seq)}>", mode + id
# _addcmd cmd
end
+ private :_tag_bind_core
- def tag_bindinfo(tag)
- tk_split_list(tk_send('tag', 'bind', tag)).filter{|seq|
- seq.tr('<>',' ').strip.gsub(/\s+/,',')
- }
+ def tag_bind(tag, seq, cmd=Proc.new, args=nil)
+ _tag_bind_core('', tag, seq, cmd=Proc.new, args=nil)
+ end
+
+ def tag_bind_append(tag, seq, cmd=Proc.new, args=nil)
+ _tag_bind_core('+', tag, seq, cmd=Proc.new, args=nil)
+ end
+
+ def tag_bindinfo(tag, context=nil)
+ if context
+ (tk_send('tag', 'bind', tag,
+ "<#{tk_event_sequence(context)}>")).collect{|cmdline|
+ if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
+ [Tk_CMDTBL[$1], $2]
+ else
+ cmdline
+ end
+ }
+ else
+ tk_split_list(tk_send('tag', 'bind', tag)).filter{|seq|
+ seq[1..-2].gsub(/></,',')
+ }
+ end
end
def tag_cget(tag, key)
@@ -357,19 +378,26 @@ class TkTextTag<TkObject
end
def bind(seq, cmd=Proc.new, args=nil)
- seq = context.join("><") if seq.kind_of? Array
- if /,/ =~ seq
- seq = seq.split(/\s*,\s*/).join("><")
- end
id = install_bind(cmd, args)
- tk_call @t.path, 'tag', 'bind', @id, "<#{seq}>", id
+ tk_call @t.path, 'tag', 'bind', @id, "<#{tk_event_sequence(seq)}>", id
# @t._addcmd cmd
end
- def bindinfo
- tk_split_list(tk_call(@t.path, 'tag', 'bind', @id)).filter{|seq|
- seq.tr('<>',' ').strip.gsub(/\s+/,',')
- }
+ def bindinfo(context=nil)
+ if context
+ (tk_call(@t.path, 'tag', 'bind', @id,
+ "<#{tk_event_sequence(context)}>")).collect{|cmdline|
+ if cmdline =~ /^rb_out (c\d+)\s+(.*)$/
+ [Tk_CMDTBL[$1], $2]
+ else
+ cmdline
+ end
+ }
+ else
+ tk_split_list(tk_call(@t.path, 'tag', 'bind', @id)).filter{|seq|
+ seq[1..-2].gsub(/></,',')
+ }
+ end
end
def raise(above=None)