1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* 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
This commit is contained in:
nagai 2002-06-04 07:03:33 +00:00
parent dc010ff515
commit 4cb164ee2a
10 changed files with 722 additions and 172 deletions

View file

@ -48,20 +48,44 @@ int *tclDummyMathPtr = (int *) matherr;
/*---- module TclTkLib ----*/ /*---- module TclTkLib ----*/
struct invoke_queue { struct invoke_queue {
Tcl_Event ev;
int argc; int argc;
VALUE *argv; VALUE *argv;
VALUE obj; VALUE obj;
int done; int done;
VALUE result; int safe_level;
VALUE *result;
VALUE thread; VALUE thread;
struct invoke_queue *next;
}; };
static struct invoke_queue *iqueue;
static VALUE main_thread; 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 */ /* Tk_ThreadTimer */
static Tcl_TimerToken timer_token; static Tcl_TimerToken timer_token = (Tcl_TimerToken)NULL;
/* timer callback */ /* timer callback */
static void _timer_for_tcl _((ClientData)); static void _timer_for_tcl _((ClientData));
@ -73,44 +97,230 @@ _timer_for_tcl(clientData)
VALUE thread; VALUE thread;
Tk_DeleteTimerHandler(timer_token); Tk_DeleteTimerHandler(timer_token);
timer_token = Tk_CreateTimerHandler(100, _timer_for_tcl, (ClientData)0); if (timer_tick > 0) {
timer_token = Tk_CreateTimerHandler(timer_tick, _timer_for_tcl,
(ClientData)0);
} else {
timer_token = (Tcl_TimerToken)NULL;
}
CHECK_INTS; /* rb_thread_schedule(); */
q = iqueue; timer_tick += event_loop_max;
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);
}
}
rb_thread_schedule();
} }
#if TCL_MAJOR_VERSION >= 8 static VALUE
static int ip_ruby _((ClientData, Tcl_Interp *, int, Tcl_Obj *CONST*)); set_eventloop_tick(self, tick)
#else VALUE self;
static int ip_ruby _((ClientData, Tcl_Interp *, int, char **)); VALUE tick;
#endif {
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();
}
return Qnil;
}
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 */ /* execute Tk_MainLoop */
static VALUE static VALUE
lib_mainloop(self) lib_mainloop(argc, argv, self)
int argc;
VALUE *argv;
VALUE self; VALUE self;
{ {
timer_token = Tk_CreateTimerHandler(100, _timer_for_tcl, (ClientData)0); VALUE check_rootwidget;
DUMP1("start Tk_Mainloop");
Tk_MainLoop(); if (rb_scan_args(argc, argv, "01", &check_rootwidget) == 0) {
DUMP1("stop Tk_Mainloop"); check_rootwidget = Qtrue;
Tk_DeleteTimerHandler(timer_token); } 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; 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 ----*/ /*---- class TclTkIp ----*/
struct tcltkip { struct tcltkip {
Tcl_Interp *ip; /* the interpreter */ Tcl_Interp *ip; /* the interpreter */
@ -245,6 +455,7 @@ ip_new(self)
/* from Tk_Main() */ /* from Tk_Main() */
DUMP1("Tcl_CreateInterp"); DUMP1("Tcl_CreateInterp");
ptr->ip = Tcl_CreateInterp(); ptr->ip = Tcl_CreateInterp();
current_interp = ptr->ip;
/* from Tcl_AppInit() */ /* from Tcl_AppInit() */
DUMP1("Tcl_Init"); DUMP1("Tcl_Init");
@ -459,48 +670,103 @@ ip_invoke_real(argc, argv, obj)
return rb_str_new2(ptr->ip->result); 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 static VALUE
ip_invoke(argc, argv, obj) ip_invoke(argc, argv, obj)
int argc; int argc;
VALUE *argv; VALUE *argv;
VALUE obj; VALUE obj;
{ {
struct invoke_queue *tmp, *p; struct invoke_queue *tmp;
VALUE result = rb_thread_current(); VALUE current = rb_thread_current();
VALUE result;
VALUE *alloc_argv, *alloc_result;
Tcl_QueuePosition position;
if (result == main_thread) { if (eventloop_thread == 0 || current == eventloop_thread) {
DUMP2("invoke from current eventloop %lx", current);
return ip_invoke_real(argc, argv, obj); 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->obj = obj;
tmp->argc = argc; tmp->argc = argc;
tmp->argv = ALLOC_N(VALUE, argc); tmp->argv = alloc_argv;
MEMCPY(tmp->argv, argv, VALUE, argc); tmp->result = alloc_result;
tmp->thread = result; tmp->thread = current;
tmp->done = 0; tmp->safe_level = rb_safe_level();
tmp->ev.proc = invoke_queue_handler;
position = TCL_QUEUE_TAIL;
tmp->next = iqueue; /* add the handler to Tcl event queue */
iqueue = tmp; Tcl_QueueEvent(&tmp->ev, position);
/* wait for the handler to be processed */
rb_thread_stop(); rb_thread_stop();
result = tmp->result;
if (iqueue == tmp) {
iqueue = tmp->next;
free(tmp->argv);
free(tmp);
return result;
}
p = iqueue; /* get result & free allocated memory */
while (p->next) { result = *alloc_result;
if (p->next == tmp) { free(alloc_argv);
p->next = tmp->next; free(alloc_result);
free(tmp->argv);
free(tmp);
break;
}
p = p->next;
}
return result; return result;
} }
@ -533,6 +799,14 @@ Init_tcltklib()
VALUE lib = rb_define_module("TclTkLib"); VALUE lib = rb_define_module("TclTkLib");
VALUE ip = rb_define_class("TclTkIp", rb_cObject); 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 #if defined USE_TCL_STUBS && defined USE_TK_STUBS
extern int ruby_tcltk_stubs(); extern int ruby_tcltk_stubs();
int ret = ruby_tcltk_stubs(); int ret = ruby_tcltk_stubs();
@ -543,7 +817,16 @@ Init_tcltklib()
eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError); eTkCallbackBreak = rb_define_class("TkCallbackBreak", rb_eStandardError);
eTkCallbackContinue = rb_define_class("TkCallbackContinue",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_singleton_method(ip, "new", ip_new, 0);
rb_define_method(ip, "_eval", ip_eval, 1); 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, "_fromUTF8",ip_fromUTF8,2);
rb_define_method(ip, "_invoke", ip_invoke, -1); rb_define_method(ip, "_invoke", ip_invoke, -1);
rb_define_method(ip, "_return_value", ip_retval, 0); 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); rb_define_method(ip, "restart", lib_restart, 0);
main_thread = rb_thread_current(); main_thread = rb_thread_current();
eventloop_thread = 0;
watchdog_thread = 0;
#ifdef __MACOS__ #ifdef __MACOS__
_macinit(); _macinit();
#endif #endif

View file

@ -132,6 +132,13 @@ module TkComm
end end
private :tk_tcl2ruby, :tk_split_list, :tk_split_simplelist 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) def hash_kv(keys)
conf = [] conf = []
if keys and keys != None if keys and keys != None
@ -204,6 +211,8 @@ module TkComm
return nil if str == None return nil if str == None
if str.kind_of?(String) if str.kind_of?(String)
# do nothing # do nothing
elsif str.kind_of?(Symbol)
str = str.id2name
elsif str.kind_of?(Hash) elsif str.kind_of?(Hash)
str = hash_kv(str).join(" ") str = hash_kv(str).join(" ")
elsif str.kind_of?(Array) elsif str.kind_of?(Array)
@ -259,13 +268,15 @@ module TkComm
end end
private :install_cmd, :uninstall_cmd private :install_cmd, :uninstall_cmd
def install_win(ppath) def install_win(ppath,name=nil)
id = format("w%.4d", Tk_IDs[1]) if !name or name == ''
name = format("w%.4d", Tk_IDs[1])
Tk_IDs[1] += 1 Tk_IDs[1] += 1
end
if !ppath or ppath == "." if !ppath or ppath == "."
@path = format(".%s", id); @path = format(".%s", name);
else else
@path = format("%s.%s", ppath, id) @path = format("%s.%s", ppath, name)
end end
Tk_WINDOWS[@path] = self Tk_WINDOWS[@path] = self
end end
@ -483,6 +494,8 @@ module TkCore
} }
EOL EOL
EventFlag = TclTkLib::EventFlag
def callback_break def callback_break
fail TkCallbackBreak, "Tk callback returns 'break' status" fail TkCallbackBreak, "Tk callback returns 'break' status"
end end
@ -616,12 +629,42 @@ module TkCore
tk_call('info', *args) tk_call('info', *args)
end end
def mainloop def mainloop(check_root = true)
TclTkLib.mainloop TclTkLib.mainloop(check_root)
end 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 TkCore::INTERP.restart
TkComm::Tk_CMDTBL.clear
TkComm::Tk_WINDOWS.clear TkComm::Tk_WINDOWS.clear
nil nil
end end
@ -2077,12 +2120,87 @@ module TkOption
tk_call 'option', 'clear' tk_call 'option', 'clear'
end end
def get win, name, klass def get win, name, klass
tk_call 'option', 'get', win ,name, klass tk_call('option', 'get', win ,name, klass).taint
end end
def readfile file, pri=None def readfile file, pri=None
tk_call 'option', 'readfile', file, pri tk_call 'option', 'readfile', file, pri
end end
module_function :add, :clear, :get, :readfile 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 end
module TkTreatFont module TkTreatFont
@ -2096,6 +2214,7 @@ module TkTreatFont
alias fontobj font_configinfo alias fontobj font_configinfo
def font_configure(slot) def font_configure(slot)
slot = _symbolkey2str(slot)
if (fnt = slot.delete('font')) if (fnt = slot.delete('font'))
if fnt.kind_of? TkFont if fnt.kind_of? TkFont
return fnt.call_font_configure(self.path, self.path,'configure',slot) return fnt.call_font_configure(self.path, self.path,'configure',slot)
@ -2203,6 +2322,7 @@ module TkTreatItemFont
def tagfont_configure(tagOrId, slot) def tagfont_configure(tagOrId, slot)
pathname = __item_pathname(tagOrId) pathname = __item_pathname(tagOrId)
slot = _symbolkey2str(slot)
if (fnt = slot.delete('font')) if (fnt = slot.delete('font'))
if fnt.kind_of? TkFont if fnt.kind_of? TkFont
return fnt.call_font_configure(pathname, self.path, return fnt.call_font_configure(pathname, self.path,
@ -2345,7 +2465,7 @@ class TkObject<TkKernel
end end
def cget(slot) def cget(slot)
case slot case slot.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
tk_call path, 'cget', "-#{slot}" tk_call path, 'cget', "-#{slot}"
else else
@ -2355,16 +2475,20 @@ class TkObject<TkKernel
def configure(slot, value=None) def configure(slot, value=None)
if slot.kind_of? Hash if slot.kind_of? Hash
if (slot['font'] || slot['kanjifont'] || if (slot['font'] || slot[:font] ||
slot['latinfont'] || slot['asciifont'] ) slot['kanjifont'] || slot[:kanjifont] ||
font_configure(slot.dup) slot['latinfont'] || slot[:latinfont] ||
slot['asciifont'] || slot[:asciifont] )
font_configure(slot)
else else
tk_call path, 'configure', *hash_kv(slot) tk_call path, 'configure', *hash_kv(slot)
end end
else else
if (slot == 'font' || slot == 'kanjifont' || if (slot == 'font' || slot == :font ||
slot == 'latinfont' || slot == 'asciifont') slot == 'kanjifont' || slot == :kanjifont ||
slot == 'latinfont' || slot == :latinfont ||
slot == 'asciifont' || slot == :asciifont )
if value == None if value == None
fontobj fontobj
else else
@ -2381,11 +2505,12 @@ class TkObject<TkKernel
end end
def configinfo(slot = nil) def configinfo(slot = nil)
if slot == 'font' || slot == 'kanjifont' if slot == 'font' || slot == :font ||
slot == 'kanjifont' || slot == :kanjifont
fontobj fontobj
else else
if slot if slot
case slot case slot.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
conf = tk_split_simplelist(tk_send('configure', "-#{slot}") ) conf = tk_split_simplelist(tk_send('configure', "-#{slot}") )
else else
@ -2455,7 +2580,19 @@ class TkWindow<TkObject
extend TkBindCore extend TkBindCore
def initialize(parent=nil, keys=nil) def initialize(parent=nil, keys=nil)
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) install_win(if parent then parent.path end)
end
if self.method(:create_self).arity == 0 if self.method(:create_self).arity == 0
p 'create_self has no arg' if $DEBUG p 'create_self has no arg' if $DEBUG
create_self create_self
@ -2464,10 +2601,9 @@ class TkWindow<TkObject
configure(keys) configure(keys)
end end
else else
p 'create_self has an arg' if $DEBUG p 'create_self has args' if $DEBUG
fontkeys = {} fontkeys = {}
if keys if keys
keys = keys.dup
['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key| ['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key|
fontkeys[key] = keys.delete(key) if keys.key?(key) fontkeys[key] = keys.delete(key) if keys.key?(key)
} }
@ -2668,17 +2804,17 @@ class TkWindow<TkObject
tk_call 'grab', 'set', path tk_call 'grab', 'set', path
elsif args.length == 1 elsif args.length == 1
case args[0] case args[0]
when 'global' when 'global', :global
return(tk_call 'grab', 'set', '-global', path) return(tk_call 'grab', 'set', '-global', path)
when 'release' when 'release', :release
return(tk_call 'grab', 'release', path) return(tk_call 'grab', 'release', path)
else else
val = tk_call('grab', args[0], path) val = tk_call('grab', args[0], path)
end end
case args[0] case args[0]
when 'current' when 'current', :current
return window(val) return window(val)
when 'status' when 'status', :status
return val return val
end end
else else
@ -2811,15 +2947,27 @@ class TkToplevel<TkWindow
################# #################
def initialize(parent=nil, screen=nil, classname=nil, keys=nil) 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 if screen.kind_of? Hash
keys = screen keys = _symbolkey2str(screen)
else else
@screen = screen @screen = screen
end end
@classname = classname @classname = classname
if keys.kind_of? Hash if keys.kind_of? Hash
if keys.key?('classname') keys = _symbolkey2str(keys)
keys = keys.dup if keys.key?(:classname) || keys.key?('classname')
keys['class'] = keys.delete('classname') keys['class'] = keys.delete('classname')
end end
@classname = keys['class'] @classname = keys['class']
@ -2875,17 +3023,24 @@ class TkFrame<TkWindow
################# #################
def initialize(parent=nil, keys=nil) def initialize(parent=nil, keys=nil)
if keys.kind_of? Hash if parent.kind_of? Hash
keys = _symbolkey2str(parent)
else
if keys
keys = _symbolkey2str(keys)
keys['parent'] = parent
else
keys = {'parent'=>parent}
end
end
if keys.key?('classname') if keys.key?('classname')
keys = keys.dup
keys['class'] = keys.delete('classname') keys['class'] = keys.delete('classname')
end end
@classname = keys['class'] @classname = keys['class']
@colormap = keys['colormap'] @colormap = keys['colormap']
@container = keys['container'] @container = keys['container']
@visual = keys['visual'] @visual = keys['visual']
end super(keys)
super(parent, keys)
end end
def create_self(keys) def create_self(keys)
@ -3170,7 +3325,7 @@ class TkListbox<TkTextWin
end end
def itemcget(index, key) def itemcget(index, key)
case key case key.to_s
when 'text', 'label', 'show' when 'text', 'label', 'show'
tk_send 'itemcget', index, "-#{key}" tk_send 'itemcget', index, "-#{key}"
else else
@ -3179,16 +3334,20 @@ class TkListbox<TkTextWin
end end
def itemconfigure(index, key, val=None) def itemconfigure(index, key, val=None)
if key.kind_of? Hash if key.kind_of? Hash
if (key['font'] || key['kanjifont'] || if (key['font'] || key[:font] ||
key['latinfont'] || key['asciifont']) key['kanjifont'] || key[:kanjifont] ||
tagfont_configure(index, key.dup) key['latinfont'] || key[:latinfont] ||
key['asciifont'] || key[:asciifont] )
tagfont_configure(index, _symbolkey2str(key))
else else
tk_send 'itemconfigure', index, *hash_kv(key) tk_send 'itemconfigure', index, *hash_kv(key)
end end
else else
if (key == 'font' || key == 'kanjifont' || if (key == 'font' || key == :font ||
key == 'latinfont' || key == 'asciifont' ) key == 'kanjifont' || key == :kanjifont ||
key == 'latinfont' || key == :latinfont ||
key == 'asciifont' || key == :asciifont )
tagfont_configure(index, {key=>val}) tagfont_configure(index, {key=>val})
else else
tk_call 'itemconfigure', index, "-#{key}", val tk_call 'itemconfigure', index, "-#{key}", val
@ -3198,7 +3357,7 @@ class TkListbox<TkTextWin
def itemconfiginfo(index, key=nil) def itemconfiginfo(index, key=nil)
if key if key
case key case key.to_s
when 'text', 'label', 'show' when 'text', 'label', 'show'
conf = tk_split_simplelist(tk_send('itemconfigure',index,"-#{key}")) conf = tk_split_simplelist(tk_send('itemconfigure',index,"-#{key}"))
else else
@ -3305,7 +3464,7 @@ class TkMenu<TkWindow
number(tk_send('yposition', index)) number(tk_send('yposition', index))
end end
def entrycget(index, key) def entrycget(index, key)
case key case key.to_s
when 'text', 'label', 'show' when 'text', 'label', 'show'
tk_send 'entrycget', index, "-#{key}" tk_send 'entrycget', index, "-#{key}"
else else
@ -3314,16 +3473,20 @@ class TkMenu<TkWindow
end end
def entryconfigure(index, key, val=None) def entryconfigure(index, key, val=None)
if key.kind_of? Hash if key.kind_of? Hash
if (key['font'] || key['kanjifont'] || if (key['font'] || key[:font] ||
key['latinfont'] || key['asciifont']) key['kanjifont'] || key[:kanjifont] ||
tagfont_configure(index, key.dup) key['latinfont'] || key[:latinfont] ||
key['asciifont'] || key[:asciifont])
tagfont_configure(index, _symbolkey2str(key))
else else
tk_send 'entryconfigure', index, *hash_kv(key) tk_send 'entryconfigure', index, *hash_kv(key)
end end
else else
if (key == 'font' || key == 'kanjifont' || if (key == 'font' || key == :font ||
key == 'latinfont' || key == 'asciifont' ) key == 'kanjifont' || key == :kanjifont ||
key == 'latinfont' || key == :latinfont ||
key == 'asciifont' || key == :asciifont )
tagfont_configure({key=>val}) tagfont_configure({key=>val})
else else
tk_call 'entryconfigure', index, "-#{key}", val tk_call 'entryconfigure', index, "-#{key}", val
@ -3333,7 +3496,7 @@ class TkMenu<TkWindow
def entryconfiginfo(index, key=nil) def entryconfiginfo(index, key=nil)
if key if key
case key case key.to_s
when 'text', 'label', 'show' when 'text', 'label', 'show'
conf = tk_split_simplelist(tk_send('entryconfigure',index,"-#{key}")) conf = tk_split_simplelist(tk_send('entryconfigure',index,"-#{key}"))
else else
@ -3371,17 +3534,28 @@ end
class TkMenuClone<TkMenu class TkMenuClone<TkMenu
def initialize(parent, type=None) 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) unless parent.kind_of?(TkMenu)
fail ArgumentError, "parent must be TkMenu" fail ArgumentError, "parent must be TkMenu"
end end
@parent = parent @parent = parent
install_win(@parent.path) install_win(@parent.path, widgetname)
tk_call @parent.path, 'clone', @path, type tk_call @parent.path, 'clone', @path, type
end end
end end
module TkSystemMenu module TkSystemMenu
def initialize(parent, keys=nil) def initialize(parent, keys=nil)
if parent.kind_of? Hash
keys = _symbolkey2str(parent)
parent = keys.delete('parent')
end
fail unless parent.kind_of? TkMenu fail unless parent.kind_of? TkMenu
@path = format("%s.%s", parent.path, self.type::SYSMENU_NAME) @path = format("%s.%s", parent.path, self.type::SYSMENU_NAME)
TkComm::Tk_WINDOWS[@path] = self TkComm::Tk_WINDOWS[@path] = self
@ -3437,6 +3611,12 @@ class TkOptionMenubutton<TkMenubutton
end end
def initialize(parent=nil, var=TkVariable.new, firstval=nil, *vals) 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 fail unless var.kind_of? TkVariable
@variable = var @variable = var
firstval = @variable.value unless firstval firstval = @variable.value unless firstval
@ -3498,10 +3678,18 @@ module TkComposite
extend Tk extend Tk
def initialize(parent=nil, *args) def initialize(parent=nil, *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) @frame = TkFrame.new(parent)
@path = @epath = @frame.path @path = @epath = @frame.path
initialize_composite(*args) initialize_composite(*args)
end end
end
def epath def epath
@epath @epath

View file

@ -1,6 +1,7 @@
# #
# tkafter.rb : methods for Tcl/Tk after command # tkafter.rb : methods for Tcl/Tk after command
# 2000/08/01 by Hidetoshi Nagai <nagai@ai.kyutech.ac.jp> #
# $Id$
# #
require 'tk' require 'tk'
@ -11,18 +12,16 @@ class TkAfter
Tk_CBID = [0] Tk_CBID = [0]
Tk_CBTBL = {} 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 # class methods
############################### ###############################
def TkAfter.callback(arg) def TkAfter.callback(obj_id)
@after_id = nil @after_id = nil
arg = Array(tk_split_list(arg))
obj_id = arg.shift
ex_obj = Tk_CBTBL[obj_id] ex_obj = Tk_CBTBL[obj_id]
return nil if ex_obj == nil; # canceled return nil if ex_obj == nil; # canceled
_get_eval_string(ex_obj.do_callback(*arg)) _get_eval_string(ex_obj.do_callback)
end end
def TkAfter.info def TkAfter.info
@ -35,10 +34,10 @@ class TkAfter
############################### ###############################
# instance methods # instance methods
############################### ###############################
def do_callback(*args) def do_callback
@in_callback = true @in_callback = true
begin begin
ret = @current_proc.call(*args) @return_value = @current_proc.call(self)
rescue StandardError, NameError rescue StandardError, NameError
if @cancel_on_exception if @cancel_on_exception
cancel cancel
@ -48,21 +47,22 @@ class TkAfter
end end
end end
if @set_next if @set_next
set_next_callback(*args) set_next_callback(@current_args)
else else
@set_next = true @set_next = true
end end
@in_callback = false @in_callback = false
ret @return_value
end end
def set_callback(sleep, args=nil) 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) @after_id = tk_call('after', sleep, @after_script)
@current_args = args
@current_script = [sleep, @after_script] @current_script = [sleep, @after_script]
end end
def set_next_callback(*args) def set_next_callback(args)
if @running == false || @proc_max == 0 || @do_loop == 0 if @running == false || @proc_max == 0 || @do_loop == 0
Tk_CBTBL[@id] = nil ;# for GC Tk_CBTBL[@id] = nil ;# for GC
@running = false @running = false
@ -81,7 +81,7 @@ class TkAfter
@current_args = args @current_args = args
if @sleep_time.kind_of? Proc if @sleep_time.kind_of? Proc
sleep = @sleep_time.call(*args) sleep = @sleep_time.call(self)
else else
sleep = @sleep_time sleep = @sleep_time
end end
@ -91,15 +91,7 @@ class TkAfter
@current_pos += 1 @current_pos += 1
@current_proc = cmd @current_proc = cmd
if cmd_args[0].kind_of? Proc set_callback(sleep, cmd_args)
#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 end
def initialize(*args) def initialize(*args)
@ -115,6 +107,7 @@ class TkAfter
@current_script = [] @current_script = []
@current_proc = nil @current_proc = nil
@current_args = nil @current_args = nil
@return_value = nil
@sleep_time = 0 @sleep_time = 0
@current_sleep = 0 @current_sleep = 0
@ -137,7 +130,10 @@ class TkAfter
attr :after_id attr :after_id
attr :after_script attr :after_script
attr :current_proc attr :current_proc
attr :current_args
attr :current_sleep attr :current_sleep
alias :current_interval :current_sleep
attr :return_value
attr_accessor :loop_exec attr_accessor :loop_exec
@ -257,7 +253,7 @@ class TkAfter
set_callback(sleep, @init_args) set_callback(sleep, @init_args)
@set_next = false if @in_callback @set_next = false if @in_callback
else else
set_next_callback(*@init_args) set_next_callback(@init_args)
end end
self self

View file

@ -1,4 +1,4 @@
#
# tkcanvas.rb - Tk canvas classes # tkcanvas.rb - Tk canvas classes
# $Date$ # $Date$
# by Yukihiro Matsumoto <matz@caelum.co.jp> # by Yukihiro Matsumoto <matz@caelum.co.jp>
@ -180,7 +180,7 @@ class TkCanvas<TkWindow
end end
def itemcget(tagOrId, option) def itemcget(tagOrId, option)
case option case option.to_s
when 'dash', 'activedash', 'disableddash' when 'dash', 'activedash', 'disableddash'
conf = tk_send('itemcget', tagid(tagOrId), "-#{option}") conf = tk_send('itemcget', tagid(tagOrId), "-#{option}")
if conf =~ /^[0-9]/ if conf =~ /^[0-9]/
@ -197,6 +197,7 @@ class TkCanvas<TkWindow
def itemconfigure(tagOrId, key, value=None) def itemconfigure(tagOrId, key, value=None)
if key.kind_of? Hash if key.kind_of? Hash
key = _symbolkey2str(key)
if ( key['font'] || key['kanjifont'] \ if ( key['font'] || key['kanjifont'] \
|| key['latinfont'] || key['asciifont'] ) || key['latinfont'] || key['asciifont'] )
tagfont_configure(tagOrId, key.dup) tagfont_configure(tagOrId, key.dup)
@ -205,8 +206,10 @@ class TkCanvas<TkWindow
end end
else else
if ( key == 'font' || key == 'kanjifont' \ if ( key == 'font' || key == :font ||
|| key == 'latinfont' || key == 'asciifont' ) key == 'kanjifont' || key == :kanjifont ||
key == 'latinfont' || key == :latinfont ||
key == 'asciifont' || key == :asciifont )
tagfont_configure(tagid(tagOrId), {key=>value}) tagfont_configure(tagid(tagOrId), {key=>value})
else else
tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value tk_send 'itemconfigure', tagid(tagOrId), "-#{key}", value
@ -226,7 +229,7 @@ class TkCanvas<TkWindow
def itemconfiginfo(tagOrId, key=nil) def itemconfiginfo(tagOrId, key=nil)
if key if key
case key case key.to_s
when 'dash', 'activedash', 'disableddash' when 'dash', 'activedash', 'disableddash'
conf = tk_split_simplelist(tk_send 'itemconfigure', conf = tk_split_simplelist(tk_send 'itemconfigure',
tagid(tagOrId), "-#{key}") tagid(tagOrId), "-#{key}")
@ -433,7 +436,7 @@ module TkcTagAccess
@c.itemtype @id @c.itemtype @id
end end
# Followings operators supports logical expressions of canvas tags # Following operators support logical expressions of canvas tags
# (for Tk8.3+). # (for Tk8.3+).
# If tag1.path is 't1' and tag2.path is 't2', then # If tag1.path is 't1' and tag2.path is 't2', then
# ltag = tag1 & tag2; ltag.path => "(t1)&&(t2)" # ltag = tag1 & tag2; ltag.path => "(t1)&&(t2)"
@ -473,6 +476,7 @@ class TkcTag<TkObject
include TkcTagAccess include TkcTagAccess
CTagID_TBL = {} CTagID_TBL = {}
Tk_CanvasTag_ID = ['ctag0000']
def TkcTag.id2obj(canvas, id) def TkcTag.id2obj(canvas, id)
cpath = canvas.path cpath = canvas.path
@ -480,7 +484,6 @@ class TkcTag<TkObject
CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id CTagID_TBL[cpath][id]? CTagID_TBL[cpath][id]: id
end end
Tk_CanvasTag_ID = ['ctag0000']
def initialize(parent, mode=nil, *args) def initialize(parent, mode=nil, *args)
if not parent.kind_of?(TkCanvas) if not parent.kind_of?(TkCanvas)
fail format("%s need to be TkCanvas", parent.inspect) fail format("%s need to be TkCanvas", parent.inspect)
@ -501,7 +504,7 @@ class TkcTag<TkObject
def delete def delete
@c.delete @id @c.delete @id
CTagID_TBL[@path][@id] = nil if CTagID_TBL[@path] CTagID_TBL[@cpath][@id] = nil if CTagID_TBL[@cpath]
end end
alias remove delete alias remove delete
alias destroy delete alias destroy delete
@ -565,6 +568,7 @@ class TkcTagString<TkcTag
end end
end end
end end
TkcNamedTag = TkcTagString
class TkcTagAll<TkcTag class TkcTagAll<TkcTag
def initialize(parent) def initialize(parent)
@ -643,9 +647,16 @@ class TkcItem<TkObject
@parent = @c = parent @parent = @c = parent
@path = parent.path @path = parent.path
fontkeys = {} 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 if args[-1].kind_of? Hash
args = args.dup keys = _symbolkey2str(args.pop)
keys = args.pop
['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key| ['font', 'kanjifont', 'latinfont', 'asciifont'].each{|key|
fontkeys[key] = keys.delete(key) if keys.key?(key) fontkeys[key] = keys.delete(key) if keys.key?(key)
} }
@ -797,7 +808,7 @@ class TkPhotoImage<TkImage
end end
def cget(option) def cget(option)
case option case option.to_s
when 'data', 'file' when 'data', 'file'
tk_send 'cget', option tk_send 'cget', option
else else

View file

@ -1,7 +1,9 @@
# #
# tkclass.rb - Tk classes # tkclass.rb - Tk classes
# $Date$ # Date: 2000/11/27 09:23:36
# by Yukihiro Matsumoto <matz@caelum.co.jp> # by Yukihiro Matsumoto <matz@caelum.co.jp>
#
# $Id$
require "tk" require "tk"
@ -13,6 +15,7 @@ Radiobutton = TkRadioButton
Checkbutton = TkCheckButton Checkbutton = TkCheckButton
Message = TkMessage Message = TkMessage
Entry = TkEntry Entry = TkEntry
Spinbox = TkSpinbox
Text = TkText Text = TkText
Scale = TkScale Scale = TkScale
Scrollbar = TkScrollbar Scrollbar = TkScrollbar
@ -28,10 +31,16 @@ Polygon = TkcPolygon
Rectangle = TkcRectangle Rectangle = TkcRectangle
TextItem = TkcText TextItem = TkcText
WindowItem = TkcWindow WindowItem = TkcWindow
BitmapImage = TkBitmapImage
PhotoImage = TkPhotoImage
Selection = TkSelection Selection = TkSelection
Winfo = TkWinfo Winfo = TkWinfo
Pack = TkPack Pack = TkPack
Grid = TkGrid
Place = TkPlace
Variable = TkVariable Variable = TkVariable
Font = TkFont
VirtualEvent = TkVirtualEvent
def Mainloop def Mainloop
Tk.mainloop Tk.mainloop

View file

@ -23,6 +23,7 @@ class TkDialog < TkWindow
@button_configs = proc{|num| button_configs num} @button_configs = proc{|num| button_configs num}
if keys.kind_of? Hash if keys.kind_of? Hash
keys = _symbolkey2str(keys)
@title = keys['title'] if keys['title'] @title = keys['title'] if keys['title']
@message = keys['message'] if keys['message'] @message = keys['message'] if keys['message']
@bitmap = keys['bitmap'] if keys['bitmap'] @bitmap = keys['bitmap'] if keys['bitmap']

View file

@ -73,6 +73,7 @@ class TkEntry<TkLabel
def configure(slot, value=None) def configure(slot, value=None)
if slot.kind_of? Hash if slot.kind_of? Hash
slot = _symbolkey2str(slot)
if slot['vcmd'].kind_of? Array if slot['vcmd'].kind_of? Array
cmd, *args = slot['vcmd'] cmd, *args = slot['vcmd']
slot['vcmd'] = ValidateCmd.new(cmd, args.join(' ')) slot['vcmd'] = ValidateCmd.new(cmd, args.join(' '))
@ -99,8 +100,10 @@ class TkEntry<TkLabel
end end
super(slot) super(slot)
else else
if (slot == 'vcmd' || slot == 'validatecommand' || if (slot == 'vcmd' || slot == :vcmd ||
slot == 'invcmd' || slot == 'invalidcommand') slot == 'validatecommand' || slot == :validatecommand ||
slot == 'invcmd' || slot == :invcmd ||
slot == 'invalidcommand' !! slot == :invalidcommand)
if value.kind_of? Array if value.kind_of? Array
cmd, *args = value cmd, *args = value
value = ValidateCmd.new(cmd, args.join(' ')) value = ValidateCmd.new(cmd, args.join(' '))

View file

@ -173,16 +173,18 @@ class TkFont
TkFont.new(nil, nil).call_font_configure(path, *(args + [{}])) TkFont.new(nil, nil).call_font_configure(path, *(args + [{}]))
else else
begin 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| fnt))].collect{|key,value|
[key[1..-1], value] [key[1..-1], value]
}.assoc('compound')[1] }.assoc('compound')[1])
rescue rescue
compound = [] compound = []
end end
if compound == [] if compound == []
TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \ #TkFont.new(fnt, DEFAULT_KANJI_FONT_NAME) \
.call_font_configure(path, *(args + [{}])) #.call_font_configure(path, *(args + [{}]))
TkFont.new(fnt).call_font_configure(path, *(args + [{}]))
else else
TkFont.new(compound[0], compound[1]) \ TkFont.new(compound[0], compound[1]) \
.call_font_configure(path, *(args + [{}])) .call_font_configure(path, *(args + [{}]))
@ -220,6 +222,7 @@ class TkFont
end end
def _get_font_info_from_hash(font) def _get_font_info_from_hash(font)
font = _symbolkey2str(font)
foundry = (info = font['foundry'] .to_s)? info: '*' foundry = (info = font['foundry'] .to_s)? info: '*'
family = (info = font['family'] .to_s)? info: '*' family = (info = font['family'] .to_s)? info: '*'
weight = (info = font['weight'] .to_s)? info: '*' weight = (info = font['weight'] .to_s)? info: '*'
@ -353,7 +356,7 @@ class TkFont
if JAPANIZED_TK if JAPANIZED_TK
if font.kind_of? Hash if font.kind_of? Hash
if font['charset'] if font[:charset] || font['charset']
tk_call('font', 'create', @latinfont, *hash_kv(font)) tk_call('font', 'create', @latinfont, *hash_kv(font))
else else
tk_call('font', 'create', @latinfont, tk_call('font', 'create', @latinfont,
@ -398,7 +401,7 @@ class TkFont
if JAPANIZED_TK if JAPANIZED_TK
if font.kind_of? Hash if font.kind_of? Hash
if font['charset'] if font[:charset] || font['charset']
tk_call('font', 'create', @kanjifont, *hash_kv(font)) tk_call('font', 'create', @kanjifont, *hash_kv(font))
else else
tk_call('font', 'create', @kanjifont, tk_call('font', 'create', @kanjifont,

View file

@ -66,7 +66,13 @@ class TkMenubar<TkFrame
include TkComposite include TkComposite
def initialize(parent = nil, spec = nil, options = nil) def initialize(parent = nil, spec = nil, options = nil)
if parent.kind_of? Hash
options = _symbolkey2str(parent)
spec = options.delete('spec')
super(options)
else
super(parent, options) super(parent, options)
end
@menus = [] @menus = []

View file

@ -185,7 +185,7 @@ class TkText<TkTextWin
end end
def tag_cget(tag, key) def tag_cget(tag, key)
case key case key.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
tk_call @path, 'tag', 'cget', tag, "-#{key}" tk_call @path, 'tag', 'cget', tag, "-#{key}"
else else
@ -195,16 +195,19 @@ class TkText<TkTextWin
def tag_configure(tag, key, val=None) def tag_configure(tag, key, val=None)
if key.kind_of? Hash if key.kind_of? Hash
key = _symbolkey2str(key)
if ( key['font'] || key['kanjifont'] \ if ( key['font'] || key['kanjifont'] \
|| key['latinfont'] || key['asciifont'] ) || key['latinfont'] || key['asciifont'] )
tagfont_configure(tag, key.dup) tagfont_configure(tag, key)
else else
tk_send 'tag', 'configure', tag, *hash_kv(key) tk_send 'tag', 'configure', tag, *hash_kv(key)
end end
else else
if key == 'font' || key == 'kanjifont' || if key == 'font' || key == :font ||
key == 'latinfont' || key == 'asciifont' key == 'kanjifont' || key == :kanjifont ||
key == 'latinfont' || key == :latinfont ||
key == 'asciifont' || key == :asciifont
tagfont_configure(tag, {key=>val}) tagfont_configure(tag, {key=>val})
else else
tk_send 'tag', 'configure', tag, "-#{key}", val tk_send 'tag', 'configure', tag, "-#{key}", val
@ -214,7 +217,7 @@ class TkText<TkTextWin
def tag_configinfo(tag, key=nil) def tag_configinfo(tag, key=nil)
if key if key
case key case key.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
conf = tk_split_simplelist(tk_send('tag','configure',tag,"-#{key}")) conf = tk_split_simplelist(tk_send('tag','configure',tag,"-#{key}"))
else else
@ -549,14 +552,25 @@ end
class TkTextTag<TkObject class TkTextTag<TkObject
include TkTreatTagFont include TkTreatTagFont
TTagID_TBL = {}
Tk_TextTag_ID = ['tag0000'] 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) def initialize(parent, *args)
if not parent.kind_of?(TkText) if not parent.kind_of?(TkText)
fail format("%s need to be TkText", parent.inspect) fail format("%s need to be TkText", parent.inspect)
end end
@parent = @t = parent @parent = @t = parent
@tpath = parent.path
@path = @id = Tk_TextTag_ID[0] @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_TextTag_ID[0] = Tk_TextTag_ID[0].succ
#tk_call @t.path, "tag", "configure", @id, *hash_kv(keys) #tk_call @t.path, "tag", "configure", @id, *hash_kv(keys)
if args != [] then if args != [] then
@ -618,7 +632,7 @@ class TkTextTag<TkObject
end end
def cget(key) def cget(key)
case key case key.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
tk_call @t.path, 'tag', 'cget', @id, "-#{key}" tk_call @t.path, 'tag', 'cget', @id, "-#{key}"
else else
@ -671,6 +685,31 @@ class TkTextTag<TkObject
def destroy def destroy
tk_call @t.path, 'tag', 'delete', @id 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
end end
@ -792,6 +831,7 @@ class TkTextWindow<TkObject
end end
@path.gravity = 'left' @path.gravity = 'left'
@index = @path.path @index = @path.path
keys = _symbolkey2str(keys)
@id = keys['window'] @id = keys['window']
if keys['create'] if keys['create']
@p_create = keys['create'] @p_create = keys['create']
@ -810,7 +850,7 @@ class TkTextWindow<TkObject
end end
def cget(slot) def cget(slot)
case slot case slot.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
tk_call @t.path, 'window', 'cget', @index, "-#{slot}" tk_call @t.path, 'window', 'cget', @index, "-#{slot}"
else else
@ -820,6 +860,7 @@ class TkTextWindow<TkObject
def configure(slot, value=None) def configure(slot, value=None)
if slot.kind_of? Hash if slot.kind_of? Hash
slot = _symbolkey2str(slot)
@id = slot['window'] if slot['window'] @id = slot['window'] if slot['window']
if slot['create'] if slot['create']
self.create=value self.create=value
@ -829,8 +870,8 @@ class TkTextWindow<TkObject
tk_call @t.path, 'window', 'configure', @index, *hash_kv(slot) tk_call @t.path, 'window', 'configure', @index, *hash_kv(slot)
end end
else else
@id = value if slot == 'window' @id = value if slot == 'window' || slot == :window
if slot == 'create' if slot == 'create' || slot == :create
self.create=value self.create=value
else else
tk_call @t.path, 'window', 'configure', @index, "-#{slot}", value tk_call @t.path, 'window', 'configure', @index, "-#{slot}", value
@ -861,7 +902,7 @@ class TkTextWindow<TkObject
def configinfo(slot = nil) def configinfo(slot = nil)
if slot if slot
case slot case slot.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
conf = tk_split_simplelist(tk_call @t.path, 'window', 'configure', conf = tk_split_simplelist(tk_call @t.path, 'window', 'configure',
@index, "-#{slot}") @index, "-#{slot}")
@ -931,7 +972,7 @@ class TkTextImage<TkObject
end end
def cget(slot) def cget(slot)
case slot case slot.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
tk_call @t.path, 'image', 'cget', @index, "-#{slot}" tk_call @t.path, 'image', 'cget', @index, "-#{slot}"
else else
@ -960,7 +1001,7 @@ class TkTextImage<TkObject
def configinfo(slot = nil) def configinfo(slot = nil)
if slot if slot
case slot case slot.to_s
when 'text', 'label', 'show', 'data', 'file' when 'text', 'label', 'show', 'data', 'file'
conf = tk_split_simplelist(tk_call @t.path, 'image', 'configure', conf = tk_split_simplelist(tk_call @t.path, 'image', 'configure',
@index, "-#{slot}") @index, "-#{slot}")