From 0a64817fb80016030c03518fb9459f63c11605ea Mon Sep 17 00:00:00 2001 From: matz Date: Fri, 13 Aug 1999 05:37:52 +0000 Subject: remove marshal/gtk/kconv git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@518 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ext/tk/lib/tk.rb | 2495 +++++++++++++++++++++++++++++++++++++++++++++ ext/tk/lib/tkafter.rb | 296 ++++++ ext/tk/lib/tkbgerror.rb | 17 + ext/tk/lib/tkcanvas.rb | 829 +++++++++++++++ ext/tk/lib/tkclass.rb | 38 + ext/tk/lib/tkdialog.rb | 141 +++ ext/tk/lib/tkentry.rb | 73 ++ ext/tk/lib/tkfont.rb | 953 +++++++++++++++++ ext/tk/lib/tkmenubar.rb | 137 +++ ext/tk/lib/tkmngfocus.rb | 27 + ext/tk/lib/tkpalette.rb | 48 + ext/tk/lib/tkscrollbox.rb | 29 + ext/tk/lib/tktext.rb | 946 +++++++++++++++++ ext/tk/lib/tkvirtevent.rb | 66 ++ 14 files changed, 6095 insertions(+) create mode 100644 ext/tk/lib/tk.rb create mode 100644 ext/tk/lib/tkafter.rb create mode 100644 ext/tk/lib/tkbgerror.rb create mode 100644 ext/tk/lib/tkcanvas.rb create mode 100644 ext/tk/lib/tkclass.rb create mode 100644 ext/tk/lib/tkdialog.rb create mode 100644 ext/tk/lib/tkentry.rb create mode 100644 ext/tk/lib/tkfont.rb create mode 100644 ext/tk/lib/tkmenubar.rb create mode 100644 ext/tk/lib/tkmngfocus.rb create mode 100644 ext/tk/lib/tkpalette.rb create mode 100644 ext/tk/lib/tkscrollbox.rb create mode 100644 ext/tk/lib/tktext.rb create mode 100644 ext/tk/lib/tkvirtevent.rb (limited to 'ext/tk/lib') diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb new file mode 100644 index 0000000000..2b4b504b0a --- /dev/null +++ b/ext/tk/lib/tk.rb @@ -0,0 +1,2495 @@ +# +# tk.rb - Tk interface modue using tcltklib +# $Date$ +# by Yukihiro Matsumoto + +# use Shigehiro's tcltklib +require "tcltklib" +require "tkutil" + +module TkComm + None = Object.new + def None.to_s + 'None' + end + + Tk_CMDTBL = {} + Tk_WINDOWS = {} + + def error_at + frames = caller() + frames.delete_if do |c| + c =~ %r!/tk(|core|thcore|canvas|text|entry|scrollbox)\.rb:\d+! + end + frames + end + private :error_at + + def _genobj_for_tkwidget(path) + return TkRoot.new if path == '.' + + begin + tk_class = TkCore::INTERP._invoke('winfo', 'class', path) + rescue + return path + end + + ruby_class = TkClassBind::WidgetClassNameTBL[tk_class] + gen_class_name = ruby_class.name + 'GeneratedOnTk' + unless Object.const_defined? gen_class_name + eval "class #{gen_class_name}<#{ruby_class.name} + def initialize(path) + @path=path + Tk_WINDOWS[@path] = self + end + end" + end + eval "#{gen_class_name}.new('#{path}')" + end + + def tk_tcl2ruby(val) + if val =~ /^rb_out (c\d+)/ + return Tk_CMDTBL[$1] + end + if val.include? ?\s + return val.split.collect{|v| tk_tcl2ruby(v)} + end + case val + when /^@font/ + TkFont.get_obj(val) + when /^-?\d+$/ + val.to_i + when /^\./ + Tk_WINDOWS[val] ? Tk_WINDOWS[val] : _genobj_for_tkwidget(val) + when / / + val.split.collect{|elt| + tk_tcl2ruby(elt) + } + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + + def tk_split_list(str) + return [] if str == "" + idx = str.index('{') + return tk_tcl2ruby(str) unless idx + + list = tk_tcl2ruby(str[0,idx]) + list = [] if list == "" + str = str[idx+1..-1] + i = -1 + brace = 1 + str.each_byte {|c| + i += 1 + brace += 1 if c == ?{ + brace -= 1 if c == ?} + break if brace == 0 + } + if str[0, i] == ' ' + list.push ' ' + else + list.push tk_split_list(str[0, i]) + end + list += tk_split_list(str[i+1..-1]) + list + end + + def tk_split_simplelist(str) + return [] if str == "" + idx = str.index('{') + return str.split unless idx + + list = str[0,idx].split + str = str[idx+1..-1] + i = -1 + brace = 1 + str.each_byte {|c| + i += 1 + brace += 1 if c == ?{ + brace -= 1 if c == ?} + break if brace == 0 + } + if i == 0 + list.push '' + elsif str[0, i] == ' ' + list.push ' ' + else + list.push str[0..i-1] + end + list += tk_split_simplelist(str[i+1..-1]) + list + end + private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist + + def hash_kv(keys) + conf = [] + if keys and keys != None + for k, v in keys + conf.push("-#{k}") + conf.push(v) + end + end + conf + end + private :hash_kv + + def array2tk_list(ary) + ary.collect{|e| + if e.kind_of? Array + "{#{array2tk_list(e)}}" + elsif e.kind_of? Hash + "{#{e.to_a.collect{|ee| array2tk_list(ee)}.join(' ')}}" + else + s = _get_eval_string(e) + (s.index(/\s/))? "{#{s}}": s + end + }.join(" ") + end + private :array2tk_list + + def bool(val) + case val + when "1", 1, 'yes', 'true' + TRUE + else + FALSE + end + end + def number(val) + case val + when /^-?\d+$/ + val.to_i + when /^-?\d+\.\d*$/ + val.to_f + else + val + end + end + def string(val) + if val == "{}" + '' + elsif val[0] == ?{ + val[1..-2] + else + val + end + end + def list(val) + tk_split_list(val).to_a + end + def window(val) + Tk_WINDOWS[val] + end + def procedure(val) + if val =~ /^rb_out (c\d+)/ + Tk_CMDTBL[$1] + else + nil + end + end + private :bool, :number, :string, :list, :window, :procedure + + def _get_eval_string(str) + return nil if str == None + if str.kind_of?(Hash) + str = hash_kv(str).join(" ") + elsif str.kind_of?(Array) + str = array2tk_list(str) + elsif str.kind_of?(Proc) + str = install_cmd(str) + elsif str == nil + str = "" + elsif str == false + str = "0" + elsif str == true + str = "1" + elsif (str.respond_to?(:to_eval)) + str = str.to_eval() + else + str = str.to_s() + end + return str + end + private :_get_eval_string + + Tk_IDs = [0, 0] # [0]-cmdid, [1]-winid + def _curr_cmd_id + id = format("c%.4d", Tk_IDs[0]) + end + def _next_cmd_id + id = _curr_cmd_id + Tk_IDs[0] += 1 + id + end + def install_cmd(cmd) + return '' if cmd == '' + id = _next_cmd_id + Tk_CMDTBL[id] = cmd + @cmdtbl = [] unless @cmdtbl + @cmdtbl.push id + return format("rb_out %s", id); + end + def uninstall_cmd(id) + id = $1 if /rb_out (c\d+)/ + Tk_CMDTBL[id] = nil + end + private :install_cmd, :uninstall_cmd + + def install_win(ppath) + id = format("w%.4d", Tk_IDs[1]) + Tk_IDs[1] += 1 + if !ppath or ppath == "." + @path = format(".%s", id); + else + @path = format("%s.%s", ppath, id) + end + Tk_WINDOWS[@path] = self + end + + def uninstall_win() + Tk_WINDOWS[@path] = nil + end + + class Event + def initialize(seq,b,f,h,k,s,t,w,x,y,aa,ee,kk,nn,ww,tt,xx,yy) + @serial = seq + @num = b + @focus = (f == 1) + @height = h + @keycode = k + @state = s + @time = t + @width = w + @x = x + @y = y + @char = aa + @send_event = (ee == 1) + @keysym = kk + @keysym_num = nn + @type = tt + @widget = ww + @x_root = xx + @y_root = yy + end + attr :serial + attr :num + attr :focus + attr :height + attr :keycode + attr :state + attr :time + attr :width + attr :x + attr :y + attr :char + attr :send_event + attr :keysym + attr :keysym_num + attr :type + attr :widget + attr :x_root + attr :y_root + end + + def install_bind(cmd, args=nil) + if args + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, *arg + }) + id + " " + args + else + id = install_cmd(proc{|arg| + TkUtil.eval_cmd cmd, Event.new(*arg) + }) + id + ' %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y' + end + end + + def tk_event_sequence(context) + if context.kind_of? TkVirtualEvent + context = context.path + end + if context.kind_of? Array + context = context.collect{|ev| + if context.kind_of? TkVirtualEvent + ev.path + else + ev + end + }.join("><") + end + 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, "<#{tk_event_sequence(context)}>", mode + id + rescue + uninstall_cmd(id) + fail + end + end + + def _bind(path, context, cmd, args=nil) + _bind_core('', path, context, cmd, args) + end + + def _bind_append(path, context, cmd, args=nil) + _bind_core('+', path, context, cmd, args) + 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(/>", *hash_kv(keys)) + else + tk_call('event', 'generate', window, "<#{tk_event_sequence(context)}>") + end + end + + def messageBox(keys) + tk_call 'tk_messageBox', *hash_kv(keys) + end + + def getOpenFile(keys) + tk_call 'tk_getOpenFile', *hash_kv(keys) + end + + def getSaveFile(keys) + tk_call 'tk_getSaveFile', *hash_kv(keys) + end + + def chooseColor(keys) + tk_call 'tk_chooseColor', *hash_kv(keys) + end + + def tk_call(*args) + print args.join(" "), "\n" if $DEBUG + args.filter {|x|_get_eval_string(x)} + args.compact! + args.flatten! + begin + res = INTERP._invoke(*args) + rescue NameError + err = $! + begin + args.unshift "unknown" + res = INTERP._invoke(*args) + rescue + raise unless /^invalid command/ =~ $! + raise err + end + end + if INTERP._return_value() != 0 + fail RuntimeError, res, error_at + end + print "==> ", res, "\n" if $DEBUG + return res + end +end + +module Tk + include TkCore + extend Tk + + TCL_VERSION = INTERP._invoke("info", "tclversion") + TK_VERSION = INTERP._invoke("set", "tk_version") + JAPANIZED_TK = (INTERP._invoke("info", "commands", "kanji") != "") + + def root + TkRoot.new + end + + def bell + tk_call 'bell' + end + + def Tk.focus(display=nil) + if display == nil + r = tk_call('focus') + else + r = tk_call('focus', '-displayof', display) + end + tk_tcl2ruby(r) + end + + def Tk.focus_lastfor(win) + tk_tcl2ruby(tk_call('focus', '-lastfor', win)) + end + + def toUTF8(str,encoding) + INTERP._toUTF8(str,encoding) + end + + def fromUTF8(str,encoding) + INTERP._fromUTF8(str,encoding) + end + + module Scrollable + def xscrollcommand(cmd=Proc.new) + configure_cmd 'xscrollcommand', cmd + end + def yscrollcommand(cmd=Proc.new) + configure_cmd 'yscrollcommand', cmd + end + end + + module Wm + include TkComm + def aspect(*args) + w = window(tk_call('wm', 'grid', path, *args)) + w.split.collect{|s|s.to_i} if args.length == 0 + end + def client(name=None) + tk_call 'wm', 'client', path, name + end + def colormapwindows(*args) + list(tk_call('wm', 'colormapwindows', path, *args)) + end + def wm_command(value=None) + string(tk_call('wm', 'command', path, value)) + end + def deiconify + tk_call 'wm', 'deiconify', path + end + def focusmodel(*args) + tk_call 'wm', 'focusmodel', path, *args + end + def frame + tk_call 'wm', 'frame', path + end + def geometry(*args) + list(tk_call('wm', 'geometry', path, *args)) + end + def grid(*args) + w = tk_call('wm', 'grid', path, *args) + list(w) if args.size == 0 + end + def group(*args) + tk_call 'wm', 'group', path, *args + end + def iconbitmap(*args) + tk_call 'wm', 'iconbitmap', path, *args + end + def iconify + tk_call 'wm', 'iconify', path + end + def iconmask(*args) + tk_call 'wm', 'iconmask', path, *args + end + def iconname(*args) + tk_call 'wm', 'iconname', path, *args + end + def iconposition(*args) + w = tk_call('wm', 'iconposition', path, *args) + list(w) if args.size == 0 + end + def iconwindow(*args) + w = tk_call('wm', 'iconwindow', path, *args) + window(w) if args.size == 0 + end + def maxsize(*args) + w = tk_call('wm', 'maxsize', path, *args) + list(w) if not args.size == 0 + end + def minsize(*args) + w = tk_call('wm', 'minsize', path, *args) + list(w) if args.size == 0 + end + def overrideredirect(bool=None) + if bool == None + bool(tk_call('wm', 'overrideredirect', path)) + else + tk_call 'wm', 'overrideredirect', path, bool + end + end + def positionfrom(*args) + tk_call 'wm', 'positionfrom', path, *args + end + def protocol(name=nil, cmd=nil) + if cmd + tk_call('wm', 'protocol', path, name, cmd) + elsif name + result = tk_call('wm', 'protocol', path, name) + (result == "")? nil : tk_tcl2ruby(result) + else + tk_split_simplelist(tk_call('wm', 'protocol', path)) + end + end + def resizable(*args) + w = tk_call('wm', 'resizable', path, *args) + if args.length == 0 + list(w).collect{|e| bool(e)} + end + end + def sizefrom(*args) + list(tk_call('wm', 'sizefrom', path, *args)) + end + def state + tk_call 'wm', 'state', path + end + def title(*args) + tk_call 'wm', 'title', path, *args + end + def transient(*args) + tk_call 'wm', 'transient', path, *args + end + def withdraw + tk_call 'wm', 'withdraw', path + end + end +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 + if val == [] + INTERP._eval(format('global %s; set %s(0) 0; unset %s(0)', + @id, @id, @id)) + elsif val.kind_of?(Array) + 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(/[][$"]/, '\\\\\&') + '"' + INTERP._eval(format('global %s; array set %s %s', @id, @id, s)) + else + s = '"' + _get_eval_string(val).gsub(/[][$"]/, '\\\\\&') + '"' + INTERP._eval(format('global %s; set %s %s', @id, @id, s)) + end + end + + def wait + INTERP._eval("tkwait variable #{@id}") + end + + def id + @id + end + + def value + begin + INTERP._eval(format('global %s; set %s', @id, @id)) + rescue + if INTERP._eval(format('global %s; array exists %s', @id, @id)) != "1" + raise + else + Hash[*tk_split_simplelist(INTERP._eval(format('global %s; array get %s', + @id, @id)))] + end + end + end + + def value=(val) + begin + 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 + else + if val == [] + INTERP._eval(format('global %s; unset %s; set %s(0) 0; unset %s(0)', + @id, @id, @id, @id)) + elsif val.kind_of?(Array) + 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; unset %s; array set %s %s', + @id, @id, @id, s)) + else + raise + end + end + end + end + + def [](index) + INTERP._eval(format('global %s; set %s(%s)', + @id, @id, _get_eval_string(index))) + end + + def []=(index,val) + INTERP._eval(format('global %s; set %s(%s) %s', @id, @id, + _get_eval_string(index), _get_eval_string(val))) + end + + def to_i + Integer(number(value)) + end + + def to_f + Float(number(value)) + end + + def to_s + String(string(value)) + end + + def inspect + format "", @id + end + + def ==(other) + case other + when TkVariable + self.equal(self) + when String + self.to_s == other + when Integer + self.to_i == other + when Float + self.to_f == other + when Array + self.to_a == other + else + false + end + end + + def to_a + list(value) + end + + 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 + next + 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 + next + 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 TkVarAccessvalue}) + end + else + tk_call path, 'configure', "-#{slot}", value + end + end + end + + def configure_cmd(slot, value) + configure slot, install_cmd(value) + end + + def configinfo(slot = nil) + if slot == 'font' || slot == 'kanjifont' + fontobj + else + if slot + conf = tk_split_list(tk_send('configure', "-#{slot}") ) + conf[0] = conf[0][1..-1] + conf + else + ret = tk_split_list(tk_send('configure') ).collect{|conf| + conf[0] = conf[0][1..-1] + conf + } + if ret.assoc('font') + ret.delete_if{|item| item[0] == 'font' || item[0] == 'kanjifont'} + ret.push(['font', fontobj]) + else + ret + end + end + end + end + + def bind(context, cmd=Proc.new, args=nil) + _bind path, context, cmd, args + end + + def bind_append(context, cmd=Proc.new, args=nil) + _bind_append path, context, cmd, args + end + + def bindinfo(context=nil) + _bindinfo path, context + end + + def event_generate(context, keys=nil) + if keys + tk_call('event', 'generate', path, + "<#{tk_event_sequence(context)}>", *hash_kv(keys)) + else + tk_call('event', 'generate', path, "<#{tk_event_sequence(context)}>") + end + end + + def tk_trace_variable(v) + unless v.kind_of?(TkVariable) + fail ArgumentError, format("requires TkVariable given %s", v.type) + end + v + end + private :tk_trace_variable + + def destroy + tk_call 'trace', 'vdelete', @tk_vn, 'w', @var_id if @var_id + 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.bindinfo to_eval, context + end +end + +class TkWindowval}) + else + tk_call 'entryconfigure', index, "-#{key}", val + end + end + end + + def entryconfiginfo(index, key=nil) + if key + conf = tk_split_list(tk_send('entryconfigure',index,"-#{key}")) + conf[0] = conf[0][1..-1] + conf + else + tk_split_list(tk_send('entryconfigure', index)).collect{|conf| + conf[0] = conf[0][1..-1] + conf + } + end + end +end + +class TkMenubutton +# +require 'tk' + +class TkAfter + include TkCore + extend TkCore + + Tk_CBID = [0] + Tk_CBTBL = {} + + INTERP._invoke("proc", "rb_after", "args", "ruby [format \"TkAfter.callback %%Q!%s!\" $args]") + + ############################### + # class methods + ############################### + def TkAfter.callback(arg) + @after_id = nil + arg = Array(tk_split_list(arg)) + obj_id = arg.shift + ex_obj = Tk_CBTBL[obj_id] + return nil if ex_obj == nil; # canceled + _get_eval_string(ex_obj.do_callback(*arg)) + end + + def TkAfter.info + tk_call('after', 'info').split(' ').filter{|id| + ret = Tk_CBTBL.find{|key,val| val.after_id == id} + (ret == nil)? id: ret[1] + } + end + + ############################### + # instance methods + ############################### + def do_callback(*args) + @in_callback = true + ret = @current_proc.call(*args) + if @set_next + set_next_callback(*args) + else + @set_next = true + end + @in_callback = false + ret + end + + def set_callback(sleep, args=nil) + @after_script = "rb_after #{@id} #{_get_eval_string(args)}" + @after_id = tk_call('after', sleep, @after_script) + @current_script = [sleep, @after_script] + end + + def set_next_callback(*args) + if @running == false || @proc_max == 0 || @do_loop == 0 + Tk_CBTBL[@id] = nil ;# for GC + @running = false + return + end + if @current_pos >= @proc_max + if @do_loop < 0 || (@do_loop -= 1) > 0 + @current_pos = 0 + else + Tk_CBTBL[@id] = nil ;# for GC + @running = false + return + end + end + + @current_args = args + + if @sleep_time.kind_of? Proc + sleep = @sleep_time.call(*args) + else + sleep = @sleep_time + end + @current_sleep = sleep + + cmd, *cmd_args = @loop_proc[@current_pos] + @current_pos += 1 + @current_proc = cmd + + if cmd_args[0].kind_of? Proc + #c = cmd_args.shift + #cb_args = c.call(*(cmd_args + args)) + cb_args = cmd_args[0].call(*args) + else + cb_args = cmd_args + end + + set_callback(sleep, cb_args) + end + + def initialize(*args) + @id = format("a%.4d", Tk_CBID[0]) + Tk_CBID[0] += 1 + + @set_next = true + + @init_sleep = 0 + @init_proc = nil + @init_args = [] + + @current_script = [] + @current_proc = nil + @current_args = nil + + @sleep_time = 0 + @current_sleep = 0 + @loop_exec = 0 + @do_loop = 0 + @loop_proc = [] + @proc_max = 0 + @current_pos = 0 + + @after_id = nil + @after_script = nil + + set_procs(*args) if args != [] + + @running = false + end + + attr :after_id + attr :after_script + attr :current_proc + attr :current_sleep + + attr_accessor :loop_exec + + def get_procs + [@init_sleep, @init_proc, @init_args, @sleep_time, @loop_exec, @loop_proc] + end + + def current_status + [@running, @current_sleep, @current_proc, @current_args, @do_loop] + end + + def running? + @running + end + + def loop_rest + @do_loop + end + + def loop_rest=(rest) + @do_loop = rest + end + + def set_procs(interval, loop_exec, *procs) + if !interval == 'idle' \ + && !interval.kind_of?(Integer) && !interval.kind_of?(Proc) + fail format("%s need to be Integer or Proc", interval.inspect) + end + @sleep_time = interval + + @loop_proc = [] + procs.each{|e| + if e.kind_of? Proc + @loop_proc.push([e]) + else + @loop_proc.push(e) + end + } + @proc_max = @loop_proc.size + @current_pos = 0 + + @do_loop = 0 + if loop_exec + if loop_exec.kind_of?(Integer) && loop_exec < 0 + @loop_exec = -1 + elsif loop_exec == nil || loop_exec == false || loop_exec == 0 + @loop_exec = 1 + else + if not loop_exec.kind_of?(Integer) + fail format("%s need to be Integer", loop_exec.inspect) + end + @loop_exec = loop_exec + end + @do_loop = @loop_exec + end + + self + end + + def add_procs(*procs) + procs.each{|e| + if e.kind_of? Proc + @loop_proc.push([e]) + else + @loop_proc.push(e) + end + } + @proc_max = @loop_proc.size + + self + end + + def set_start_proc(sleep, init_proc, *init_args) + if !sleep == 'idle' && !sleep.kind_of?(Integer) + fail format("%s need to be Integer", sleep.inspect) + end + @init_sleep = sleep + @init_proc = init_proc + @init_args = init_args + self + end + + def start(*init_args) + return nil if @running + + Tk_CBTBL[@id] = self + @do_loop = @loop_exec + @current_pos = 0 + + argc = init_args.size + if argc > 0 + sleep = init_args.shift + if !sleep == 'idle' && !sleep.kind_of?(Integer) + fail format("%s need to be Integer", sleep.inspect) + end + @init_sleep = sleep + end + @init_proc = init_args.shift if argc > 1 + @init_args = init_args if argc > 0 + + @current_sleep = @init_sleep + @running = true + if @init_proc + if not @init_proc.kind_of? Proc + fail format("%s need to be Proc", @init_proc.inspect) + end + @current_proc = @init_proc + set_callback(sleep, @init_args) + @set_next = false if @in_callback + else + set_next_callback(*@init_args) + end + + self + end + + def restart(*restart_args) + cancel if @running + if restart_args == [] + start(@init_sleep, @init_proc, *@init_args) + else + start(*restart_args) + end + end + + def cancel + @running = false + tk_call 'after', 'cancel', @after_id if @after_id + @after_id = nil + Tk_CBTBL[@id] = nil ;# for GC + self + end + alias stop cancel + + def continue(wait=nil) + sleep, cmd = @current_script + return nil if cmd == nil || @running == true + if wait + if not wait.kind_of? Integer + fail format("%s need to be Integer", wait.inspect) + end + sleep = wait + end + Tk_CBTBL[@id] = self + @running = true + @after_id = tk_call('after', sleep, cmd) + self + end + + def skip + return nil if @running == false + cancel + Tk_CBTBL[@id] = self + @running = true + set_next_callback(@current_args) + self + end + + def info + if @after_id + inf = tk_split_list(tk_call('after', 'info', @after_id)) + [Tk_CBTBL[inf[0][1]], inf[1]] + else + nil + end + end +end diff --git a/ext/tk/lib/tkbgerror.rb b/ext/tk/lib/tkbgerror.rb new file mode 100644 index 0000000000..8022077a3f --- /dev/null +++ b/ext/tk/lib/tkbgerror.rb @@ -0,0 +1,17 @@ +# +# tkbgerror -- bgerror ( tkerror ) module +# 1998/07/16 by Hidetoshi Nagai +# +require 'tk' + +module TkBgError + extend Tk + + def bgerror(message) + tk_call 'bgerror', message + end + alias tkerror bgerror + alias show bgerror + + module_function :bgerror, :tkerror, :show +end diff --git a/ext/tk/lib/tkcanvas.rb b/ext/tk/lib/tkcanvas.rb new file mode 100644 index 0000000000..1cf24eeb7b --- /dev/null +++ b/ext/tk/lib/tkcanvas.rb @@ -0,0 +1,829 @@ +# +# tkcanvas.rb - Tk canvas classes +# $Date$ +# by Yukihiro Matsumoto +# $Date$ +# by Hidetoshi Nagai + +require "tk" +require 'tkfont' + +module TkTreatCItemFont + def tagfont_configinfo(tagOrId) + if tagOrId.kind_of?(TkcItem) || tagOrId.kind_of?(TkcTag) + pathname = self.path + ';' + tagOrId.id.to_s + else + pathname = self.path + ';' + tagOrId.to_s + end + ret = TkFont.used_on(pathname) + if ret == nil + ret = TkFont.init_widget_font(pathname, + self.path, 'itemconfigure', tagOrId) + end + ret + end + alias tagfontobj tagfont_configinfo + + def tagfont_configure(tagOrId, slot) + if tagOrId.kind_of?(TkcItem) || tagOrId.kind_of?(TkcTag) + pathname = self.path + ';' + tagOrId.id.to_s + else + pathname = self.path + ';' + tagOrId.to_s + end + if (fnt = slot['font']) + slot['font'] = nil + if fnt.kind_of? TkFont + return fnt.call_font_configure(pathname, + self.path,'itemconfigure',tagOrId,slot) + else + latintagfont_configure(tagOrId, fnt) if fnt + end + end + if (ltn = slot['latinfont']) + slot['latinfont'] = nil + latintagfont_configure(tagOrId, ltn) if ltn + end + if (ltn = slot['asciifont']) + slot['asciifont'] = nil + latintagfont_configure(tagOrId, ltn) if ltn + end + if (knj = slot['kanjifont']) + slot['kanjifont'] = nil + kanjitagfont_configure(tagOrId, knj) if knj + end + + tk_call(self.path, 'itemconfigure', tagOrId, *hash_kv(slot)) if slot != {} + self + end + + def latintagfont_configure(tagOrId, ltn, keys=nil) + fobj = tagfontobj(tagOrId) + if ltn.kind_of? TkFont + conf = {} + ltn.latin_configinfo.each{|key,val| conf[key] = val if val != []} + if conf == {} + fobj.latin_replace(ltn) + fobj.latin_configure(keys) if keys + elsif keys + fobj.latin_configure(conf.update(keys)) + else + fobj.latin_configure(conf) + end + else + fobj.latin_replace(ltn) + end + end + alias asciitagfont_configure latintagfont_configure + + def kanjitagfont_configure(tagOrId, knj, keys=nil) + fobj = tagfontobj(tagOrId) + if knj.kind_of? TkFont + conf = {} + knj.kanji_configinfo.each{|key,val| conf[key] = val if val != []} + if conf == {} + fobj.kanji_replace(knj) + fobj.kanji_configure(keys) if keys + elsif keys + fobj.kanji_configure(conf.update(keys)) + else + fobj.kanji_configure(conf) + end + else + fobj.kanji_replace(knj) + end + end + + def tagfont_copy(tagOrId, window, wintag=nil) + if wintag + window.tagfontobj(wintag).configinfo.each{|key,value| + tagfontobj(tagOrId).configure(key,value) + } + tagfontobj(tagOrId).replace(window.tagfontobj(wintag).latin_font, + window.tagfontobj(wintag).kanji_font) + else + window.tagfont(tagOrId).configinfo.each{|key,value| + tagfontobj(tagOrId).configure(key,value) + } + tagfontobj(tagOrId).replace(window.fontobj.latin_font, + window.fontobj.kanji_font) + end + end + + def latintagfont_copy(tagOrId, window, wintag=nil) + if wintag + tagfontobj(tagOrId).latin_replace(window.tagfontobj(wintag).latin_font) + else + tagfontobj(tagOrId).latin_replace(window.fontobj.latin_font) + end + end + alias asciitagfont_copy latintagfont_copy + + def kanjitagfont_copy(tagOrId, window, wintag=nil) + if wintag + tagfontobj(tagOrId).kanji_replace(window.tagfontobj(wintag).kanji_font) + else + tagfontobj(tagOrId).kanji_replace(window.fontobj.kanji_font) + end + end +end + +class TkCanvas", id + rescue + uninstall_cmd(cmd) + fail + end + # @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(/>value}) + else + tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value + end + end + end +# def itemconfigure(tagOrId, key, value=None) +# if key.kind_of? Hash +# tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(key) +# else +# tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value +# end +# end +# def itemconfigure(tagOrId, keys) +# tk_send 'itemconfigure', tagid(tagOrId), *hash_kv(keys) +# end + + def itemconfiginfo(tagOrId, key=nil) + if key + conf = tk_split_list(tk_send 'itemconfigure', tagid(tagOrId), "-#{key}") + conf[0] = conf[0][1..-1] + conf + else + tk_split_list(tk_send 'itemconfigure', tagid(tagOrId)).collect{|conf| + conf[0] = conf[0][1..-1] + conf + } + end + end + + def lower(tag, below=None) + tk_send 'lower', tagid(tag), below + end + + def move(tag, x, y) + tk_send 'move', tagid(tag), x, y + end + + def postscript(keys) + tk_send "postscript", *hash_kv(keys) + end + + def raise(tag, above=None) + tk_send 'raise', tagid(tag), above + end + + def scale(tag, x, y, xs, ys) + tk_send 'scale', tagid(tag), x, y, xs, ys + end + + def scan_mark(x, y) + tk_send 'scan', 'mark', x, y + end + def scan_dragto(x, y) + tk_send 'scan', 'dragto', x, y + end + + def select(mode, *args) + tk_send 'select', mode, *args + end + def select_adjust(tagOrId, index) + select('adjust', tagid(tagOrId), index) + end + def select_clear + select('clear') + end + def select_from(tagOrId, index) + select('from', tagid(tagOrId), index) + end + def select_item + select('item') + end + def select_to(tagOrId, index) + select('to', tagid(tagOrId), index) + end + + def itemtype(tag) + TkcItem.type2class(tk_send 'type', tagid(tag)) + end + + def xview(*index) + tk_send 'xview', *index + end + def yview(*index) + tk_send 'yview', *index + end +end + +module TkcTagAccess + include TkComm + include TkTreatTagFont + + def addtag(tag) + @c.addtag(tag, 'with', @id) + end + + def bbox + @c.bbox(@id) + end + + def bind(seq, cmd=Proc.new, args=nil) + @c.itembind @id, seq, cmd, args + end + + def bindinfo(seq=nil) + @c.itembindinfo @id, seq + end + + def cget(option) + @c.itemcget @id, option + end + + def configure(key, value=None) + @c.itemconfigure @id, key, value + end +# def configure(keys) +# @c.itemconfigure @id, keys +# end + + def configinfo(key=nil) + @c.itemconfiginfo @id, key + end + + def coords(*args) + @c.coords @id, *args + end + + def dchars(first, last=None) + @c.dchars @id, first, last + end + + def dtag(tag_to_del=None) + @c.dtag @id, tag_to_del + end + + def find + @c.find 'withtag', @id + end + alias list find + + def focus + @c.itemfocus @id + end + + def gettags + @c.gettags @id + end + + def icursor(index) + @c.icursor @id, index + end + + def index(index) + @c.index @id, index + end + + def insert(beforethis, string) + @c.insert @id, beforethis, string + end + + def lower(belowthis=None) + @c.lower @id, belowthis + end + + def move(xamount, yamount) + @c.move @id, xamount, yamount + end + + def raise(abovethis=None) + @c.raise @id, abovethis + end + + def scale(xorigin, yorigin, xscale, yscale) + @c.scale @id, xorigin, yorigin, xscale, yscale + end + + def select_adjust(index) + @c.select('adjust', @id, index) + end + def select_from(index) + @c.select('from', @id, index) + end + def select_to(index) + @c.select('to', @id, index) + end + + def itemtype + @c.itemtype @id + end +end + +class TkcTag + +require "tk" + +TopLevel = TkToplevel +Frame = TkFrame +Label = TkLabel +Button = TkButton +Radiobutton = TkRadioButton +Checkbutton = TkCheckButton +Message = TkMessage +Entry = TkEntry +Text = TkText +Scale = TkScale +Scrollbar = TkScrollbar +Listbox = TkListbox +Menu = TkMenu +Menubutton = TkMenubutton +Canvas = TkCanvas +Arc = TkcArc +Bitmap = TkcBitmap +Line = TkcLine +Oval = TkcOval +Polygon = TkcPolygon +Rectangle = TkcRectangle +TextItem = TkcText +WindowItem = TkcWindow +Selection = TkSelection +Winfo = TkWinfo +Pack = TkPack +Variable = TkVariable + +def Mainloop + Tk.mainloop +end diff --git a/ext/tk/lib/tkdialog.rb b/ext/tk/lib/tkdialog.rb new file mode 100644 index 0000000000..1133db6ae9 --- /dev/null +++ b/ext/tk/lib/tkdialog.rb @@ -0,0 +1,141 @@ +require "tk" + +class TkDialog < TkWindow + extend Tk + + # initialize tk_dialog + def initialize(keys = nil) + super() + @var = TkVariable.new + id = @var.id + + @title = title + + @message = message + @message_config = message_config + + @bitmap = bitmap + @bitmap_config = message_config + + @default_button = default_button + + @buttons = buttons + @button_configs = proc{|num| button_configs num} + + if keys.kind_of? Hash + @title = keys['title'] if keys['title'] + @message = keys['message'] if keys['message'] + @bitmap = keys['bitmap'] if keys['bitmap'] + @default_button = keys['default'] if keys['default'] + @buttons = keys['buttons'] if keys['buttons'] + + @command = keys['prev_command'] + + @message_config = keys['message_config'] if keys['message_config'] + @bitmap_config = keys['bitmap_config'] if keys['bitmap_config'] + @button_configs = keys['button_configs'] if keys['button_configs'] + end + + if @title.include? ?\s + @title = '{' + @title + '}' + end + + @buttons = tk_split_list(@buttons) if @buttons.kind_of? String + @buttons = @buttons.collect{|s| + if s.kind_of? Array + s = s.join(' ') + end + if s.include? ?\s + '{' + s + '}' + else + s + end + } + + config = "" + if @message_config.kind_of? Hash + config << format("%s.msg configure %s\n", + @path, hash_kv(@message_config).join(' ')) + end + if @bitmap_config.kind_of? Hash + config << format("%s.msg configure %s\n", + @path, hash_kv(@bitmap_config).join(' ')) + end + if @button_configs.kind_of? Proc + @buttons.each_index{|i| + if (c = @button_configs.call(i)).kind_of? Hash + config << format("%s.button%s configure %s\n", + @path, i, hash_kv(c).join(' ')) + end + } + end + config = 'after idle {' + config + '};' if config != "" + + if @command.kind_of? Proc + @command.call(self) + end + + INTERP._eval('eval {global '+id+';'+config+ + 'set '+id+' [tk_dialog '+ + @path+" "+@title+" {#{@message}} "+@bitmap+" "+ + String(@default_button)+" "+@buttons.join(' ')+']}') + end + def value + return @var.value.to_i + end + ###################################################### + # # + # these methods must be overridden for each dialog # + # # + ###################################################### + def title + return "DIALOG" + end + def message + return "MESSAGE" + end + def message_config + return nil + end + def bitmap + return "info" + end + def bitmap_config + return nil + end + def default_button + return 0 + end + def buttons + #return "BUTTON1 BUTTON2" + return ["BUTTON1", "BUTTON2"] + end + def button_configs(num) + return nil + end +end + +# +# dialog for warning +# +class TkWarning < TkDialog + def initialize(mes) + @mes = mes + super() + end + def message + return @mes + end + def title + return "WARNING"; + end + def bitmap + return "warning"; + end + def default_button + return 0; + end + def buttons + return "OK"; + end +end diff --git a/ext/tk/lib/tkentry.rb b/ext/tk/lib/tkentry.rb new file mode 100644 index 0000000000..b834c455c6 --- /dev/null +++ b/ext/tk/lib/tkentry.rb @@ -0,0 +1,73 @@ +# +# tkentry.rb - Tk entry classes +# $Date$ +# by Yukihiro Matsumoto + +require 'tk.rb' + +class TkEntry@latinfont, 'kanjifont'=>@kanjifont} + else + @compoundfont = @latinfont + @fontslot = {'font'=>@latinfont} + end + end + + def create_latinfont_tk8x(font) + @latinfont = @id + 'l' + + if JAPANIZED_TK + 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 + else + if font.kind_of? Hash + tk_call('font', 'create', @latinfont, *hash_kv(font)) + else + keys = {} + if font.kind_of? Array + actual_core(array2tk_list(font)).each{|key,val| keys[key] = val} + elsif font.kind_of? TkFont + actual_core(font.latin_font).each{|key,val| keys[key] = val} + else + actual_core(font).each{|key,val| keys[key] = val} + end + tk_call('font', 'create', @latinfont, *hash_kv(keys)) + end + end + end + + def create_kanjifont_tk80(font) + unless JAPANIZED_TK + @kanjifont = "" + return + end + + @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_kanjifont_tk81(font) + @kanjifont = @id + 'k' + + if font.kind_of? Hash + tk_call('font', 'create', @kanjifont, *hash_kv(font)) + else + keys = {} + if font.kind_of? Array + actual_core(array2tk_list(font)).each{|key,val| keys[key] = val} + elsif font.kind_of? TkFont + actual_core(font.kanji_font).each{|key,val| keys[key] = val} + else + actual_core(font).each{|key,val| keys[key] = val} + end + tk_call('font', 'create', @kanjifont, *hash_kv(keys)) + end + + keys = {} + actual_core(@kanjifont).each{|key,val| keys[key] = val} + begin + tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) + rescue + end + end + + def create_compoundfont_tk80(keys) + @compoundfont = @id + 'c' + if JAPANIZED_TK + @fontslot = {'font'=>@compoundfont} + tk_call('font', 'create', @compoundfont, + '-compound', [@latinfont, @kanjifont], *hash_kv(keys)) + else + tk_call('font', 'create', @compoundfont) + latinkeys = {} + begin + actual_core(@latinfont).each{|key,val| latinkeys[key] = val} + rescue + latinkeys {} + end + if latinkeys != {} + tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) + end + @fontslot = {'font'=>@compoundfont} + tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) + end + end + + def create_compoundfont_tk81(keys) + @compoundfont = @id + 'c' + tk_call('font', 'create', @compoundfont) + + latinkeys = {} + begin + actual_core(@latinfont).each{|key,val| latinkeys[key] = val} + rescue + latinkeys {} + end + if latinkeys != {} + tk_call('font', 'configure', @compoundfont, *hash_kv(latinkeys)) + end + + kanjikeys = {} + begin + actual_core(@kanjifont).each{|key,val| kanjikeys[key] = val} + rescue + kanjikeys {} + end + if kanjikeys != {} + tk_call('font', 'configure', @compoundfont, *hash_kv(kanjikeys)) + end + + @fontslot = {'font'=>@compoundfont} + tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) + end + + def actual_core_tk4x(font, window=nil, option=nil) + # dummy + if option + "" + else + [['family',[]], ['size',[]], ['weight',[]], ['slant',[]], + ['underline',[]], ['overstrike',[]], ['charset',[]], + ['pointadjust',[]]] + end + end + + def actual_core_tk8x(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_simplelist(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 + [['family',[]], ['size',[]], ['weight',[]], ['slant',[]], + ['underline',[]], ['overstrike',[]], ['charset',[]], + ['pointadjust',[]]] + end + end + + def configure_core_tk8x(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_tk8x(font, option=nil) + if option == 'compound' + "" + elsif option + tk_call('font', 'configure', font, "-#{option}") + else + l = tk_split_simplelist(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 delete_core_tk4x + Tk_FontNameTBL[@id] = nil + Tk_FontUseTBL.delete_if{|key,value| value == self} + end + + def delete_core_tk8x + begin + tk_call('font', 'delete', @latinfont) + rescue + end + begin + tk_call('font', 'delete', @kanjifont) + rescue + end + begin + tk_call('font', 'delete', @compoundfont) + rescue + end + Tk_FontNameTBL[@id] = nil + Tk_FontUseTBL.delete_if{|key,value| value == self} + end + + def latin_replace_core_tk4x(ltn) + create_latinfont_tk4x(ltn) + @compoundfont[0] = [@latinfont] if JAPANIZED_TK + @fontslot['font'] = @latinfont + Tk_FontUseTBL.dup.each{|w, fobj| + if self == fobj + begin + if w.include?(';') + win, tag = w.split(';') + winobj = tk_tcl2ruby(win) +# winobj.tagfont_configure(tag, {'font'=>@latinfont}) + if winobj.kind_of? TkText + tk_call(win, 'tag', 'configure', tag, '-font', @latinfont) + elsif winobj.kind_of? TkCanvas + tk_call(win, 'itemconfigure', tag, '-font', @latinfont) + elsif winobj.kind_of? TkMenu + tk_call(win, 'entryconfigure', tag, '-font', @latinfont) + else + raise RuntimeError, "unknown widget type" + end + else +# tk_tcl2ruby(w).font_configure('font'=>@latinfont) + tk_call(w, 'configure', '-font', @latinfont) + end + rescue + Tk_FontUseTBL[w] = nil + end + end + } + self + end + + def kanji_replace_core_tk4x(knj) + return self unless JAPANIZED_TK + + create_kanjifont_tk4x(knj) + @compoundfont[1] = [@kanjifont] + @fontslot['kanjifont'] = @kanjifont + Tk_FontUseTBL.dup.each{|w, fobj| + if self == fobj + begin + if w.include?(';') + win, tag = w.split(';') + winobj = tk_tcl2ruby(win) +# winobj.tagfont_configure(tag, {'kanjifont'=>@kanjifont}) + if winobj.kind_of? TkText + tk_call(win, 'tag', 'configure', tag, '-kanjifont', @kanjifont) + elsif winobj.kind_of? TkCanvas + tk_call(win, 'itemconfigure', tag, '-kanjifont', @kanjifont) + elsif winobj.kind_of? TkMenu + tk_call(win, 'entryconfigure', tag, '-kanjifont', @latinfont) + else + raise RuntimeError, "unknown widget type" + end + else +# tk_tcl2ruby(w).font_configure('kanjifont'=>@kanjifont) + tk_call(w, 'configure', '-kanjifont', @kanjifont) + end + rescue + Tk_FontUseTBL[w] = nil + end + end + } + self + end + + def latin_replace_core_tk8x(ltn) + begin + tk_call('font', 'delete', @latinfont) + rescue + end + create_latinfont(ltn) + self + end + + def kanji_replace_core_tk80(knj) + return self unless JAPANIZED_TK + + begin + tk_call('font', 'delete', @kanjifont) + rescue + end + create_kanjifont(knj) + self + end + + def kanji_replace_core_tk81(knj) + if font.kind_of? Hash + tk_call('font', 'configure', @compoundfont, *hash_kv(knj)) + else + keys = {} + if knj.kind_of? Array + actual_core(array2tk_list(knj)).each{|key,val| keys[key] = val} + elsif knj.kind_of? TkFont + actual_core(knj.latin_font).each{|key,val| keys[key] = val} + else + actual_core(knj).each{|key,val| keys[key] = val} + end + tk_call('font', 'configure', @compoundfont, *hash_kv(keys)) + end + self + end + + def measure_core_tk4x(window, text) + 0 + end + + def measure_core_tk8x(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 + [['ascent',[]], ['descent',[]], ['linespace',[]], ['fixed',[]]] + end + end + + def metrics_core_tk8x(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 actual_core actual_core_tk4x + alias configure_core configure_core_tk4x + alias configinfo_core configinfo_core_tk4x + alias delete_core delete_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_tk8x + alias create_kanjifont create_kanjifont_tk80 + alias create_compoundfont create_compoundfont_tk80 + alias actual_core actual_core_tk8x + alias configure_core configure_core_tk8x + alias configinfo_core configinfo_core_tk8x + alias delete_core delete_core_tk8x + alias latin_replace_core latin_replace_core_tk8x + alias kanji_replace_core kanji_replace_core_tk80 + alias measure_core measure_core_tk8x + alias metrics_core metrics_core_tk8x + + when /^8\.1/ + alias create_latinfont create_latinfont_tk8x + alias create_kanjifont create_kanjifont_tk81 + alias create_compoundfont create_compoundfont_tk81 + alias actual_core actual_core_tk8x + alias configure_core configure_core_tk8x + alias configinfo_core configinfo_core_tk8x + alias delete_core delete_core_tk8x + alias latin_replace_core latin_replace_core_tk8x + alias kanji_replace_core kanji_replace_core_tk81 + alias measure_core measure_core_tk8x + alias metrics_core metrics_core_tk8x + + end + + ################################### + public + ################################### + def call_font_configure(path, *args) + args += hash_kv(args.pop.update(@fontslot)) + tk_call *args + Tk_FontUseTBL[path] = self + self + end + + def used + ret = [] + Tk_FontUseTBL.each{|key,value| + if key.include?(';') + win, tag = key.split(';') + winobj = tk_tcl2ruby(win) + if winobj.kind_of? TkText + ret.push([winobj, winobj.tagid2obj(tag)]) + elsif winobj.kind_of? TkCanvas + if (tagobj = TkcTag.id2obj(tag)).kind_of? TkcTag + ret.push([winobj, tagobj]) + elsif (tagobj = TkcItem.id2obj(tag)).kind_of? TkcItem + ret.push([winobj, tagobj]) + else + ret.push([winobj, tag]) + end + elsif winobj.kind_of? TkMenu + ret.push([winobj, tag]) + else + ret.push([win, tag]) + end + else + ret.push(tk_tcl2ruby(key)) if value == self + end + } + ret + end + + def id + @id + end + + def to_eval + font + end + + def font + @compoundfont + 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) + #if JAPANIZED_TK + if @kanjifont != "" + actual_core(@kanjifont, nil, option) + else + actual_core_tk4x(nil, nil, option) + end + end + + def kanji_actual_displayof(window, option=nil) + #if JAPANIZED_TK + if @kanjifont != "" + window = '.' unless window + actual_core(@kanjifont, window, option) + else + actual_core_tk4x(nil, window, option) + end + 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 delete + delete_core + end + + def latin_configure(slot, value=None) + if JAPANIZED_TK + configure_core(@latinfont, slot, value) + else + configure(slot, value) + end + end + + def latin_configinfo(slot=nil) + if JAPANIZED_TK + configinfo_core(@latinfont, slot) + else + configure(slot, value) + end + end + + def kanji_configure(slot, value=None) + #if JAPANIZED_TK + if @kanjifont != "" + configure_core(@kanjifont, slot, value) + configure('size'=>configinfo('size')) # to reflect new configuration + else + #"" + configure(slot, value) + end + end + + def kanji_configinfo(slot=nil) + #if JAPANIZED_TK + if @kanjifont != "" + configinfo_core(@kanjifont, slot) + else + #[] + configinfo(slot) + end + end + + def replace(ltn, knj) + latin_replace(ltn) + kanji_replace(knj) + self + end + + def latin_replace(ltn) + latin_replace_core(ltn) + reset_pointadjust + end + + def kanji_replace(knj) + kanji_replace_core(knj) + reset_pointadjust + 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) + if JAPANIZED_TK + metrics_core(@kanjifont, nil, option) + else + metrics_core_tk4x(nil, nil, option) + end + end + + def kanji_metrics_displayof(window, option=nil) + if JAPANIZED_TK + window = '.' unless window + metrics_core(@kanjifont, window, option) + else + metrics_core_tk4x(nil, window, option) + end + end + + def reset_pointadjust + begin + if /^8\.*/ === Tk::TK_VERSION && JAPANIZED_TK + configure('pointadjust' => latin_actual.assoc('size')[1].to_f / + kanji_actual.assoc('size')[1].to_f ) + end + rescue + end + self + 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 + +module TkTreatTagFont + def font_configinfo + @parent.tagfont_configinfo(@id) + end + alias font font_configinfo + + def font_configure(slot) + @parent.tagfont_configure(@id, slot) + end + + def latinfont_configure(ltn, keys=nil) + @parent.latintagfont_configure(@id, ltn, keys) + end + alias asciifont_configure latinfont_configure + + def kanjifont_configure(knj, keys=nil) + @parent.kanjitagfont_configure(@id, ltn, keys) + end + + def font_copy(window, wintag=nil) + @parent.tagfont_copy(@id, window, wintag) + end + + def latinfont_copy(window, wintag=nil) + @parent.latintagfont_copy(@id, window, wintag) + end + alias asciifont_copy latinfont_copy + + def kanjifont_copy(window, wintag=nil) + @parent.kanjitagfont_copy(@id, window, wintag) + end +end diff --git a/ext/tk/lib/tkmenubar.rb b/ext/tk/lib/tkmenubar.rb new file mode 100644 index 0000000000..441f3f5c03 --- /dev/null +++ b/ext/tk/lib/tkmenubar.rb @@ -0,0 +1,137 @@ +# +# tkmenubar.rb +# +# Copyright (C) 1998 maeda shugo. All rights reserved. +# This file can be distributed under the terms of the Ruby. + +# Usage: +# +# menu_spec = [ +# [['File', 0], +# ['Open', proc{puts('Open clicked')}, 0], +# '---', +# ['Quit', proc{exit}, 0]], +# [['Edit', 0], +# ['Cut', proc{puts('Cut clicked')}, 2], +# ['Copy', proc{puts('Copy clicked')}, 0], +# ['Paste', proc{puts('Paste clicked')}, 0]] +# ] +# menubar = TkMenubar.new(nil, menu_spec, +# 'tearoff'=>false, +# 'foreground'=>'grey40', +# 'activeforeground'=>'red', +# 'font'=>'-adobe-helvetica-bold-r-*--12-*-iso8859-1') +# menubar.pack('side'=>'top', 'fill'=>'x') +# +# +# OR +# +# +# menubar = TkMenubar.new +# menubar.add_menu([['File', 0], +# ['Open', proc{puts('Open clicked')}, 0], +# '---', +# ['Quit', proc{exit}, 0]]) +# menubar.add_menu([['Edit', 0], +# ['Cut', proc{puts('Cut clicked')}, 2], +# ['Copy', proc{puts('Copy clicked')}, 0], +# ['Paste', proc{puts('Paste clicked')}, 0]]) +# menubar.configure('tearoff', false) +# menubar.configure('foreground', 'grey40') +# menubar.configure('activeforeground', 'red') +# menubar.configure('font', '-adobe-helvetica-bold-r-*--12-*-iso8859-1') +# menubar.pack('side'=>'top', 'fill'=>'x') + +# The format of the menu_spec is: +# [ +# [ +# [button text, underline, accelerator], +# [menu label, command, underline, accelerator], +# '---', # separator +# ... +# ], +# ... +# ] + +# underline and accelerator are optional parameters. +# Hashes are OK instead of Arrays. + +# To use add_menu, configuration must be done by calling configure after +# adding all menus by add_menu, not by the constructor arguments. + +require "tk" + +class TkMenubar item_info) + end + end + + mbtn.menu(menu) + @menus.push([mbtn, menu]) + delegate('tearoff', menu) + delegate('foreground', mbtn, menu) + delegate('background', mbtn, menu) + delegate('disabledforeground', mbtn, menu) + delegate('activeforeground', mbtn, menu) + delegate('activebackground', mbtn, menu) + delegate('font', mbtn, menu) + delegate('kanjifont', mbtn, menu) + mbtn.pack('side' => 'left') + end + + def [](index) + return @menus[index] + end +end diff --git a/ext/tk/lib/tkmngfocus.rb b/ext/tk/lib/tkmngfocus.rb new file mode 100644 index 0000000000..921fb646e7 --- /dev/null +++ b/ext/tk/lib/tkmngfocus.rb @@ -0,0 +1,27 @@ +# +# tkmngfocus.rb : methods for Tcl/Tk standard library 'focus.tcl' +# 1998/07/16 by Hidetoshi Nagai +# +require 'tk' + +module TkManageFocus + extend Tk + + def TkManageFocus.followsMouse + tk_call 'tk_focusFollowsMouse' + end + + def TkManageFocus.next(window) + tk_call 'tk_focusNext', window + end + def focusNext + TkManageFocus.next(self) + end + + def TkManageFocus.prev(window) + tk_call 'tk_focusPrev', window + end + def focusPrev + TkManageFocus.prev(self) + end +end diff --git a/ext/tk/lib/tkpalette.rb b/ext/tk/lib/tkpalette.rb new file mode 100644 index 0000000000..a2dc7c87cb --- /dev/null +++ b/ext/tk/lib/tkpalette.rb @@ -0,0 +1,48 @@ +# +# tkpalette.rb : methods for Tcl/Tk standard library 'palette.tcl' +# 1998/06/21 by Hidetoshi Nagai +# +require 'tk' + +module TkPalette + include Tk + extend Tk + + def TkPalette.set(*args) + args = args.to_a.flatten if args.kind_of? Hash + tk_call 'tk_setPalette', *args + end + def TkPalette.setPalette(*args) + TkPalette.set(*args) + end + + def TkPalette.bisque + tk_call 'tk_bisque' + end + + def TkPalette.darken(color, percent) + tk_call 'tkDarken', color, percent + end + + def TkPalette.recolorTree(window, colors) + if not colors.kind_of?(Hash) + fail "2nd arg need to be Hash" + end + + colors.each{|key, value| + begin + if window.cget(key) == tk_call('set', "tkPalette(#{key})") + window[key] = colors[key] + end + rescue + # ignore + end + } + + TkWinfo.children(window).each{|w| TkPalette.recolorTree(w, colors)} + end + + def recolorTree(colors) + TkPalette.recolorTree(self, colors) + end +end diff --git a/ext/tk/lib/tkscrollbox.rb b/ext/tk/lib/tkscrollbox.rb new file mode 100644 index 0000000000..6236430491 --- /dev/null +++ b/ext/tk/lib/tkscrollbox.rb @@ -0,0 +1,29 @@ +# +# tkscrollbox.rb - Tk Listbox with Scrollbar +# as an example of Composite Widget +# $Date$ +# by Yukihiro Matsumoto + +require 'tk.rb' + +class TkScrollbox'left','fill'=>'both','expand'=>'yes' + scroll.configure 'command', list.path+" yview" + scroll.pack 'side'=>'right','fill'=>'y' + + delegate('DEFAULT', list) + delegate('foreground', list) + delegate('background', list, scroll) + delegate('borderwidth', @frame) + delegate('relief', @frame) + + configure keys if keys + end +end diff --git a/ext/tk/lib/tktext.rb b/ext/tk/lib/tktext.rb new file mode 100644 index 0000000000..324af90f85 --- /dev/null +++ b/ext/tk/lib/tktext.rb @@ -0,0 +1,946 @@ +# +# tktext.rb - Tk text classes +# $Date$ +# by Yukihiro Matsumoto + +require 'tk.rb' +require 'tkfont' + +module TkTreatTextTagFont + def tagfont_configinfo(tag) + if tag.kind_of? TkTextTag + pathname = self.path + ';' + tag.id + else + pathname = self.path + ';' + tag + end + ret = TkFont.used_on(pathname) + if ret == nil + ret = TkFont.init_widget_font(pathname, + self.path, 'tag', 'configure', tag) + end + ret + end + alias tagfontobj tagfont_configinfo + + def tagfont_configure(tag, slot) + if tag.kind_of? TkTextTag + pathname = self.path + ';' + tag.id + else + pathname = self.path + ';' + tag + end + if (fnt = slot['font']) + slot['font'] = nil + if fnt.kind_of? TkFont + return fnt.call_font_configure(pathname, + self.path,'tag','configure',tag,slot) + else + latintagfont_configure(tag, fnt) if fnt + end + end + if (ltn = slot['latinfont']) + slot['latinfont'] = nil + latintagfont_configure(tag, ltn) if ltn + end + if (ltn = slot['asciifont']) + slot['asciifont'] = nil + latintagfont_configure(tag, ltn) if ltn + end + if (knj = slot['kanjifont']) + slot['kanjifont'] = nil + kanjitagfont_configure(tag, knj) if knj + end + + tk_call(self.path, 'tag', 'configure', tag, *hash_kv(slot)) if slot != {} + self + end + + def latintagfont_configure(tag, ltn, keys=nil) + fobj = tagfontobj(tag) + if ltn.kind_of? TkFont + conf = {} + ltn.latin_configinfo.each{|key,val| conf[key] = val if val != []} + if conf == {} + fobj.latin_replace(ltn) + fobj.latin_configure(keys) if keys + elsif keys + fobj.latin_configure(conf.update(keys)) + else + fobj.latin_configure(conf) + end + else + fobj.latin_replace(ltn) + end + end + alias asciitagfont_configure latintagfont_configure + + def kanjitagfont_configure(tag, knj, keys=nil) + fobj = tagfontobj(tag) + if knj.kind_of? TkFont + conf = {} + knj.kanji_configinfo.each{|key,val| conf[key] = val if val != []} + if conf == {} + fobj.kanji_replace(knj) + fobj.kanji_configure(keys) if keys + elsif keys + fobj.kanji_configure(conf.update(keys)) + else + fobj.kanji_configure(conf) + end + else + fobj.kanji_replace(knj) + end + end + + def tagfont_copy(tag, window, wintag=nil) + if wintag + window.tagfontobj(wintag).configinfo.each{|key,value| + tagfontobj(tag).configure(key,value) + } + tagfontobj(tag).replace(window.tagfontobj(wintag).latin_font, + window.tagfontobj(wintag).kanji_font) + else + window.tagfont(wintag).configinfo.each{|key,value| + tagfontobj(tag).configure(key,value) + } + tagfontobj(tag).replace(window.fontobj.latin_font, + window.fontobj.kanji_font) + end + end + + def latintagfont_copy(tag, window, wintag=nil) + if wintag + tagfontobj(tag).latin_replace(window.tagfontobj(wintag).latin_font) + else + tagfontobj(tag).latin_replace(window.fontobj.latin_font) + end + end + alias asciitagfont_copy latintagfont_copy + + def kanjitagfont_copy(tag, window, wintag=nil) + if wintag + tagfontobj(tag).kanji_replace(window.tagfontobj(wintag).kanji_font) + else + tagfontobj(tag).kanji_replace(window.fontobj.kanji_font) + end + end +end + +class TkText", mode + id + # _addcmd cmd + end + private :_tag_bind_core + + def tag_bind(tag, seq, cmd=Proc.new, args=nil) + _tag_bind_core('', tag, seq, cmd, args=nil) + end + + def tag_bind_append(tag, seq, cmd=Proc.new, args=nil) + _tag_bind_core('+', tag, seq, cmd, 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(/>val}) + else + tk_send 'tag', 'configure', tag, "-#{key}", val + end + end + end + + def tag_configinfo(tag, key=nil) + if key + conf = tk_split_list(tk_send('tag','configure',tag,"-#{key}")) + conf[0] = conf[0][1..-1] + conf + else + tk_split_list(tk_send('tag', 'configure', tag)).collect{|conf| + conf[0] = conf[0][1..-1] + conf + } + end + end + + def tag_raise(tag, above=None) + tk_send 'tag', 'raise', tag, above + end + + def tag_lower(tag, below=None) + tk_send 'tag', 'lower', tag, below + end + + def tag_remove(tag, *index) + tk_send 'tag', 'remove', tag, *index + end + + def tag_ranges(tag) + l = tk_split_simplelist(tk_send('tag', 'ranges', tag)) + r = [] + while key=l.shift + r.push [key, l.shift] + end + r + end + + def tag_nextrange(tag, first, last=None) + tk_split_simplelist(tk_send('tag', 'nextrange', tag, first, last)) + end + + def tag_prevrange(tag, first, last=None) + tk_split_simplelist(tk_send('tag', 'prevrange', tag, first, last)) + end + + def search_with_length(pat,start,stop=None) + pat = pat.char if pat.kind_of? Integer + if stop != None + return ["", 0] if compare(start,'>=',stop) + txt = get(start,stop) + if (pos = txt.index(pat)) + pos = txt[0..(pos-1)].split('').length if pos > 0 + if pat.kind_of? String + return [index(start + " + #{pos} chars"), pat.split('').length] + else + return [index(start + " + #{pos} chars"), $&.split('').length] + end + else + return ["", 0] + end + else + txt = get(start,'end - 1 char') + if (pos = txt.index(pat)) + pos = txt[0..(pos-1)].split('').length if pos > 0 + if pat.kind_of? String + return [index(start + " + #{pos} chars"), pat.split('').length] + else + return [index(start + " + #{pos} chars"), $&.split('').length] + end + else + txt = get('1.0','end - 1 char') + if (pos = txt.index(pat)) + pos = txt[0..(pos-1)].split('').length if pos > 0 + if pat.kind_of? String + return [index("1.0 + #{pos} chars"), pat.split('').length] + else + return [index("1.0 + #{pos} chars"), $&.split('').length] + end + else + return ["", 0] + end + end + end + end + + def search(pat,start,stop=None) + search_with_length(pat,start,stop)[0] + end + + def rsearch_with_length(pat,start,stop=None) + pat = pat.char if pat.kind_of? Integer + if stop != None + return ["", 0] if compare(start,'<=',stop) + txt = get(stop,start) + if (pos = txt.rindex(pat)) + pos = txt[0..(pos-1)].split('').length if pos > 0 + if pat.kind_of? String + return [index(stop + " + #{pos} chars"), pat.split('').length] + else + return [index(stop + " + #{pos} chars"), $&.split('').length] + end + else + return ["", 0] + end + else + txt = get('1.0',start) + if (pos = txt.rindex(pat)) + pos = txt[0..(pos-1)].split('').length if pos > 0 + if pat.kind_of? String + return [index("1.0 + #{pos} chars"), pat.split('').length] + else + return [index("1.0 + #{pos} chars"), $&.split('').length] + end + else + txt = get('1.0','end - 1 char') + if (pos = txt.rindex(pat)) + pos = txt[0..(pos-1)].split('').length if pos > 0 + if pat.kind_of? String + return [index("1.0 + #{pos} chars"), pat.split('').length] + else + return [index("1.0 + #{pos} chars"), $&.split('').length] + end + else + return ["", 0] + end + end + end + end + + def rsearch(pat,start,stop=None) + rsearch_with_length(pat,start,stop)[0] + end +end + +class TkTextTag", id + # @t._addcmd cmd + end + + 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(/> 0 + tk_call @t.path, 'window', 'configure', @index, *hash_kv(slot) + end + else + @id = value if slot == 'window' + if slot == 'create' + self.create=value + else + tk_call @t.path, 'window', 'configure', @index, "-#{slot}", value + end + end + end + + def window + @id + end + + def window=(value) + tk_call @t.path, 'window', 'configure', @index, '-window', value + @id = value + end + + def create + @p_create + end + + def create=(value) + @p_create = value + if @p_create.kind_of? Proc + value = install_cmd(proc{@id = @p_create.call}) + end + tk_call @t.path, 'window', 'configure', @index, '-create', value + end + + def configinfo(slot = nil) + if slot + conf = tk_split_list(tk_call @t.path, 'window', 'configure', + @index, "-#{slot}") + conf[0] = conf[0][1..-1] + conf + else + tk_split_list(tk_call @t.path, 'window', 'configure', + @index).collect{|conf| + conf[0] = conf[0][1..-1] + conf + } + end + end + + def _dump(type, *index) + str = tk_send('dump', type, *index) + result = [] + sel = nil + i = 0 + while i < str.size + # retrieve key + idx = str.index(/ /, i) + result.push str[i..(idx-1)] + i = idx + 1 + + # retrieve value + case result[-1] + when 'text' + if str[i] == ?{ + # text formed as {...} + val, i = _retrieve_braced_text(str, i) + result.push val + else + # text which may contain backslahes + val, i = _retrieve_backslashed_text(str, i) + result.push val + end + else + idx = str.index(/ /, i) + val = str[i..(idx-1)] + case result[-1] + when 'mark' + case val + when 'insert' + result.push TkTextMarkInsert.new(self) + when 'current' + result.push TkTextMarkCurrent.new(self) + when 'anchor' + result.push TkTextMarkAnchor.new(self) + else + result.push tk_tcl2rb(val) + end + when 'tagon' + if val == 'sel' + if sel + result.push sel + else + result.push TkTextTagSel.new(self) + end + else + result.push tk_tcl2rb val + end + when 'tagoff' + result.push tk_tcl2rb sel + when 'window' + result.push tk_tcl2rb val + end + i = idx + 1 + end + + # retrieve index + idx = str.index(/ /, i) + if idx + result.push str[i..(idx-1)] + i = idx + 1 + else + result.push str[i..-1] + break + end + end + + kvis = [] + until result.empty? + kvis.push [result.shift, result.shift, result.shift] + end + kvis # result is [[key1, value1, index1], [key2, value2, index2], ...] + end + private :_dump + + def _retrieve_braced_text(str, i) + cnt = 0 + idx = i + while idx < str.size + case str[idx] + when ?{ + cnt += 1 + when ?} + cnt -= 1 + if cnt == 0 + break + end + end + idx += 1 + end + return str[i+1..idx-1], idx + 2 + end + private :_retrieve_braced_text + + def _retrieve_backslashed_text(str, i) + j = i + idx = nil + loop { + idx = str.index(/ /, j) + if str[idx-1] == ?\\ + j += 1 + else + break + end + } + val = str[i..(idx-1)] + val.gsub!(/\\( |\{|\})/, '\1') + return val, idx + 1 + end + private :_retrieve_backslashed_text + + def dump_all(*index) + _dump('-all', *index) + end + def dump_mark(*index) + _dump('-mark', *index) + end + def dump_tag(*index) + _dump('-tag', *index) + end + def dump_text(*index) + _dump('-text', *index) + end + def dump_window(*index) + _dump('-window', *index) + end +end + +class TkTextImage +# +require 'tk' + +class TkVirtualEvent", TkVirturlEventID[0]) + TkVirturlEventID[0] += 1 + add(*sequences) + end + + def add(*sequences) + if sequences != [] + tk_call('event', 'add', "<#{@id}>", + *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) ) + TkVirturlEventTBL[@id] = self + end + self + end + + def delete(*sequences) + if sequences == [] + tk_call('event', 'delete', "<#{@id}>") + TkVirturlEventTBL[@id] = nil + else + tk_call('event', 'delete', "<#{@id}>", + *(sequences.collect{|seq| "<#{tk_event_sequence(seq)}>"}) ) + TkVirturlEventTBL[@id] = nil if info == [] + end + self + end + + def info + tk_call('event', 'info', "<#{@id}>").split(/\s+/).filter{|seq| + l = seq.scan(/<*[^<>]+>*/).filter{|subseq| + case (subseq) + when /^<<[^<>]+>>$/ + TkVirtualEvent.getobj(subseq[1..-2]) + when /^<[^<>]+>$/ + subseq[1..-2] + else + subseq.split('') + end + }.flatten + (l.size == 1) ? l[0] : l + } + end +end -- cgit v1.2.3