diff options
author | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2002-06-04 07:03:33 +0000 |
---|---|---|
committer | nagai <nagai@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2002-06-04 07:03:33 +0000 |
commit | 4cb164ee2a30ecb59ce93670e569f384c7da7521 (patch) | |
tree | b72a391e53110bb8b216ef9d16741b314f148ce6 | |
parent | dc010ff5157787b80ed35410587d0b988d55dda4 (diff) | |
download | ruby-4cb164ee2a30ecb59ce93670e569f384c7da7521.tar.gz |
* tkfont.rb: Fix bugs on TkFont.init_widget_font for Tk8.x.
* tkafter.rb: Add self to 1st argument of interval- and loop-proc
TkAfter#current_interval returns an interval (sleep) time value
TkAfter#current_args returns an array of arguments
TkAfter#return_value returns a return value of last loop-proc
e.g.
TkAfter.new(
proc{|obj| 500 - obj.current_interval}, 10,
[proc{|obj| p obj.current_args}, 'proc', 1],
proc{|obj| p obj.current_args; ['return', 2]},
[proc{|obj|
p obj.return_value
p ['proc', obj.current_args[0].call(obj.return_value[1],
obj.current_args[1])]},
proc{|*args| args[0] + args[1]}, 1],
proc{p ['proc', 4]} ).start(100)
* tk*.rb: Allow to use Symbols for parameters.
Allow new notation of constructor (also allow old notation).
e.g.
TkFrame.new('classname'=>'User'){|base|
pack
f = TkFrame.new(base, :classname=>'ButtonFrame').pack
TkButton.new(
:parent => f,
:text => 'Quit',
:command => proc{exit}
).pack(
:fill => :x,
:pady => 2
)
}
* tkcanvas.rb: (TkcItem) Add 'coords' parameter to the canvas item
constructor (for new notation of constructor).
e.g.
c = TkCanvas.new.pack
l = TkcLine.new(c, :coords=>[[0,0], [100,100]])
* tcltklib.c: New 'mainloop' and 'mainloop_watchdog'.
The priority of their event-loop can be controlled.
They accept an optional argument.
If it false, they don't exit although the root widget is destroyed.
This function is sometimes useful, if it is used with 'restart'.
'mainloop' can't treat Thread#join/value in a callback routine.
(e.g. TkButton.new(:command=>proc{p Thread.new{button.invoke}.value}) )
'mainloop_watchdog' can treat them, but watchdog thread is always running
(so, a little heavier than 'mainloop').
If the purpose of using Thread#join/value is to do something under some
safe-level, please use Proc object.
(e.g. :command=>proc{$SAFE=1;proc{$SAFE=2;button.invoke}.call;p $SAFE})
* tk.rb: Support functions of new 'mainloop' and 'mainloop_watchdog'.
* tk.rb: (Tk.restart) Add 'app-name' paramater and 'use' parameter.
'app-name' specifies the name and the resource class of the
application. If 'app-name' is specified to 'xxx', the application
class on the resource database is set to 'Xxx' and the application
name is changed by the same rule of Tk.appname method. 'use'
specifies the main window for embedding the root widget instead of
generating a new window.
* tk.rb: Add new parameter 'widgetname' to the widget constructor to
support effective use of Resource Database. For example, the
resource 'Xxx*quit.text: QUIT' can set the text of the button
generated by the following code.
e.g.
Tk.restart('Xxx')
TkButton.new(nil, 'widgetname'=>'quit', 'command'=>proc{exit}).pack
Tk.mainloop
* tk.rb: TkOption::get always returns a tainted string.
Add TkOption::new_proc_class.
It generates a class to import procedures defined on the resource
database. For example, there is a following resource file.
----< resource-test >------------
*CMD.foo: {|*args| p [$SAFE, :foo, args]}
*CMD.XXX.bar: {|*args| p [$SAFE, :bar, args]}
*Button.command: ruby {p self; p $SAFE; TkOption::CMD::XXX.bar(1,2,3)}
---------------------------------
The following code is a sample of use of the resource file.
e.g.
require 'tk'
TkOption.readfile 'resource-test'
p TkOption.new_proc_class(:CMD, [:foo], 1)
p TkOption.new_proc_class(:XXX, [:bar], 2, false, TkOption::CMD)
TkButton.new(:text=>'test').pack
Tk.mainloop
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@2515 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ext/tcltklib/tcltklib.c | 410 | ||||
-rw-r--r-- | ext/tk/lib/tk.rb | 296 | ||||
-rw-r--r-- | ext/tk/lib/tkafter.rb | 42 | ||||
-rw-r--r-- | ext/tk/lib/tkcanvas.rb | 33 | ||||
-rw-r--r-- | ext/tk/lib/tkclass.rb | 11 | ||||
-rw-r--r-- | ext/tk/lib/tkdialog.rb | 1 | ||||
-rw-r--r-- | ext/tk/lib/tkentry.rb | 7 | ||||
-rw-r--r-- | ext/tk/lib/tkfont.rb | 17 | ||||
-rw-r--r-- | ext/tk/lib/tkmenubar.rb | 10 | ||||
-rw-r--r-- | ext/tk/lib/tktext.rb | 65 |
10 files changed, 721 insertions, 171 deletions
diff --git a/ext/tcltklib/tcltklib.c b/ext/tcltklib/tcltklib.c index 990fbc38af..ba7fdc5000 100644 --- a/ext/tcltklib/tcltklib.c +++ b/ext/tcltklib/tcltklib.c @@ -48,20 +48,44 @@ int *tclDummyMathPtr = (int *) matherr; /*---- module TclTkLib ----*/ struct invoke_queue { + Tcl_Event ev; int argc; VALUE *argv; VALUE obj; int done; - VALUE result; + int safe_level; + VALUE *result; VALUE thread; - struct invoke_queue *next; }; -static struct invoke_queue *iqueue; static VALUE main_thread; +static VALUE eventloop_thread; +static VALUE watchdog_thread; +Tcl_Interp *current_interp; + +/* + * 'event_loop_max' is a maximum events which the eventloop processes in one + * term of thread scheduling. 'no_event_tick' is the count-up value when + * there are no event for processing. + * 'timer_tick' is a limit of one term of thread scheduling. + * If 'timer_tick' == 0, then not use the timer for thread scheduling. + */ +static int tick_counter; +#define DEFAULT_EVENT_LOOP_MAX 800 +#define DEFAULT_NO_EVENT_TICK 10 +#define DEFAULT_TIMER_TICK 0 +static int event_loop_max = DEFAULT_EVENT_LOOP_MAX; +static int no_event_tick = DEFAULT_NO_EVENT_TICK; +static int timer_tick = DEFAULT_TIMER_TICK; + +#if TCL_MAJOR_VERSION >= 8 +static int ip_ruby _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); +#else +static int ip_ruby _((ClientData, Tcl_Interp *, int, char **)); +#endif /* Tk_ThreadTimer */ -static Tcl_TimerToken timer_token; +static Tcl_TimerToken timer_token = (Tcl_TimerToken)NULL; /* timer callback */ static void _timer_for_tcl _((ClientData)); @@ -73,44 +97,230 @@ _timer_for_tcl(clientData) VALUE thread; Tk_DeleteTimerHandler(timer_token); - timer_token = Tk_CreateTimerHandler(100, _timer_for_tcl, (ClientData)0); - - CHECK_INTS; - q = iqueue; - while (q) { - tmp = q; - q = q->next; - if (!tmp->done) { - tmp->done = 1; - tmp->result = ip_invoke_real(tmp->argc, tmp->argv, tmp->obj); - thread = tmp->thread; - tmp = tmp->next; - rb_thread_run(thread); + if (timer_tick > 0) { + timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl, + (ClientData)0); + } else { + timer_token = (Tcl_TimerToken)NULL; + } + + /* rb_thread_schedule(); */ + timer_tick += event_loop_max; +} + +static VALUE +set_eventloop_tick(self, tick) + VALUE self; + VALUE tick; +{ + int ttick = NUM2INT(tick); + + if (ttick < 0) { + rb_raise(rb_eArgError, "timer-tick parameter must be 0 or plus number"); + } + + /* delete old timer callback */ + Tk_DeleteTimerHandler(timer_token); + + timer_tick = ttick; + if (timer_tick > 0) { + /* start timer callback */ + timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl, + (ClientData)0); + } else { + timer_token = (Tcl_TimerToken)NULL; + } + + return tick; +} + +static VALUE +get_eventloop_tick(self) + VALUE self; +{ + return INT2NUM(timer_tick); +} + +static VALUE +set_eventloop_weight(self, loop_max, no_event) + VALUE self; + VALUE loop_max; + VALUE no_event; +{ + int lpmax = NUM2INT(loop_max); + int no_ev = NUM2INT(no_event); + + if (lpmax <= 0 || no_ev <= 0) { + rb_raise(rb_eArgError, "weight parameters must be plus number"); + } + + event_loop_max = lpmax; + no_event_tick = no_ev; + + return rb_ary_new3(2, loop_max, no_event); +} + +static VALUE +get_eventloop_weight(self) + VALUE self; +{ + return rb_ary_new3(2, INT2NUM(event_loop_max), INT2NUM(no_event_tick)); +} + +VALUE +lib_mainloop_core(check_root_widget) + VALUE check_root_widget; +{ + VALUE current = eventloop_thread; + int check = (check_root_widget == Qtrue); + + Tk_DeleteTimerHandler(timer_token); + if (timer_tick > 0) { + timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl, + (ClientData)0); + } else { + timer_token = (Tcl_TimerToken)NULL; + } + + for(;;) { + tick_counter = 0; + while(tick_counter < event_loop_max) { + if (Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT)) { + tick_counter++; + } else { + tick_counter += no_event_tick; } + if (watchdog_thread != 0 && eventloop_thread != current) { + return Qnil; + } + } + if (check && Tk_GetNumMainWindows() == 0) { + break; + } + rb_thread_schedule(); } - rb_thread_schedule(); + return Qnil; } -#if TCL_MAJOR_VERSION >= 8 -static int ip_ruby _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); -#else -static int ip_ruby _((ClientData, Tcl_Interp *, int, char **)); -#endif + +VALUE +lib_mainloop_ensure(parent_evloop) + VALUE parent_evloop; +{ + if (ruby_debug) { + fprintf(stderr, "tcltklib: eventloop-thread : %lx -> %lx\n", + eventloop_thread, parent_evloop); + } + + Tk_DeleteTimerHandler(timer_token); + timer_token = (Tcl_TimerToken)NULL; + eventloop_thread = parent_evloop; + return Qnil; +} + +static VALUE +lib_mainloop_launcher(check_rootwidget) + VALUE check_rootwidget; +{ + VALUE parent_evloop = eventloop_thread; + + eventloop_thread = rb_thread_current(); + + if (ruby_debug) { + fprintf(stderr, "tcltklib: eventloop-thread : %lx -> %lx\n", + parent_evloop, eventloop_thread); + } + + return rb_ensure(lib_mainloop_core, check_rootwidget, + lib_mainloop_ensure, parent_evloop); +} /* execute Tk_MainLoop */ static VALUE -lib_mainloop(self) +lib_mainloop(argc, argv, self) + int argc; + VALUE *argv; VALUE self; { - timer_token = Tk_CreateTimerHandler(100, _timer_for_tcl, (ClientData)0); - DUMP1("start Tk_Mainloop"); - Tk_MainLoop(); - DUMP1("stop Tk_Mainloop"); - Tk_DeleteTimerHandler(timer_token); + VALUE check_rootwidget; + + if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { + check_rootwidget = Qtrue; + } else if (RTEST(check_rootwidget)) { + check_rootwidget = Qtrue; + } else { + check_rootwidget = Qfalse; + } + + return lib_mainloop_launcher(check_rootwidget); +} + +static VALUE +lib_mainloop_watchdog(argc, argv, self) + int argc; + VALUE *argv; + VALUE self; +{ + VALUE check_rootwidget; + VALUE evloop; + int check; + ID stop; + + if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) { + check_rootwidget = Qtrue; + } else if (RTEST(check_rootwidget)) { + check_rootwidget = Qtrue; + } else { + check_rootwidget = Qfalse; + } + check = (check_rootwidget == Qtrue); + stop = rb_intern("stop?"); + + /* check other watchdog thread */ + if (watchdog_thread != 0) { + if (rb_funcall(watchdog_thread, stop, 0) == Qtrue) { + rb_funcall(watchdog_thread, rb_intern("kill"), 0); + } else { + return Qnil; + } + } + watchdog_thread = rb_thread_current(); + + /* watchdog start */ + do { + if (eventloop_thread == 0 + || rb_funcall(eventloop_thread, stop, 0) == Qtrue) { + /* start new eventloop thread */ + DUMP2("eventloop thread %lx is sleeping or dead", eventloop_thread); + evloop = rb_thread_create(lib_mainloop_launcher, + (void*)&check_rootwidget); + DUMP2("create new eventloop thread %lx", evloop); + rb_thread_run(evloop); + } + rb_thread_schedule(); + } while(!check || Tk_GetNumMainWindows() != 0); return Qnil; } +static VALUE +lib_do_one_event(argc, argv, self) + int argc; + VALUE *argv; + VALUE self; +{ + VALUE obj, vflags; + int flags; + + if (rb_scan_args(argc, argv, "01", &vflags) == 0) { + flags = 0; + } else { + Check_Type(vflags, T_FIXNUM); + flags = FIX2INT(vflags); + } + return INT2NUM(Tcl_DoOneEvent(flags)); +} + /*---- class TclTkIp ----*/ struct tcltkip { Tcl_Interp *ip; /* the interpreter */ @@ -245,6 +455,7 @@ ip_new(self) /* from Tk_Main() */ DUMP1("Tcl_CreateInterp"); ptr->ip = Tcl_CreateInterp(); + current_interp = ptr->ip; /* from Tcl_AppInit() */ DUMP1("Tcl_Init"); @@ -459,48 +670,103 @@ ip_invoke_real(argc, argv, obj) return rb_str_new2(ptr->ip->result); } +VALUE +ivq_safelevel_handler(arg, ivq) + VALUE arg; + VALUE ivq; +{ + struct invoke_queue *q; + + Data_Get_Struct(ivq, struct invoke_queue, q); + DUMP2("(safe-level handler) $SAFE = %d", q->safe_level); + rb_set_safe_level(q->safe_level); + return ip_invoke_real(q->argc, q->argv, q->obj); +} + +int +invoke_queue_handler(evPtr, flags) + Tcl_Event *evPtr; + int flags; +{ + struct invoke_queue *tmp, *q = (struct invoke_queue *)evPtr; + + DUMP1("do_invoke_queue_handler"); + DUMP2("invoke queue_thread : %lx", rb_thread_current()); + DUMP2("added by thread : %lx", q->thread); + + if (q->done) { + /* processed by another event-loop */ + return 0; + } + + /* process it */ + q->done = 1; + + /* check safe-level */ + if (rb_safe_level() != q->safe_level) { + *(q->result) = rb_funcall(rb_proc_new(ivq_safelevel_handler, + Data_Wrap_Struct(rb_cData,0,0,q)), + rb_intern("call"), 0); + } else { + *(q->result) = ip_invoke_real(q->argc, q->argv, q->obj); + } + + /* back to caller */ + rb_thread_run(q->thread); + + /* end of handler : remove it */ + return 1; +} + static VALUE ip_invoke(argc, argv, obj) int argc; VALUE *argv; VALUE obj; { - struct invoke_queue *tmp, *p; - VALUE result = rb_thread_current(); + struct invoke_queue *tmp; + VALUE current = rb_thread_current(); + VALUE result; + VALUE *alloc_argv, *alloc_result; + Tcl_QueuePosition position; - if (result == main_thread) { - return ip_invoke_real(argc, argv, obj); + if (eventloop_thread == 0 || current == eventloop_thread) { + DUMP2("invoke from current eventloop %lx", current); + return ip_invoke_real(argc, argv, obj); } - tmp = ALLOC(struct invoke_queue); + + DUMP2("invoke from thread %lx (NOT current eventloop)", current); + + /* allocate memory (protected from Tcl_ServiceEvent) */ + alloc_argv = ALLOC_N(VALUE,argc); + MEMCPY(alloc_argv, argv, VALUE, argc); + alloc_result = ALLOC(VALUE); + + /* allocate memory (freed by Tcl_ServiceEvent */ + tmp = (struct invoke_queue *)Tcl_Alloc(sizeof(struct invoke_queue)); + + /* construct event data */ + tmp->done = 0; tmp->obj = obj; tmp->argc = argc; - tmp->argv = ALLOC_N(VALUE, argc); - MEMCPY(tmp->argv, argv, VALUE, argc); - tmp->thread = result; - tmp->done = 0; + tmp->argv = alloc_argv; + tmp->result = alloc_result; + tmp->thread = current; + tmp->safe_level = rb_safe_level(); + tmp->ev.proc = invoke_queue_handler; + position = TCL_QUEUE_TAIL; - tmp->next = iqueue; - iqueue = tmp; + /* add the handler to Tcl event queue */ + Tcl_QueueEvent(&tmp->ev, position); + /* wait for the handler to be processed */ rb_thread_stop(); - result = tmp->result; - if (iqueue == tmp) { - iqueue = tmp->next; - free(tmp->argv); - free(tmp); - return result; - } - p = iqueue; - while (p->next) { - if (p->next == tmp) { - p->next = tmp->next; - free(tmp->argv); - free(tmp); - break; - } - p = p->next; - } + /* get result & free allocated memory */ + result = *alloc_result; + free(alloc_argv); + free(alloc_result); + return result; } @@ -533,6 +799,14 @@ Init_tcltklib() VALUE lib = rb_define_module("TclTkLib"); VALUE ip = rb_define_class("TclTkIp", rb_cObject); + VALUE ev_flag = rb_define_module_under(lib, "EventFlag"); + rb_define_const(ev_flag, "WINDOW", INT2FIX(TCL_WINDOW_EVENTS)); + rb_define_const(ev_flag, "FILE", INT2FIX(TCL_FILE_EVENTS)); + rb_define_const(ev_flag, "TIMER", INT2FIX(TCL_TIMER_EVENTS)); + rb_define_const(ev_flag, "IDLE", INT2FIX(TCL_IDLE_EVENTS)); + rb_define_const(ev_flag, "ALL", INT2FIX(TCL_ALL_EVENTS)); + rb_define_const(ev_flag, "DONT_WAIT", INT2FIX(TCL_DONT_WAIT)); + #if defined USE_TCL_STUBS && defined USE_TK_STUBS extern int ruby_tcltk_stubs(); int ret = ruby_tcltk_stubs(); @@ -543,7 +817,16 @@ Init_tcltklib() eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError); eTkCallbackContinue = rb_define_class("TkCallbackContinue",rb_eStandardError); - rb_define_module_function(lib, "mainloop", lib_mainloop, 0); + rb_define_module_function(lib, "mainloop", lib_mainloop, -1); + rb_define_module_function(lib, "mainloop_watchdog", + lib_mainloop_watchdog, -1); + rb_define_module_function(lib, "do_one_event", lib_do_one_event, -1); + rb_define_module_function(lib, "set_eventloop_tick",set_eventloop_tick,1); + rb_define_module_function(lib, "get_eventloop_tick",get_eventloop_tick,0); + rb_define_module_function(lib, "set_eventloop_weight", + set_eventloop_weight, 2); + rb_define_module_function(lib, "get_eventloop_weight", + get_eventloop_weight, 0); rb_define_singleton_method(ip, "new", ip_new, 0); rb_define_method(ip, "_eval", ip_eval, 1); @@ -551,10 +834,19 @@ Init_tcltklib() rb_define_method(ip, "_fromUTF8",ip_fromUTF8,2); rb_define_method(ip, "_invoke", ip_invoke, -1); rb_define_method(ip, "_return_value", ip_retval, 0); - rb_define_method(ip, "mainloop", lib_mainloop, 0); + rb_define_method(ip, "mainloop", lib_mainloop, -1); + rb_define_method(ip, "mainloop_watchdog", lib_mainloop_watchdog, -1); + rb_define_method(ip, "do_one_event", lib_do_one_event, -1); + rb_define_method(ip, "set_eventloop_tick", set_eventloop_tick, 1); + rb_define_method(ip, "get_eventloop_tick", get_eventloop_tick, 0); + rb_define_method(ip, "set_eventloop_weight", set_eventloop_weight, 2); + rb_define_method(ip, "get_eventloop_weight", get_eventloop_weight, 0); rb_define_method(ip, "restart", lib_restart, 0); main_thread = rb_thread_current(); + eventloop_thread = 0; + watchdog_thread = 0; + #ifdef __MACOS__ _macinit(); #endif diff --git a/ext/tk/lib/tk.rb b/ext/tk/lib/tk.rb index bac2ae35f9..2e33c4294c 100644 --- a/ext/tk/lib/tk.rb +++ b/ext/tk/lib/tk.rb @@ -132,6 +132,13 @@ module TkComm end private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist + def _symbolkey2str(keys) + h = {} + keys.each{|key,value| h[key.to_s] = value} + h + end + private :_symbolkey2str + def hash_kv(keys) conf = [] if keys and keys != None @@ -204,6 +211,8 @@ module TkComm return nil if str == None if str.kind_of?(String) # do nothing + elsif str.kind_of?(Symbol) + str = str.id2name elsif str.kind_of?(Hash) str = hash_kv(str).join(" ") elsif str.kind_of?(Array) @@ -259,13 +268,15 @@ module TkComm end private :install_cmd, :uninstall_cmd - def install_win(ppath) - id = format("w%.4d", Tk_IDs[1]) - Tk_IDs[1] += 1 + def install_win(ppath,name=nil) + if !name or name == '' + name = format("w%.4d", Tk_IDs[1]) + Tk_IDs[1] += 1 + end if !ppath or ppath == "." - @path = format(".%s", id); + @path = format(".%s", name); else - @path = format("%s.%s", ppath, id) + @path = format("%s.%s", ppath, name) end Tk_WINDOWS[@path] = self end @@ -483,6 +494,8 @@ module TkCore } EOL + EventFlag = TclTkLib::EventFlag + def callback_break fail TkCallbackBreak, "Tk callback returns 'break' status" end @@ -616,12 +629,42 @@ module TkCore tk_call('info', *args) end - def mainloop - TclTkLib.mainloop + def mainloop(check_root = true) + TclTkLib.mainloop(check_root) end - def restart + def mainloop_watchdog(check_root = true) + TclTkLib.mainloop_watchdog(check_root) + end + + def do_one_event(flag = 0) + TclTkLib.do_one_event(flag) + end + + def set_eventloop_tick(timer_tick) + TclTkLib.set_eventloop_tick(timer_tick) + end + + def get_eventloop_tick() + TclTkLib.get_eventloop_tick + end + + def set_eventloop_weight(loop_max, no_event_tick) + TclTkLib.set_eventloop_weight(loop_max, no_event_tick) + end + + def get_eventloop_weight() + TclTkLib.get_eventloop_weight + end + + def restart(app_name = nil, use = nil) + tk_call('set', 'argv0', app_name) if app_name + if use + tk_call('set', 'argc', 2) + tk_call('set', 'argv', "-use #{use}") + end TkCore::INTERP.restart + TkComm::Tk_CMDTBL.clear TkComm::Tk_WINDOWS.clear nil end @@ -2077,12 +2120,87 @@ module TkOption tk_call 'option', 'clear' end def get win, name, klass - tk_call 'option', 'get', win ,name, klass + tk_call('option', 'get', win ,name, klass).taint end def readfile file, pri=None tk_call 'option', 'readfile', file, pri end module_function :add, :clear, :get, :readfile + + # support procs on the resource database + @@resource_proc_class = Class.new + class << @@resource_proc_class + private :new + + CARRIER = '.'.freeze + METHOD_TBL = {} + ADD_METHOD = false + SAFE_MODE = 4 + + def __check_proc_string__(str) + # If you want to check the proc_string, do it in this method. + str + end + + def method_missing(id, *args) + res_proc = self::METHOD_TBL[id] + unless res_proc.kind_of? Proc + if id == :new || (!self::METHOD_TBL.has_key?(id) && !self::ADD_METHOD) + raise NoMethodError, + "not support resource-proc '#{id.id2name}' for #{self.name}" + end + proc_str = TkOption.get(self::CARRIER, id.id2name, '') + proc_str = '{' + proc_str + '}' unless /\A\{.*\}\Z/ =~ proc_str + proc_str = __check_proc_string__(proc_str) + res_proc = eval 'Proc.new' + proc_str + self::METHOD_TBL[id] = res_proc + end + proc{ + $SAFE = self::SAFE_MODE + res_proc.call(*args) + }.call + end + + private :__check_proc_string__, :method_missing + end + + def new_proc_class(klass, func, safe = 4, add = false, parent = nil) + klass = klass.to_s if klass.kind_of? Symbol + unless (?A..?Z) === klass[0] + fail ArgumentError, "bad string '#{klass}' for class name" + end + unless func.kind_of? Array + fail ArgumentError, "method-list must be Array" + end + func_str = func.join(' ') + if parent == nil + install_win(parent) + elsif parent <= @@resource_proc_class + install_win(parent::CARRIER) + else + fail ArgumentError, "parent must be Resource-Proc class" + end + carrier = Tk.tk_call('frame', @path, '-class', klass) + + body = <<-"EOD" + class #{klass} < TkOption.module_eval('@@resource_proc_class') + CARRIER = '#{carrier}'.freeze + METHOD_TBL = {} + ADD_METHOD = #{add} + SAFE_MODE = #{safe} + %w(#{func_str}).each{|f| METHOD_TBL[f.intern] = nil } + end + EOD + + if parent.kind_of?(Class) && parent <= @@resource_proc_class + parent.class_eval body + eval parent.name + '::' + klass + else + eval body + eval 'TkOption::' + klass + end + end + module_function :new_proc_class end module TkTreatFont @@ -2096,6 +2214,7 @@ module TkTreatFont alias fontobj font_configinfo def font_configure(slot) + slot = _symbolkey2str(slot) if (fnt = slot.delete('font')) if fnt.kind_of? TkFont return fnt.call_font_configure(self.path, self.path,'configure',slot) @@ -2203,6 +2322,7 @@ module TkTreatItemFont def tagfont_configure(tagOrId, slot) pathname = __item_pathname(tagOrId) + slot = _symbolkey2str(slot) if (fnt = slot.delete('font')) if fnt.kind_of? TkFont return fnt.call_font_configure(pathname, self.path, @@ -2345,7 +2465,7 @@ class TkObject<TkKernel end def cget(slot) - case slot + case slot.to_s when 'text', 'label', 'show', 'data', 'file' tk_call path, 'cget', "-#{slot}" else @@ -2355,16 +2475,20 @@ class TkObject<TkKernel def configure(slot, value=None) if slot.kind_of? Hash - if (slot['font'] || slot['kanjifont'] || - slot['latinfont'] || slot['asciifont'] ) - font_configure(slot.dup) + if (slot['font'] || slot[:font] || + slot['kanjifont'] || slot[:kanjifont] || + slot['latinfont'] || slot[:latinfont] || + slot['asciifont'] || slot[:asciifont] ) + font_configure(slot) else tk_call path, 'configure', *hash_kv(slot) end else - if (slot == 'font' || slot == 'kanjifont' || - slot == 'latinfont' || slot == 'asciifont') + if (slot == 'font' || slot == :font || + slot == 'kanjifont' || slot == :kanjifont || + slot == 'latinfont' || slot == :latinfont || + slot == 'asciifont' || slot == :asciifont ) if value == None fontobj else @@ -2381,11 +2505,12 @@ class TkObject<TkKernel end def configinfo(slot = nil) - if slot == 'font' || slot == 'kanjifont' + if slot == 'font' || slot == :font || + slot == 'kanjifont' || slot == :kanjifont fontobj else if slot - case slot + case slot.to_s when 'text', 'label', 'show', 'data', 'file' conf = tk_split_simplelist(tk_send('configure', "-#{slot}") ) else @@ -2455,7 +2580,19 @@ class TkWindow<TkObject extend TkBindCore def initialize(parent=nil, keys=nil) - install_win(if parent then parent.path end) + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + keydup = true + parent = keys.delete('parent') + widgetname = keys.delete('widgetname') + install_win(if parent then parent.path end, widgetname) + elsif keys + keys = _symbolkey2str(keys) + widgetname = keys.delete('widgetname') + install_win(if parent then parent.path end, widgetname) + else + install_win(if parent then parent.path end) + end if self.method(:create_self).arity == 0 p 'create_self has no arg' if $DEBUG create_self @@ -2464,10 +2601,9 @@ class TkWindow<TkObject configure(keys) end else - p 'create_self has an arg' if $DEBUG + p 'create_self has args' if $DEBUG fontkeys = {} if keys - keys = keys.dup ['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key| fontkeys[key] = keys.delete(key) if keys.key?(key) } @@ -2668,17 +2804,17 @@ class TkWindow<TkObject tk_call 'grab', 'set', path elsif args.length == 1 case args[0] - when 'global' + when 'global', :global return(tk_call 'grab', 'set', '-global', path) - when 'release' + when 'release', :release return(tk_call 'grab', 'release', path) else val = tk_call('grab', args[0], path) end case args[0] - when 'current' + when 'current', :current return window(val) - when 'status' + when 'status', :status return val end else @@ -2811,15 +2947,27 @@ class TkToplevel<TkWindow ################# def initialize(parent=nil, screen=nil, classname=nil, keys=nil) + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + @screen = keys['screen'] + @classname = keys['class'] + @colormap = keys['colormap'] + @container = keys['container'] + @screen = keys['screen'] + @use = keys['use'] + @visual = keys['visual'] + super(keys) + return + end if screen.kind_of? Hash - keys = screen + keys = _symbolkey2str(screen) else @screen = screen end @classname = classname if keys.kind_of? Hash - if keys.key?('classname') - keys = keys.dup + keys = _symbolkey2str(keys) + if keys.key?(:classname) || keys.key?('classname') keys['class'] = keys.delete('classname') end @classname = keys['class'] @@ -2875,17 +3023,24 @@ class TkFrame<TkWindow ################# def initialize(parent=nil, keys=nil) - if keys.kind_of? Hash - if keys.key?('classname') - keys = keys.dup - keys['class'] = keys.delete('classname') + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + else + if keys + keys = _symbolkey2str(keys) + keys['parent'] = parent + else + keys = {'parent'=>parent} end - @classname = keys['class'] - @colormap = keys['colormap'] - @container = keys['container'] - @visual = keys['visual'] end - super(parent, keys) + if keys.key?('classname') + keys['class'] = keys.delete('classname') + end + @classname = keys['class'] + @colormap = keys['colormap'] + @container = keys['container'] + @visual = keys['visual'] + super(keys) end def create_self(keys) @@ -3170,7 +3325,7 @@ class TkListbox<TkTextWin end def itemcget(index, key) - case key + case key.to_s when 'text', 'label', 'show' tk_send 'itemcget', index, "-#{key}" else @@ -3179,16 +3334,20 @@ class TkListbox<TkTextWin end def itemconfigure(index, key, val=None) if key.kind_of? Hash - if (key['font'] || key['kanjifont'] || - key['latinfont'] || key['asciifont']) - tagfont_configure(index, key.dup) + if (key['font'] || key[:font] || + key['kanjifont'] || key[:kanjifont] || + key['latinfont'] || key[:latinfont] || + key['asciifont'] || key[:asciifont] ) + tagfont_configure(index, _symbolkey2str(key)) else tk_send 'itemconfigure', index, *hash_kv(key) end else - if (key == 'font' || key == 'kanjifont' || - key == 'latinfont' || key == 'asciifont' ) + if (key == 'font' || key == :font || + key == 'kanjifont' || key == :kanjifont || + key == 'latinfont' || key == :latinfont || + key == 'asciifont' || key == :asciifont ) tagfont_configure(index, {key=>val}) else tk_call 'itemconfigure', index, "-#{key}", val @@ -3198,7 +3357,7 @@ class TkListbox<TkTextWin def itemconfiginfo(index, key=nil) if key - case key + case key.to_s when 'text', 'label', 'show' conf = tk_split_simplelist(tk_send('itemconfigure',index,"-#{key}")) else @@ -3305,7 +3464,7 @@ class TkMenu<TkWindow number(tk_send('yposition', index)) end def entrycget(index, key) - case key + case key.to_s when 'text', 'label', 'show' tk_send 'entrycget', index, "-#{key}" else @@ -3314,16 +3473,20 @@ class TkMenu<TkWindow end def entryconfigure(index, key, val=None) if key.kind_of? Hash - if (key['font'] || key['kanjifont'] || - key['latinfont'] || key['asciifont']) - tagfont_configure(index, key.dup) + if (key['font'] || key[:font] || + key['kanjifont'] || key[:kanjifont] || + key['latinfont'] || key[:latinfont] || + key['asciifont'] || key[:asciifont]) + tagfont_configure(index, _symbolkey2str(key)) else tk_send 'entryconfigure', index, *hash_kv(key) end else - if (key == 'font' || key == 'kanjifont' || - key == 'latinfont' || key == 'asciifont' ) + if (key == 'font' || key == :font || + key == 'kanjifont' || key == :kanjifont || + key == 'latinfont' || key == :latinfont || + key == 'asciifont' || key == :asciifont ) tagfont_configure({key=>val}) else tk_call 'entryconfigure', index, "-#{key}", val @@ -3333,7 +3496,7 @@ class TkMenu<TkWindow def entryconfiginfo(index, key=nil) if key - case key + case key.to_s when 'text', 'label', 'show' conf = tk_split_simplelist(tk_send('entryconfigure',index,"-#{key}")) else @@ -3371,17 +3534,28 @@ end class TkMenuClone<TkMenu def initialize(parent, type=None) + widgetname = nil + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + parent = keys.delete('parent') + widgetname = keys.delete('widgetname') + type = keys.delete('type'); type = None unless type + end unless parent.kind_of?(TkMenu) fail ArgumentError, "parent must be TkMenu" end @parent = parent - install_win(@parent.path) + install_win(@parent.path, widgetname) tk_call @parent.path, 'clone', @path, type end end module TkSystemMenu def initialize(parent, keys=nil) + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + parent = keys.delete('parent') + end fail unless parent.kind_of? TkMenu @path = format("%s.%s", parent.path, self.type::SYSMENU_NAME) TkComm::Tk_WINDOWS[@path] = self @@ -3437,6 +3611,12 @@ class TkOptionMenubutton<TkMenubutton end def initialize(parent=nil, var=TkVariable.new, firstval=nil, *vals) + if parent.kind_of Hash + keys = _symbolkey2str(parent) + parent = keys['parent'] + var = keys['variable'] if keys['variable'] + firstval, *vals = keys['values'] + end fail unless var.kind_of? TkVariable @variable = var firstval = @variable.value unless firstval @@ -3498,9 +3678,17 @@ module TkComposite extend Tk def initialize(parent=nil, *args) - @frame = TkFrame.new(parent) - @path = @epath = @frame.path - initialize_composite(*args) + if parent.kind_of? Hash + keys = _symbolkey2str(parent) + parent = keys['parent'] + keys['parent'] = @frame = TkFrame.new(parent) + @path = @epath = @frame.path + initialize_composite(keys) + else + @frame = TkFrame.new(parent) + @path = @epath = @frame.path + initialize_composite(*args) + end end def epath diff --git a/ext/tk/lib/tkafter.rb b/ext/tk/lib/tkafter.rb index fe3ee38740..ec39d9957f 100644 --- a/ext/tk/lib/tkafter.rb +++ b/ext/tk/lib/tkafter.rb @@ -1,6 +1,7 @@ # # tkafter.rb : methods for Tcl/Tk after command -# 2000/08/01 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> +# +# $Id$ # require 'tk' @@ -11,18 +12,16 @@ class TkAfter Tk_CBID = [0] Tk_CBTBL = {} - INTERP._invoke("proc", "rb_after", "args", "ruby [format \"TkAfter.callback %%Q!%s!\" $args]") + INTERP._invoke("proc", "rb_after", "id", "ruby [format \"TkAfter.callback %%Q!%s!\" $id]") ############################### # class methods ############################### - def TkAfter.callback(arg) + def TkAfter.callback(obj_id) @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)) + _get_eval_string(ex_obj.do_callback) end def TkAfter.info @@ -35,10 +34,10 @@ class TkAfter ############################### # instance methods ############################### - def do_callback(*args) + def do_callback @in_callback = true begin - ret = @current_proc.call(*args) + @return_value = @current_proc.call(self) rescue StandardError, NameError if @cancel_on_exception cancel @@ -48,21 +47,22 @@ class TkAfter end end if @set_next - set_next_callback(*args) + set_next_callback(@current_args) else @set_next = true end @in_callback = false - ret + @return_value end def set_callback(sleep, args=nil) - @after_script = "rb_after #{@id} #{_get_eval_string(args)}" + @after_script = "rb_after #{@id}" @after_id = tk_call('after', sleep, @after_script) + @current_args = args @current_script = [sleep, @after_script] end - def set_next_callback(*args) + def set_next_callback(args) if @running == false || @proc_max == 0 || @do_loop == 0 Tk_CBTBL[@id] = nil ;# for GC @running = false @@ -81,7 +81,7 @@ class TkAfter @current_args = args if @sleep_time.kind_of? Proc - sleep = @sleep_time.call(*args) + sleep = @sleep_time.call(self) else sleep = @sleep_time end @@ -91,15 +91,7 @@ class TkAfter @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) + set_callback(sleep, cmd_args) end def initialize(*args) @@ -115,6 +107,7 @@ class TkAfter @current_script = [] @current_proc = nil @current_args = nil + @return_value = nil @sleep_time = 0 @current_sleep = 0 @@ -137,7 +130,10 @@ class TkAfter attr :after_id attr :after_script attr :current_proc + attr :current_args attr :current_sleep + alias :current_interval :current_sleep + attr :return_value attr_accessor :loop_exec @@ -257,7 +253,7 @@ class TkAfter set_callback(sleep, @init_args) @set_next = false if @in_callback else - set_next_callback(*@init_args) + set_next_callback(@init_args) end self diff --git a/ext/tk/lib/tkcanvas.rb b/ext/tk/lib/tkcanvas.rb index 94376072d3..ac6ed5362f 100644 --- a/ext/tk/lib/tkcanvas.rb +++ b/ext/tk/lib/tkcanvas.rb @@ -1,4 +1,4 @@ - +# # tkcanvas.rb - Tk canvas classes # $Date$ # by Yukihiro Matsumoto <matz@caelum.co.jp> @@ -180,7 +180,7 @@ class TkCanvas<TkWindow end def itemcget(tagOrId, option) - case option + case option.to_s when 'dash', 'activedash', 'disableddash' conf = tk_send('itemcget', tagid(tagOrId), "-#{option}") if conf =~ /^[0-9]/ @@ -197,6 +197,7 @@ class TkCanvas<TkWindow def itemconfigure(tagOrId, key, value=None) if key.kind_of? Hash + key = _symbolkey2str(key) if ( key['font'] || key['kanjifont'] \ || key['latinfont'] || key['asciifont'] ) tagfont_configure(tagOrId, key.dup) @@ -205,8 +206,10 @@ class TkCanvas<TkWindow end else - if ( key == 'font' || key == 'kanjifont' \ - || key == 'latinfont' || key == 'asciifont' ) + if ( key == 'font' || key == :font || + key == 'kanjifont' || key == :kanjifont || + key == 'latinfont' || key == :latinfont || + key == 'asciifont' || key == :asciifont ) tagfont_configure(tagid(tagOrId), {key=>value}) else tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value @@ -226,7 +229,7 @@ class TkCanvas<TkWindow def itemconfiginfo(tagOrId, key=nil) if key - case key + case key.to_s when 'dash', 'activedash', 'disableddash' conf = tk_split_simplelist(tk_send 'itemconfigure', tagid(tagOrId), "-#{key}") @@ -433,7 +436,7 @@ module TkcTagAccess @c.itemtype @id end - # Followings operators supports logical expressions of canvas tags + # Following operators support logical expressions of canvas tags # (for Tk8.3+). # If tag1.path is 't1' and tag2.path is 't2', then # ltag = tag1 & tag2; ltag.path => "(t1)&&(t2)" @@ -473,6 +476,7 @@ class TkcTag<TkObject include TkcTagAccess CTagID_TBL = {} + Tk_CanvasTag_ID = ['ctag0000'] def TkcTag.id2obj(canvas, id) cpath = canvas.path @@ -480,7 +484,6 @@ class TkcTag<TkObject CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id end - Tk_CanvasTag_ID = ['ctag0000'] def initialize(parent, mode=nil, *args) if not parent.kind_of?(TkCanvas) fail format("%s need to be TkCanvas", parent.inspect) @@ -501,7 +504,7 @@ class TkcTag<TkObject def delete @c.delete @id - CTagID_TBL[@path][@id] = nil if CTagID_TBL[@path] + CTagID_TBL[@cpath][@id] = nil if CTagID_TBL[@cpath] end alias remove delete alias destroy delete @@ -565,6 +568,7 @@ class TkcTagString<TkcTag end end end +TkcNamedTag = TkcTagString class TkcTagAll<TkcTag def initialize(parent) @@ -643,9 +647,16 @@ class TkcItem<TkObject @parent = @c = parent @path = parent.path fontkeys = {} + if args.size == 1 && args[0].kind_of?(Hash) + args[0] = _symbolkey2str(args[0]) + coords = args[0].delete('coords') + if not coords.kind_of?(Array) + fail "coords parameter must be given by an Array" + end + args[0,0] = coords.flatten + end if args[-1].kind_of? Hash - args = args.dup - keys = args.pop + keys = _symbolkey2str(args.pop) ['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key| fontkeys[key] = keys.delete(key) if keys.key?(key) } @@ -797,7 +808,7 @@ class TkPhotoImage<TkImage end def cget(option) - case option + case option.to_s when 'data', 'file' tk_send 'cget', option else diff --git a/ext/tk/lib/tkclass.rb b/ext/tk/lib/tkclass.rb index 0b33d4ec8b..9ea275e560 100644 --- a/ext/tk/lib/tkclass.rb +++ b/ext/tk/lib/tkclass.rb @@ -1,7 +1,9 @@ # # tkclass.rb - Tk classes -# $Date$ +# Date: 2000/11/27 09:23:36 # by Yukihiro Matsumoto <matz@caelum.co.jp> +# +# $Id$ require "tk" @@ -13,6 +15,7 @@ Radiobutton = TkRadioButton Checkbutton = TkCheckButton Message = TkMessage Entry = TkEntry +Spinbox = TkSpinbox Text = TkText Scale = TkScale Scrollbar = TkScrollbar @@ -28,10 +31,16 @@ Polygon = TkcPolygon Rectangle = TkcRectangle TextItem = TkcText WindowItem = TkcWindow +BitmapImage = TkBitmapImage +PhotoImage = TkPhotoImage Selection = TkSelection Winfo = TkWinfo Pack = TkPack +Grid = TkGrid +Place = TkPlace Variable = TkVariable +Font = TkFont +VirtualEvent = TkVirtualEvent def Mainloop Tk.mainloop diff --git a/ext/tk/lib/tkdialog.rb b/ext/tk/lib/tkdialog.rb index 1133db6ae9..8b8ee69128 100644 --- a/ext/tk/lib/tkdialog.rb +++ b/ext/tk/lib/tkdialog.rb @@ -23,6 +23,7 @@ class TkDialog < TkWindow @button_configs = proc{|num| button_configs num} if keys.kind_of? Hash + keys = _symbolkey2str(keys) @title = keys['title'] if keys['title'] @message = keys['message'] if keys['message'] @bitmap = keys['bitmap'] if keys['bitmap'] diff --git a/ext/tk/lib/tkentry.rb b/ext/tk/lib/tkentry.rb index f301bbdace..f2706125cb 100644 --- a/ext/tk/lib/tkentry.rb +++ b/ext/tk/lib/tkentry.rb @@ -73,6 +73,7 @@ class TkEntry<TkLabel def configure(slot, value=None) if slot.kind_of? Hash + slot = _symbolkey2str(slot) if slot['vcmd'].kind_of? Array cmd, *args = slot['vcmd'] slot['vcmd'] = ValidateCmd.new(cmd, args.join(' ')) @@ -99,8 +100,10 @@ class TkEntry<TkLabel end super(slot) else - if (slot == 'vcmd' || slot == 'validatecommand' || - slot == 'invcmd' || slot == 'invalidcommand') + if (slot == 'vcmd' || slot == :vcmd || + slot == 'validatecommand' || slot == :validatecommand || + slot == 'invcmd' || slot == :invcmd || + slot == 'invalidcommand' !! slot == :invalidcommand) if value.kind_of? Array cmd, *args = value value = ValidateCmd.new(cmd, args.join(' ')) diff --git a/ext/tk/lib/tkfont.rb b/ext/tk/lib/tkfont.rb index c84d0960ed..c56a8df506 100644 --- a/ext/tk/lib/tkfont.rb +++ b/ext/tk/lib/tkfont.rb @@ -173,16 +173,18 @@ class TkFont TkFont.new(nil, nil).call_font_configure(path, *(args + [{}])) else begin - compound = Hash[*tk_split_simplelist(tk_call('font', 'configure', + compound = tk_split_simplelist( + Hash[*tk_split_simplelist(tk_call('font', 'configure', fnt))].collect{|key,value| - [key[1..-1], value] - }.assoc('compound')[1] + [key[1..-1], value] + }.assoc('compound')[1]) rescue compound = [] end if compound == [] - TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \ - .call_font_configure(path, *(args + [{}])) + #TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \ + #.call_font_configure(path, *(args + [{}])) + TkFont.new(fnt).call_font_configure(path, *(args + [{}])) else TkFont.new(compound[0], compound[1]) \ .call_font_configure(path, *(args + [{}])) @@ -220,6 +222,7 @@ class TkFont end def _get_font_info_from_hash(font) + font = _symbolkey2str(font) foundry = (info = font['foundry'] .to_s)? info: '*' family = (info = font['family'] .to_s)? info: '*' weight = (info = font['weight'] .to_s)? info: '*' @@ -353,7 +356,7 @@ class TkFont if JAPANIZED_TK if font.kind_of? Hash - if font['charset'] + if font[:charset] || font['charset'] tk_call('font', 'create', @latinfont, *hash_kv(font)) else tk_call('font', 'create', @latinfont, @@ -398,7 +401,7 @@ class TkFont if JAPANIZED_TK if font.kind_of? Hash - if font['charset'] + if font[:charset] || font['charset'] tk_call('font', 'create', @kanjifont, *hash_kv(font)) else tk_call('font', 'create', @kanjifont, diff --git a/ext/tk/lib/tkmenubar.rb b/ext/tk/lib/tkmenubar.rb index 441f3f5c03..0d29571eb7 100644 --- a/ext/tk/lib/tkmenubar.rb +++ b/ext/tk/lib/tkmenubar.rb @@ -66,8 +66,14 @@ class TkMenubar<TkFrame include TkComposite def initialize(parent = nil, spec = nil, options = nil) - super(parent, options) - + if parent.kind_of? Hash + options = _symbolkey2str(parent) + spec = options.delete('spec') + super(options) + else + super(parent, options) + end + @menus = [] if spec diff --git a/ext/tk/lib/tktext.rb b/ext/tk/lib/tktext.rb index 75b28d8477..9eb70dcd61 100644 --- a/ext/tk/lib/tktext.rb +++ b/ext/tk/lib/tktext.rb @@ -185,7 +185,7 @@ class TkText<TkTextWin end def tag_cget(tag, key) - case key + case key.to_s when 'text', 'label', 'show', 'data', 'file' tk_call @path, 'tag', 'cget', tag, "-#{key}" else @@ -195,16 +195,19 @@ class TkText<TkTextWin def tag_configure(tag, key, val=None) if key.kind_of? Hash + key = _symbolkey2str(key) if ( key['font'] || key['kanjifont'] \ || key['latinfont'] || key['asciifont'] ) - tagfont_configure(tag, key.dup) + tagfont_configure(tag, key) else tk_send 'tag', 'configure', tag, *hash_kv(key) end else - if key == 'font' || key == 'kanjifont' || - key == 'latinfont' || key == 'asciifont' + if key == 'font' || key == :font || + key == 'kanjifont' || key == :kanjifont || + key == 'latinfont' || key == :latinfont || + key == 'asciifont' || key == :asciifont tagfont_configure(tag, {key=>val}) else tk_send 'tag', 'configure', tag, "-#{key}", val @@ -214,7 +217,7 @@ class TkText<TkTextWin def tag_configinfo(tag, key=nil) if key - case key + case key.to_s when 'text', 'label', 'show', 'data', 'file' conf = tk_split_simplelist(tk_send('tag','configure',tag,"-#{key}")) else @@ -549,14 +552,25 @@ end class TkTextTag<TkObject include TkTreatTagFont + TTagID_TBL = {} Tk_TextTag_ID = ['tag0000'] + def TkTextTag.id2obj(text, id) + tpath = text.path + return id unless TTagID_TBL[tpath] + TTagID_TBL[tpath][id]? TTagID_TBL[tpath][id]: id + end + def initialize(parent, *args) if not parent.kind_of?(TkText) fail format("%s need to be TkText", parent.inspect) end @parent = @t = parent + @tpath = parent.path @path = @id = Tk_TextTag_ID[0] + TTagID_TBL[@id] = self + TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] + TTagID_TBL[@tpath][@id] = self Tk_TextTag_ID[0] = Tk_TextTag_ID[0].succ #tk_call @t.path, "tag", "configure", @id, *hash_kv(keys) if args != [] then @@ -618,7 +632,7 @@ class TkTextTag<TkObject end def cget(key) - case key + case key.to_s when 'text', 'label', 'show', 'data', 'file' tk_call @t.path, 'tag', 'cget', @id, "-#{key}" else @@ -671,6 +685,31 @@ class TkTextTag<TkObject def destroy tk_call @t.path, 'tag', 'delete', @id + TTagID_TBL[@tpath][@id] = nil if CTagID_TBL[@tpath] + end +end + +class TkTextNamedTag<TkTextTag + def self.new(parent, name, *args) + if TTagID_TBL[parent.path] && TTagID_TBL[parent.path][name] + return TTagID_TBL[parent.path][name] + else + super(parent, name, *args) + end + end + + def initialize(parent, name, *args) + if not parent.kind_of?(TkText) + fail format("%s need to be TkText", parent.inspect) + end + @t = parent + @tpath = parent.path + @path = @id = name + TTagID_TBL[@tpath] = {} unless TTagID_TBL[@tpath] + TTagID_TBL[@tpath][@id] = self + if mode + tk_call @t.path, "addtag", @id, *args + end end end @@ -792,6 +831,7 @@ class TkTextWindow<TkObject end @path.gravity = 'left' @index = @path.path + keys = _symbolkey2str(keys) @id = keys['window'] if keys['create'] @p_create = keys['create'] @@ -810,7 +850,7 @@ class TkTextWindow<TkObject end def cget(slot) - case slot + case slot.to_s when 'text', 'label', 'show', 'data', 'file' tk_call @t.path, 'window', 'cget', @index, "-#{slot}" else @@ -820,6 +860,7 @@ class TkTextWindow<TkObject def configure(slot, value=None) if slot.kind_of? Hash + slot = _symbolkey2str(slot) @id = slot['window'] if slot['window'] if slot['create'] self.create=value @@ -829,8 +870,8 @@ class TkTextWindow<TkObject tk_call @t.path, 'window', 'configure', @index, *hash_kv(slot) end else - @id = value if slot == 'window' - if slot == 'create' + @id = value if slot == 'window' || slot == :window + if slot == 'create' || slot == :create self.create=value else tk_call @t.path, 'window', 'configure', @index, "-#{slot}", value @@ -861,7 +902,7 @@ class TkTextWindow<TkObject def configinfo(slot = nil) if slot - case slot + case slot.to_s when 'text', 'label', 'show', 'data', 'file' conf = tk_split_simplelist(tk_call @t.path, 'window', 'configure', @index, "-#{slot}") @@ -931,7 +972,7 @@ class TkTextImage<TkObject end def cget(slot) - case slot + case slot.to_s when 'text', 'label', 'show', 'data', 'file' tk_call @t.path, 'image', 'cget', @index, "-#{slot}" else @@ -960,7 +1001,7 @@ class TkTextImage<TkObject def configinfo(slot = nil) if slot - case slot + case slot.to_s when 'text', 'label', 'show', 'data', 'file' conf = tk_split_simplelist(tk_call @t.path, 'image', 'configure', @index, "-#{slot}") |