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

* ext/tcltklib/extconf.rb: [EXPERIMENTAL] MacOS X (darwin) support

* ext/tcltklib/tcltklib.c: fix thread trouble on callback proc, and
			   eliminate warning about instance variable access
* ext/tk/lib/tk/menubar.rb: improve supported menu_spec
* ext/tk/lib/tk/menuspec.rb: [add] menu_spec support library
* ext/tk/lib/tk/root.rb: add menu_spec support
* ext/tk/lib/tk/text.rb: bug fix
* ext/tk/lib/tk/toplevel.rb: add menu_spec support
* ext/tk/sample/menubar?.rb: [add] sample of menu_spec usage


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@6454 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nagai 2004-06-12 15:25:49 +00:00
parent 82593c058f
commit c0271cadd7
18 changed files with 726 additions and 179 deletions

View file

@ -1,3 +1,22 @@
Sun Jun 13 00:23:04 2004 Hidetoshi NAGAI <nagai@ai.kyutech.ac.jp>
* ext/tcltklib/extconf.rb: [EXPERIMENTAL] MacOS X (darwin) support
* ext/tcltklib/tcltklib.c: fix thread trouble on callback proc, and
eliminate warning about instance variable access
* ext/tk/lib/tk/menubar.rb: improve supported menu_spec
* ext/tk/lib/tk/menuspec.rb: [add] menu_spec support library
* ext/tk/lib/tk/root.rb: add menu_spec support
* ext/tk/lib/tk/text.rb: bug fix
* ext/tk/lib/tk/toplevel.rb: add menu_spec support
* ext/tk/sample/menubar?.rb: [add] sample of menu_spec usage
Sat Jun 12 14:15:20 Hirokazu Yamamoto <ocean@m2.ccsnet.ne.jp>
* dir.c: RDOC for File::FNM_CASEFOLD was missed.

View file

@ -3,6 +3,7 @@
require 'mkmf'
is_win32 = (/mswin32|mingw|cygwin|bccwin32/ =~ RUBY_PLATFORM)
is_macosx = (/darwin/ =~ RUBY_PLATFORM)
unless is_win32
have_library("nsl", "t_open")
@ -209,13 +210,19 @@ EOF
end
end
if have_header("tcl.h") && have_header("tk.h") &&
if is_macosx ||
(have_header("tcl.h") && have_header("tk.h") &&
(is_win32 || find_library("X11", "XOpenDisplay",
"/usr/X11/lib", "/usr/lib/X11", "/usr/X11R6/lib", "/usr/openwin/lib")) &&
find_tcl(tcllib, stubs) &&
find_tk(tklib, stubs)
find_tk(tklib, stubs))
$CPPFLAGS += ' -DUSE_TCL_STUBS -DUSE_TK_STUBS' if stubs
$CPPFLAGS += ' -D_WIN32' if /cygwin/ =~ RUBY_PLATFORM
if is_macosx
$CPPFLAGS += ' -I/Library/Frameworks/Tcl.framework/headers -I/Library/Frameworks/Tk.framework/Headers'
$LDFLAGS += ' -framework Tk -framework Tcl'
end
create_makefile("tcltklib") if pthread_check
end

View file

@ -909,17 +909,20 @@ ip_set_exc_message(interp, exc)
msg = rb_funcall(exc, ID_message, 0, 0);
#if TCL_MAJOR_VERSION > 8 || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION > 0)
enc = rb_ivar_get(exc, ID_at_enc);
if (NIL_P(enc)) {
enc = rb_ivar_get(msg, ID_at_enc);
enc = Qnil;
if (RTEST(rb_ivar_defined(exc, ID_at_enc))) {
enc = rb_ivar_get(exc, ID_at_enc);
}
if (NIL_P(enc) && RTEST(rb_ivar_defined(msg, ID_at_enc))) {
enc = rb_ivar_get(msg, ID_at_enc);
}
if (NIL_P(enc)) {
encoding = (Tcl_Encoding)NULL;
encoding = (Tcl_Encoding)NULL;
} else if (TYPE(enc) == T_STRING) {
encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
} else {
enc = rb_funcall(enc, ID_to_s, 0, 0);
encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
enc = rb_funcall(enc, ID_to_s, 0, 0);
encoding = Tcl_GetEncoding(interp, RSTRING(enc)->ptr);
}
/* to avoid a garbled error message dialog */
@ -1008,7 +1011,9 @@ ip_ruby_eval_body(arg)
(VALUE)0);
#else
rb_thread_critical = Qfalse;
ret = rb_eval_string_protect(arg->string, &status);
rb_thread_critical = Qtrue;
if (status) {
char *errtype, *buf;
int errtype_len, len;
@ -1288,9 +1293,13 @@ ip_ruby_cmd_core(arg)
struct cmd_body_arg *arg;
{
VALUE ret;
int thr_crit_bup;
DUMP1("call ip_ruby_cmd_core");
thr_crit_bup = rb_thread_critical;
rb_thread_critical = Qfalse;
ret = rb_apply(arg->receiver, arg->method, arg->args);
rb_thread_critical = thr_crit_bup;
DUMP1("finish ip_ruby_cmd_core");
return ret;
@ -3464,12 +3473,17 @@ lib_toUTF8_core(ip_obj, src, encodename)
if (TYPE(str) == T_STRING) {
volatile VALUE enc;
enc = rb_ivar_get(str, ID_at_enc);
enc = Qnil;
if (RTEST(rb_ivar_defined(str, ID_at_enc))) {
enc = rb_ivar_get(str, ID_at_enc);
}
if (NIL_P(enc)) {
if (NIL_P(ip_obj)) {
encoding = (Tcl_Encoding)NULL;
} else {
enc = rb_ivar_get(ip_obj, ID_at_enc);
if (RTEST(rb_ivar_defined(ip_obj, ID_at_enc))) {
enc = rb_ivar_get(ip_obj, ID_at_enc);
}
if (NIL_P(enc)) {
encoding = (Tcl_Encoding)NULL;
} else {
@ -3592,7 +3606,10 @@ lib_fromUTF8_core(ip_obj, src, encodename)
volatile VALUE enc;
if (TYPE(str) == T_STRING) {
enc = rb_ivar_get(str, ID_at_enc);
enc = Qnil;
if (RTEST(rb_ivar_defined(str, ID_at_enc))) {
enc = rb_ivar_get(str, ID_at_enc);
}
if (!NIL_P(enc) && strcmp(StringValuePtr(enc), "binary") == 0) {
rb_thread_critical = thr_crit_bup;
return str;
@ -3602,7 +3619,10 @@ lib_fromUTF8_core(ip_obj, src, encodename)
if (NIL_P(ip_obj)) {
encoding = (Tcl_Encoding)NULL;
} else {
enc = rb_ivar_get(ip_obj, ID_at_enc);
enc = Qnil;
if (RTEST(rb_ivar_defined(ip_obj, ID_at_enc))) {
enc = rb_ivar_get(ip_obj, ID_at_enc);
}
if (NIL_P(enc)) {
encoding = (Tcl_Encoding)NULL;
} else {
@ -3947,7 +3967,10 @@ alloc_invoke_arguments(argc, argv)
# if TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION == 0
av[i] = Tcl_NewStringObj(s, RSTRING(v)->len);
# else /* TCL_VERSION >= 8.1 */
enc = rb_ivar_get(v, ID_at_enc);
enc = Qnil;
if (RTEST(rb_ivar_defined(v, ID_at_enc))) {
enc = rb_ivar_get(v, ID_at_enc);
}
if (!NIL_P(enc) && strcmp(StringValuePtr(enc), "binary") == 0) {
/* binary string */
av[i] = Tcl_NewByteArrayObj(s, RSTRING(v)->len);
@ -4461,7 +4484,11 @@ ip_set_variable(self, varname_arg, value_arg, flag_arg)
Tcl_IncrRefCount(valobj);
# else /* TCL_VERSION >= 8.1 */
{
VALUE enc = rb_ivar_get(value, ID_at_enc);
VALUE enc = Qnil;
if (RTEST(rb_ivar_defined(value, ID_at_enc))) {
enc = rb_ivar_get(value, ID_at_enc);
}
if (!NIL_P(enc) && strcmp(StringValuePtr(enc), "binary") == 0) {
/* binary string */
@ -4581,7 +4608,11 @@ ip_set_variable2(self, varname_arg, index_arg, value_arg, flag_arg)
RSTRING(value)->len);
# else /* TCL_VERSION >= 8.1 */
{
VALUE enc = rb_ivar_get(value, ID_at_enc);
VALUE enc = Qnil;
if (RTEST(rb_ivar_defined(value, ID_at_enc))) {
enc = rb_ivar_get(value, ID_at_enc);
}
if (!NIL_P(enc) && strcmp(StringValuePtr(enc), "binary") == 0) {
/* binary string */
@ -4820,7 +4851,11 @@ lib_split_tklist_core(ip_obj, list_str)
rb_thread_critical = Qtrue;
{
VALUE enc = rb_ivar_get(list_str, ID_at_enc);
VALUE enc = Qnil;
if (RTEST(rb_ivar_defined(list_str, ID_at_enc))) {
enc = rb_ivar_get(list_str, ID_at_enc);
}
if (!NIL_P(enc) && strcmp(StringValuePtr(enc), "binary") == 0) {
/* binary string */

View file

@ -52,6 +52,7 @@ lib/tk/listbox.rb
lib/tk/macpkg.rb
lib/tk/menu.rb
lib/tk/menubar.rb
lib/tk/menuspec.rb
lib/tk/message.rb
lib/tk/mngfocus.rb
lib/tk/msgcat.rb
@ -92,6 +93,8 @@ sample/binstr_usage.rb
sample/btn_with_frame.rb
sample/encstr_usage.rb
sample/iso2022-kr.txt
sample/menubar1.rb
sample/menubar2.rb
sample/propagate.rb
sample/resource.en
sample/resource.ja

View file

@ -1324,7 +1324,8 @@ class MultiTkIp
else
list.push str[0..i-1]
end
list += _lst2ary(str[i+1..-1])
#list += _lst2ary(str[i+1..-1])
list.concat(_lst2ary(str[i+1..-1]))
list
end
private :_lst2ary

View file

@ -114,7 +114,7 @@ module TkComm
private :_genobj_for_tkwidget
module_function :_genobj_for_tkwidget
def tk_tcl2ruby(val, enc_mode = nil)
def tk_tcl2ruby(val, enc_mode = nil, listobj = true)
if val =~ /^rb_out\S* (c(_\d+_)?\d+)/
#return Tk_CMDTBL[$1]
return TkCore::INTERP.tk_cmd_tbl[$1]
@ -141,12 +141,18 @@ module TkComm
TkImage::Tk_IMGTBL[val]? TkImage::Tk_IMGTBL[val] : val
when /^-?\d+\.?\d*(e[-+]?\d+)?$/
val.to_f
when /[^\\] /
tk_split_escstr(val).collect{|elt|
tk_tcl2ruby(elt)
}
when /\\ /
val.gsub(/\\ /, ' ')
when /[^\\] /
if listobj
tk_split_escstr(val).collect{|elt|
tk_tcl2ruby(elt, enc_mode, listobj)
}
elsif enc_mode
_fromUTF8(val)
else
val
end
else
if enc_mode
_fromUTF8(val)
@ -157,6 +163,8 @@ module TkComm
end
private :tk_tcl2ruby
module_function :tk_tcl2ruby
private_class_method :tk_tcl2ruby
unless const_defined?(:USE_TCLs_LIST_FUNCTIONS)
USE_TCLs_LIST_FUNCTIONS = true
@ -171,19 +179,28 @@ if USE_TCLs_LIST_FUNCTIONS
TkCore::INTERP._split_tklist(str)
end
def tk_split_sublist(str)
return [] if str == ""
list = TkCore::INTERP._split_tklist(str)
if list.size == 1
tk_tcl2ruby(list[0])
def tk_split_sublist(str, depth=-1)
# return [] if str == ""
# list = TkCore::INTERP._split_tklist(str)
if depth == 0
return "" if str == ""
list = [str]
else
list.collect{|token| tk_split_sublist(token)}
return [] if str == ""
list = TkCore::INTERP._split_tklist(str)
end
if list.size == 1
tk_tcl2ruby(list[0], nil, false)
else
list.collect{|token| tk_split_sublist(token, depth - 1)}
end
end
def tk_split_list(str)
def tk_split_list(str, depth=0)
return [] if str == ""
TkCore::INTERP._split_tklist(str).collect{|token| tk_split_sublist(token)}
TkCore::INTERP._split_tklist(str).collect{|token|
tk_split_sublist(token, depth - 1)
}
end
def tk_split_simplelist(str)
@ -239,20 +256,29 @@ else
list
end
def tk_split_sublist(str)
return [] if str == ""
return [tk_split_sublist(str[1..-2])] if str =~ /^\{.*\}$/
list = tk_split_escstr(str)
if list.size == 1
tk_tcl2ruby(list[0])
def tk_split_sublist(str, depth=-1)
#return [] if str == ""
#return [tk_split_sublist(str[1..-2])] if str =~ /^\{.*\}$/
#list = tk_split_escstr(str)
if depth == 0
return "" if str == ""
str = str[1..-2] if str =~ /^\{.*\}$/
list = [str]
else
list.collect{|token| tk_split_sublist(token)}
return [] if str == []
return [tk_split_sublist(str[1..-2], depth - 1)] if str =~ /^\{.*\}$/
list = tk_split_escstr(str)
end
if list.size == 1
tk_tcl2ruby(list[0], nil, false)
else
list.collect{|token| tk_split_sublist(token, depth - 1)}
end
end
def tk_split_list(str)
def tk_split_list(str, depth=0)
return [] if str == ""
tk_split_escstr(str).collect{|token| tk_split_sublist(token)}
tk_split_escstr(str).collect{|token| tk_split_sublist(token, depth - 1)}
end
=begin
def tk_split_list(str)
@ -425,8 +451,8 @@ end
end
=end
def list(val)
tk_split_list(val)
def list(val, depth=0)
tk_split_list(val, depth)
end
def simplelist(val)
tk_split_simplelist(val)
@ -457,9 +483,10 @@ end
val
end
end
private :bool, :number, :string, :list, :simplelist, :window, :procedure
module_function :bool, :number, :num_or_str, :string, :list, :simplelist
module_function :window, :image_obj, :procedure
private :bool, :number, :string, :num_or_str
private :list, :simplelist, :window, :procedure
module_function :bool, :number, :num_or_str, :string
module_function :list, :simplelist, :window, :image_obj, :procedure
def _toUTF8(str, encoding = nil)
TkCore::INTERP._toUTF8(str, encoding)
@ -2035,9 +2062,10 @@ class TkObject<TkKernel
include TkTreatFont
include TkBindCore
def path
@path
end
### --> definition is moved to TkUtil module
# def path
# @path
# end
def epath
@path
@ -2433,6 +2461,7 @@ class TkWindow<TkObject
TkPack.configure(self, slot=>value)
end
end
alias pack_configure pack_config
def pack_info()
#ilist = list(tk_call('pack', 'info', epath))
@ -2510,6 +2539,7 @@ class TkWindow<TkObject
TkGrid.configure(self, slot=>value)
end
end
alias grid_configure grid_config
def grid_columnconfig(index, keys)
#tk_call('grid', 'columnconfigure', epath, index, *hash_kv(keys))
@ -2625,6 +2655,7 @@ class TkWindow<TkObject
#end
TkPlace.configure(self, slot, value)
end
alias place_configure place_config
def place_configinfo(slot = nil)
# for >= Tk8.4a2 ?
@ -2640,7 +2671,7 @@ class TkWindow<TkObject
# conf
# }
#end
TkPlace.configinfo(slot)
TkPlace.configinfo(self, slot)
end
def place_info()

View file

@ -62,13 +62,26 @@ module TkGrid
# master = master.epath if master.kind_of?(TkObject)
master = _epath(master)
if slot
num_or_str(tk_call_without_enc('grid', 'columnconfigure',
master, index, "-#{slot}"))
case slot
when 'uniform', :uniform
tk_call_without_enc('grid', 'columnconfigure',
master, index, "-#{slot}")
else
num_or_str(tk_call_without_enc('grid', 'columnconfigure',
master, index, "-#{slot}"))
end
else
ilist = list(tk_call_without_enc('grid','columnconfigure',master,index))
#ilist = list(tk_call_without_enc('grid','columnconfigure',master,index))
ilist = simplelist(tk_call_without_enc('grid', 'columnconfigure',
master, index))
info = {}
while key = ilist.shift
info[key[1..-1]] = ilist.shift
case key
when 'uniform'
info[key[1..-1]] = ilist.shift
else
info[key[1..-1]] = tk_tcl2ruby(ilist.shift)
end
end
info
end
@ -78,13 +91,26 @@ module TkGrid
# master = master.epath if master.kind_of?(TkObject)
master = _epath(master)
if slot
num_or_str(tk_call_without_enc('grid', 'rowconfigure',
master, index, "-#{slot}"))
case slot
when 'uniform', :uniform
tk_call_without_enc('grid', 'rowconfigure',
master, index, "-#{slot}")
else
num_or_str(tk_call_without_enc('grid', 'rowconfigure',
master, index, "-#{slot}"))
end
else
ilist = list(tk_call_without_enc('grid', 'rowconfigure', master, index))
#ilist = list(tk_call_without_enc('grid', 'rowconfigure', master, index))
ilist = simplelist(tk_call_without_enc('grid', 'rowconfigure',
master, index))
info = {}
while key = ilist.shift
info[key[1..-1]] = ilist.shift
case key
when 'uniform'
info[key[1..-1]] = ilist.shift
else
info[key[1..-1]] = tk_tcl2ruby(ilist.shift)
end
end
info
end
@ -106,10 +132,12 @@ module TkGrid
def info(slave)
# slave = slave.epath if slave.kind_of?(TkObject)
slave = _epath(slave)
ilist = list(tk_call_without_enc('grid', 'info', slave))
#ilist = list(tk_call_without_enc('grid', 'info', slave))
ilist = simplelist(tk_call_without_enc('grid', 'info', slave))
info = {}
while key = ilist.shift
info[key[1..-1]] = ilist.shift
#info[key[1..-1]] = ilist.shift
info[key[1..-1]] = tk_tcl2ruby(ilist.shift)
end
return info
end

View file

@ -1,8 +1,9 @@
#
# tk/menubar.rb
#
# Copyright (C) 1998 maeda shugo. All rights reserved.
# This file can be distributed under the terms of the Ruby.
# Original version:
# Copyright (C) 1998 maeda shugo. All rights reserved.
# This file can be distributed under the terms of the Ruby.
# Usage:
#
@ -41,30 +42,56 @@
# menubar.configure('activeforeground', 'red')
# menubar.configure('font', '-adobe-helvetica-bold-r-*--12-*-iso8859-1')
# menubar.pack('side'=>'top', 'fill'=>'x')
# The format of the menu_spec is:
# [
# [
# [button text, underline, accelerator],
# [menu label, command, underline, accelerator],
# '---', # separator
# ...
# ],
# ...
#
#
# OR
#
# radio_var = TkVariable.new('y')
# menu_spec = [
# [['File', 0],
# {:label=>'Open', :command=>proc{puts('Open clicked')}, :underline=>0},
# '---',
# ['Check_A', TkVariable.new(true), 6],
# {:type=>'checkbutton', :label=>'Check_B',
# :variable=>TkVariable.new, :underline=>6},
# '---',
# ['Radio_X', [radio_var, 'x'], 6],
# ['Radio_Y', [radio_var, 'y'], 6],
# ['Radio_Z', [radio_var, 'z'], 6],
# '---',
# ['cascade', [
# ['sss', proc{p 'sss'}, 0],
# ['ttt', proc{p 'ttt'}, 0],
# ['uuu', proc{p 'uuu'}, 0],
# ['vvv', proc{p 'vvv'}, 0],
# ], 0],
# '---',
# ['Quit', proc{exit}, 0]],
# [['Edit', 0],
# ['Cut', proc{puts('Cut clicked')}, 2],
# ['Copy', proc{puts('Copy clicked')}, 0],
# ['Paste', proc{puts('Paste clicked')}, 0]]
# ]
# menubar = TkMenubar.new(nil, menu_spec,
# 'tearoff'=>false,
# 'foreground'=>'grey40',
# 'activeforeground'=>'red',
# 'font'=>'Helvetia 12 bold')
# menubar.pack('side'=>'top', 'fill'=>'x')
# underline and accelerator are optional parameters.
# Hashes are OK instead of Arrays.
# See tk/menuspce.rb about the format of the menu_spec
# To use add_menu, configuration must be done by calling configure after
# adding all menus by add_menu, not by the constructor arguments.
require 'tk'
require 'tk/frame'
require 'tk/composite'
require 'tk/menuspec'
class TkMenubar<TkFrame
include TkComposite
include TkMenuSpec
def initialize(parent = nil, spec = nil, options = nil)
if parent.kind_of? Hash
@ -77,65 +104,25 @@ class TkMenubar<TkFrame
@menus = []
if spec
for menu_info in spec
add_menu(menu_info)
end
end
if options
for key, value in options
configure(key, value)
end
end
spec.each{|info| add_menu(info)} if spec
options.each{|key, value| configure(key, value)} if options
end
def add_menu(menu_info)
btn_info = menu_info.shift
mbtn = TkMenubutton.new(@frame)
if btn_info.kind_of?(Hash)
for key, value in btn_info
mbtn.configure(key, value)
end
elsif btn_info.kind_of?(Array)
mbtn.configure('text', btn_info[0]) if btn_info[0]
mbtn.configure('underline', btn_info[1]) if btn_info[1]
mbtn.configure('accelerator', btn_info[2]) if btn_info[2]
else
mbtn.configure('text', btn_info)
end
menu = TkMenu.new(mbtn)
for item_info in menu_info
if item_info.kind_of?(Hash)
menu.add('command', item_info)
elsif item_info.kind_of?(Array)
options = {}
options['label'] = item_info[0] if item_info[0]
options['command'] = item_info[1] if item_info[1]
options['underline'] = item_info[2] if item_info[2]
options['accelerator'] = item_info[3] if item_info[3]
menu.add('command', options)
elsif /^-+$/ =~ item_info
menu.add('sep')
else
menu.add('command', 'label' => item_info)
end
end
mbtn.menu(menu)
mbtn, menu = _create_menubutton(@frame, menu_info)
submenus = _get_cascade_menus(menu).flatten
@menus.push([mbtn, menu])
delegate('tearoff', menu)
delegate('foreground', mbtn, menu)
delegate('background', mbtn, menu)
delegate('disabledforeground', mbtn, menu)
delegate('activeforeground', mbtn, menu)
delegate('activebackground', mbtn, menu)
delegate('font', mbtn, menu)
delegate('kanjifont', mbtn, menu)
mbtn.pack('side' => 'left')
delegate('tearoff', menu, *submenus)
delegate('foreground', mbtn, menu, *submenus)
delegate('background', mbtn, menu, *submenus)
delegate('disabledforeground', mbtn, menu, *submenus)
delegate('activeforeground', mbtn, menu, *submenus)
delegate('activebackground', mbtn, menu, *submenus)
delegate('font', mbtn, menu, *submenus)
delegate('kanjifont', mbtn, menu, *submenus)
end
def [](index)

243
ext/tk/lib/tk/menuspec.rb Normal file
View file

@ -0,0 +1,243 @@
#
# tk/menuspec.rb
# Hidethoshi NAGAI (nagai@ai.kyutech.ac.jp)
#
# based on tkmenubar.rb :
# Copyright (C) 1998 maeda shugo. All rights reserved.
# This file can be distributed under the terms of the Ruby.
#
# The format of the menu_spec is:
# [ menu_info, menu_info, ... ]
#
# And the format of the menu_info is:
# [
# [text, underline, configs], # menu button/entry (*1)
# [label, command, underline, accelerator, configs], # command entry
# [label, TkVar_obj, underline, accelerator, configs], # checkbutton entry
# [label, [TkVar_obj, value],
# underline, accelerator, configs], # radiobutton entry
# [label, [[...menu_info...], [...menu_info...], ...],
# underline, accelerator, configs], # cascade entry
# '---', # separator
# ...
# ]
#
# underline, accelerator, and configs are optional pearameters.
# Hashes are OK instead of Arrays. Then the entry type ('command',
# 'checkbutton', 'radiobutton' or 'cascade') is given by 'type' key
# (e.g. :type=>'cascade'). When type is 'cascade', an array of menu_info
# is acceptable for 'menu' key (then, create sub-menu).
#
# NOTE: (*1)
# If you want to make special menus (*.help for UNIX, *.system for Win,
# and *.apple for Mac), append 'menu_name'=>name (name is 'help' for UNIX,
# 'system' for Win, and 'apple' for Mac) option to the configs hash of
# menu button/entry information.
module TkMenuSpec
def _create_menu(parent, menu_info, menu_name = nil,
tearoff = false, default_opts = nil)
if tearoff.kind_of?(Hash)
default_opts = tearoff
tearoff = false
end
if menu_name.kind_of?(Hash)
default_opts = menu_name
menu_name = nil
tearoff = false
end
if default_opts.kind_of?(Hash)
orig_opts = _symbolkey2str(default_opts)
else
orig_opts = {}
end
tearoff = orig_opts.delete('tearoff') if orig_opts.key?('tearoff')
if menu_name
menu = TkMenu.new(parent, :widgetname=>menu_name, :tearoff=>tearoff)
else
menu = TkMenu.new(parent, :tearoff=>tearoff)
end
for item_info in menu_info
if item_info.kind_of?(Hash)
options = orig_opts.dup
options.update(_symbolkey2str(item_info))
item_type = (options.delete('type') || 'command').to_s
menu_name = options.delete('menu_name')
menu_opts = orig_opts.dup
menu_opts.update(_symbolkey2str(options.delete('menu_config') || {}))
if item_type == 'cascade' && options['menu'].kind_of?(Array)
# create cascade menu
submenu = _create_menu(menu, options['menu'], menu_name,
tearoff, menu_opts)
options['menu'] = submenu
end
menu.add(item_type, options)
elsif item_info.kind_of?(Array)
options = orig_opts.dup
options['label'] = item_info[0] if item_info[0]
case item_info[1]
when TkVariable
# checkbutton
item_type = 'checkbutton'
options['variable'] = item_info[1]
options['onvalue'] = true
options['offvalue'] = false
when Array
# radiobutton or cascade
if item_info[1][0].kind_of?(TkVariable)
# radiobutton
item_type = 'radiobutton'
options['variable'] = item_info[1][0]
options['value'] = item_info[1][1] if item_info[1][1]
else
# cascade
item_type = 'cascade'
menu_opts = orig_opts.dup
if item_info[4] && item_info[4].kind_of?(Hash)
opts = _symbolkey2str(item_info[4])
menu_name = opts.delete('menu_name')
menu_config = opts.delete('menu_config') || {}
menu_opts.update(_symbolkey2str(menu_config))
end
submenu = _create_menu(menu, item_info[1], menu_name,
tearoff, menu_opts)
options['menu'] = submenu
end
else
# command
item_type = 'command'
options['command'] = item_info[1] if item_info[1]
end
options['underline'] = item_info[2] if item_info[2]
options['accelerator'] = item_info[3] if item_info[3]
if item_info[4] && item_info[4].kind_of?(Hash)
opts = _symbolkey2str(item_info[4])
if item_type == 'cascade'
opts.delete('menu_name')
opts.delete('menu_config')
end
options.update(opts)
end
menu.add(item_type, options)
elsif /^-+$/ =~ item_info
menu.add('separator')
else
menu.add('command', 'label' => item_info)
end
end
menu
end
private :_create_menu
def _create_menubutton(parent, menu_info, tearoff=false, default_opts = nil)
btn_info = menu_info[0]
if tearoff.kind_of?(Hash)
default_opts = tearoff
tearoff = false
end
if default_opts.kind_of?(Hash)
keys = _symbolkey2str(default_opts)
else
keys = {}
end
tearoff = keys.delete('tearoff') if keys.key?('tearoff')
if parent.kind_of?(TkRoot) || parent.kind_of?(TkToplevel)
# menubar by menu entries
unless (mbar = parent.menu).kind_of?(TkMenu)
mbar = TkMenu.new(parent, :tearoff=>false)
parent.menu(mbar)
end
menu_name = nil
if btn_info.kind_of?(Hash)
keys.update(_symbolkey2str(btn_info))
menu_name = keys.delete('menu_name')
keys['label'] = keys.delete('text') if keys.key?('text')
elsif btn_info.kind_of?(Array)
keys['label'] = btn_info[0] if btn_info[0]
keys['underline'] = btn_info[1] if btn_info[1]
if btn_info[2]&&btn_info[2].kind_of?(Hash)
keys.update(_symbolkey2str(btn_info[2]))
menu_name = keys.delete('menu_name')
end
else
keys = {:label=>btn_info}
end
menu = _create_menu(mbar, menu_info[1..-1], menu_name,
tearoff, default_opts)
menu.tearoff(tearoff)
keys['menu'] = menu
mbar.add('cascade', keys)
[mbar, menu]
else
# menubar by menubuttons
mbtn = TkMenubutton.new(parent)
menu_name = nil
if btn_info.kind_of?(Hash)
keys.update(_symbolkey2str(btn_info))
menu_name = keys.delete('menu_name')
keys['text'] = keys.delete('label') if keys.key?('label')
mbtn.configure(keys)
elsif btn_info.kind_of?(Array)
mbtn.configure('text', btn_info[0]) if btn_info[0]
mbtn.configure('underline', btn_info[1]) if btn_info[1]
# mbtn.configure('accelerator', btn_info[2]) if btn_info[2]
if btn_info[2]&&btn_info[2].kind_of?(Hash)
keys.update(_symbolkey2str(btn_info[2]))
menu_name = keys.delete('menu_name')
mbtn.configure(keys)
end
else
mbtn.configure('text', btn_info)
end
mbtn.pack('side' => 'left')
menu = _create_menu(mbtn, menu_info[1..-1], menu_name,
tearoff, default_opts)
mbtn.menu(menu)
[mbtn, menu]
end
end
private :_create_menubutton
def _get_cascade_menus(menu)
menus = []
(0..(menu.index('last'))).each{|idx|
if menu.menutype(idx) == 'cascade'
submenu = menu.entrycget(idx, 'menu')
menus << [submenu, _get_cascade_menus(submenu)]
end
}
menus
end
private :_get_cascade_menus
end

View file

@ -52,7 +52,8 @@ module TkOptionDB
cline = ''
open(file, 'r') {|f|
while line = f.gets
cline += line.chomp!
#cline += line.chomp!
cline.concat(line.chomp!)
case cline
when /\\$/ # continue
cline.chop!

View file

@ -34,14 +34,21 @@ module TkPlace
# win = win.epath if win.kind_of?(TkObject)
win = _epath(win)
if slot
conf = tk_split_list(tk_call_without_enc('place', 'configure',
win, "-#{slot}") )
#conf = tk_split_list(tk_call_without_enc('place', 'configure',
# win, "-#{slot}") )
conf = tk_split_simplelist(tk_call_without_enc('place', 'configure',
win, "-#{slot}") )
conf[0] = conf[0][1..-1]
conf[1] = tk_tcl2ruby(conf[1])
conf[2] = tk_tcl2ruby(conf[1])
conf[3] = tk_tcl2ruby(conf[1])
conf[4] = tk_tcl2ruby(conf[1])
conf
else
tk_split_simplelist(tk_call_without_enc('place', 'configure',
win)).collect{|conflist|
conf = list(conflist)
#conf = list(conflist)
conf = simplelist(conflist).collect!{|inf| tk_tcl2ruby(inf)}
conf[0] = conf[0][1..-1]
conf
}
@ -55,13 +62,20 @@ module TkPlace
# win = win.epath if win.kind_of?(TkObject)
win = _epath(win)
if slot
conf = tk_split_list(tk_call_without_enc('place', 'configure',
win, "-#{slot}") )
{ conf[0][1..-1] => conf[1] }
#conf = tk_split_list(tk_call_without_enc('place', 'configure',
# win, "-#{slot}") )
conf = tk_split_simplelist(tk_call_without_enc('place', 'configure',
win, "-#{slot}") )
# { conf[0][1..-1] => conf[1] }
{ conf[0][1..-1] => tk_tcl2ruby(conf[4]) }
else
ret = {}
tk_split_list(tk_call_without_enc('place','configure',win)).each{|conf|
ret[conf[0][1..-1]] = conf[1]
#tk_split_list(tk_call_without_enc('place','configure',win)).each{|conf|
tk_split_simplelist(tk_call_without_enc('place', 'configure',
win)).each{|conf_list|
#ret[conf[0][1..-1]] = conf[1]
conf = simplelist(conf_list)
ret[conf[0][1..-1]] = tk_tcl2ruby(conf[4])
}
ret
end
@ -76,10 +90,12 @@ module TkPlace
def info(win)
# win = win.epath if win.kind_of?(TkObject)
win = _epath(win)
ilist = list(tk_call_without_enc('place', 'info', win))
#ilist = list(tk_call_without_enc('place', 'info', win))
ilist = simplelist(tk_call_without_enc('place', 'info', win))
info = {}
while key = ilist.shift
info[key[1..-1]] = ilist.shift
#info[key[1..-1]] = ilist.shift
info[key[1..-1]] = tk_tcl2ruby(ilist.shift)
end
return info
end
@ -90,7 +106,8 @@ module TkPlace
list(tk_call('place', 'slaves', master))
end
module_function :configure, :configinfo, :forget, :info, :slaves
module_function :configure, :configinfo, :current_configinfo
module_function :forget, :info, :slaves
end
=begin
def TkPlace(win, slot, value=None)

View file

@ -3,9 +3,11 @@
#
require 'tk'
require 'tk/wm'
require 'tk/menuspec'
class TkRoot<TkWindow
include Wm
include TkMenuSpec
=begin
ROOT = []
@ -59,6 +61,25 @@ class TkRoot<TkWindow
"."
end
def add_menu(menu_info, tearoff=false, opts=nil)
# See tk/menuspec.rb for menu_info.
# opts is a hash of default configs for all of cascade menus.
# Configs of menu_info can override it.
if tearoff.kind_of?(Hash)
opts = tearoff
tearoff = false
end
_create_menubutton(self, menu_info, tearoff, opts)
end
def add_menubar(menu_spec, tearoff=false, opts=nil)
# See tk/menuspec.rb for menu_spec.
# opts is a hash of default configs for all of cascade menus.
# Configs of menu_spec can override it.
menu_spec.each{|info| add_menu(info, tearoff, opts)}
self.menu
end
def TkRoot.destroy
TkCore::INTERP._invoke('destroy', '.')
end

View file

@ -67,6 +67,11 @@ class TkText<TkTextWin
tk_send_without_enc('index', _get_eval_enc_str(index))
end
def get_displaychars(*index)
# Tk8.5 feature
get('-displaychars', *index)
end
def value
_fromUTF8(tk_send_without_enc('get', "1.0", "end - 1 char"))
end
@ -326,9 +331,35 @@ class TkText<TkTextWin
end
def count(idx1, idx2, *opts)
opts = opts.collect{|opt| '-' + opt.to_s}
number(tk_send_without_enc('count', _get_eval_enc_str(idx1),
_get_eval_enc_str(idx2), *opts))
# opts are Tk8.5 feature
cnt = 0
args = opts.collect{|opt|
str = opt.to_s
cnt += 1 if str != 'update'
'-' + str
}
args << _get_eval_enc_str(idx1) << _get_eval_enc_str(idx2)
if cnt <= 1
number(tk_send_without_enc('count', *opts))
else
list(tk_send_without_enc('count', *opts))
end
end
def count_info(idx1, idx2, update=true)
# Tk8.5 feature
opts = [
:chars, :displaychars, :displayindices, :displaylines,
:indices, :lines, :xpixels, :ypixels
]
if update
lst = count(idx1, idx2, :update, *opts)
else
lst = count(idx1, idx2, *opts)
end
info = {}
opts.each_with_index{|key, idx| info[key] = lst[idx]}
info
end
def replace(idx1, idx2, *opts)
@ -879,53 +910,40 @@ class TkText<TkTextWin
def tksearch(*args)
# call 'search' subcommand of text widget
# args ::= [<array_of_opts>] <pattern> <start_index> [<stop_index>]
# <pattern> must be a regular expression of Tcl
all_mode = false
opts = args.shift
if opts.kind_of?(Array)
opts = opts.collect{|opt|
opt = opt.to_s
all_mode = true if opt == 'all'
opt
}
# If <pattern> is regexp, then it must be a regular expression of Tcl
if args[0].kind_of?(Array)
opts = args.shift.collect{|opt| '-' + opt.to_s }
else
args.unshift(opts)
opts = []
end
opts << '--'
if all_mode
tk_split_simplelist(tk_send(*(opts + args)))
ret = tk_send('search', *(opts + args))
if ret == ""
nil
else
tk_send(*(opts + args))
ret
end
end
def tksearch_with_count(*args)
# call 'search' subcommand of text widget
# args ::= [<array_of_opts>] <var> <pattern> <start_index> [<stop_index>]
# <pattern> must be a regular expression of Tcl
all_mode = false
opts = args.shift
if opts.kind_of?(Array)
opts = opts.collect{|opt|
opt = opt.to_s
all_mode = true if opt == 'all'
opt
}
var = args.shift
# If <pattern> is regexp, then it must be a regular expression of Tcl
if args[0].kind_of?(Array)
opts = args.shift.collect{|opt| '-' + opt.to_s }
else
var = opts
opts = []
end
opts << '-count' << var << '--'
opts << '-count' << args.shift << '--'
if all_mode
tk_split_simplelist(tk_send(*(opts + args)))
ret = tk_send('search', *(opts + args))
if ret == ""
nil
else
tk_send(*(opts + args))
ret
end
end

View file

@ -3,9 +3,11 @@
#
require 'tk'
require 'tk/wm'
require 'tk/menuspec'
class TkToplevel<TkWindow
include Wm
include TkMenuSpec
TkCommandNames = ['toplevel'.freeze].freeze
WidgetClassName = 'Toplevel'.freeze
@ -169,6 +171,25 @@ class TkToplevel<TkWindow
@classname
end
def add_menu(menu_info, tearoff=false, opts=nil)
# See tk/menuspec.rb for menu_info.
# opts is a hash of default configs for all of cascade menus.
# Configs of menu_info can override it.
if tearoff.kind_of?(Hash)
opts = tearoff
tearoff = false
end
_create_menubutton(self, menu_info, tearoff, opts)
end
def add_menubar(menu_spec, tearoff=false, opts=nil)
# See tk/menuspec.rb for menu_spec.
# opts is a hash of default configs for all of cascade menus.
# Configs of menu_spec can override it.
menu_spec.each{|info| add_menu(info, tearoff, opts)}
self.menu
end
def self.database_class
if self == WidgetClassNames[WidgetClassName] || self.name == ''
self

View file

@ -588,7 +588,8 @@ end
=end
else
newopts = @trace_opts.dup
opts.each_byte{|c| newopts += c.chr unless newopts.index(c)}
#opts.each_byte{|c| newopts += c.chr unless newopts.index(c)}
opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
if newopts != @trace_opts
Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var')
@trace_opts.replace(newopts)
@ -637,7 +638,8 @@ end
=end
else
newopts = @trace_opts.dup
opts.each_byte{|c| newopts += c.chr unless newopts.index(c)}
# opts.each_byte{|c| newopts += c.chr unless newopts.index(c)}
opts.each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
if newopts != @trace_opts
Tk.tk_call_without_enc('trace', 'vdelete', @id, @trace_opts, 'rb_var')
@trace_opts.replace(newopts)
@ -684,7 +686,8 @@ end
idx = i
next
end
e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
# e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
}
if idx >= 0
@trace_var.delete_at(idx)
@ -694,7 +697,8 @@ end
@trace_elem.each{|elem|
@trace_elem[elem].each{|e|
e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
# e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
}
}
@ -751,11 +755,13 @@ end
newopts = ''
@trace_var.each{|e|
e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
# e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
}
@trace_elem.each{|elem|
@trace_elem[elem].each{|e|
e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
# e[0].each_byte{|c| newopts += c.chr unless newopts.index(c)}
e[0].each_byte{|c| newopts.concat(c.chr) unless newopts.index(c)}
}
}

51
ext/tk/sample/menubar1.rb Normal file
View file

@ -0,0 +1,51 @@
#
# menubar sample 1 : use frame and menubuttons
#
require 'tk'
radio_var = TkVariable.new('y')
menu_spec = [
[['File', 0],
{:label=>'Open', :command=>proc{puts('Open clicked')}, :underline=>0},
'---',
['Check_A', TkVariable.new(true), 6],
{:type=>'checkbutton', :label=>'Check_B',
:variable=>TkVariable.new, :underline=>6},
'---',
['Radio_X', [radio_var, 'x'], 6, '', {:foreground=>'black'}],
['Radio_Y', [radio_var, 'y'], 6],
['Radio_Z', [radio_var, 'z'], 6],
'---',
['cascade', [
['sss', proc{p 'sss'}, 0],
['ttt', proc{p 'ttt'}, 0],
['uuu', proc{p 'uuu'}, 0],
['vvv', proc{p 'vvv'}, 0],
],
0, '',
{:font=>'Courier 16 italic',
:menu_config=>{:font=>'Times -18 bold', :foreground=>'black'}}],
'---',
['Quit', proc{exit}, 0]],
[['Edit', 0],
['Cut', proc{puts('Cut clicked')}, 2],
['Copy', proc{puts('Copy clicked')}, 0],
['Paste', proc{puts('Paste clicked')}, 0]],
[['Help', 0, {:menu_name=>'help'}],
['About This', proc{puts('Ruby/Tk menubar sample 1')}, 6]]
]
menubar = TkMenubar.new(nil, menu_spec,
'tearoff'=>false,
'foreground'=>'grey40',
'activeforeground'=>'red',
'font'=>'Helvetia 12 bold')
menubar.pack('side'=>'top', 'fill'=>'x')
TkText.new(:wrap=>'word').pack.insert('1.0', 'Please read the sample source, and check how to override default configure options of menu entries on a menu_spec. Maybe, on windows, this menubar does not work properly about keyboard shortcuts. Then, please use "menu" option of root/toplevel widget (see sample/menubar2.rb).')
Tk.mainloop

56
ext/tk/sample/menubar2.rb Normal file
View file

@ -0,0 +1,56 @@
#
# menubar sample 2 : use 'menu' option of root/toplevel widget
#
require 'tk'
radio_var = TkVariable.new('y')
menu_spec = [
[['File', 0],
{:label=>'Open', :command=>proc{puts('Open clicked')}, :underline=>0},
'---',
['Check_A', TkVariable.new(true), 6],
{:type=>'checkbutton', :label=>'Check_B',
:variable=>TkVariable.new, :underline=>6},
'---',
['Radio_X', [radio_var, 'x'], 6, '', {:foreground=>'black'}],
['Radio_Y', [radio_var, 'y'], 6],
['Radio_Z', [radio_var, 'z'], 6],
'---',
['cascade', [
['sss', proc{p 'sss'}, 0],
['ttt', proc{p 'ttt'}, 0],
['uuu', proc{p 'uuu'}, 0],
['vvv', proc{p 'vvv'}, 0],
],
0, '',
{:font=>'Courier 16 italic',
:menu_config=>{:font=>'Times -18 bold', :foreground=>'black'}}],
'---',
['Quit', proc{exit}, 0]],
[['Edit', 0],
['Cut', proc{puts('Cut clicked')}, 2],
['Copy', proc{puts('Copy clicked')}, 0],
['Paste', proc{puts('Paste clicked')}, 0]],
[['Help', 0, {:menu_name=>'help'}],
['About This', proc{puts('Ruby/Tk menubar sample 2')}, 6]]
]
mbar = Tk.root.add_menubar(menu_spec,
# followings are default configure options
'tearoff'=>'false',
'foreground'=>'grey40',
'activeforeground'=>'red',
'font'=>'Helvetia 12 bold')
# This (default configure options) is NOT same the following.
#
# mbar = Tk.root.add_menubar(menu_spec)
# mbar.configure('foreground'=>'grey40', 'activeforeground'=>'red',
# 'font'=>'Helvetia 12 bold')
TkText.new(:wrap=>'word').pack.insert('1.0', 'Please read the sample source, and check how to override default configure options of menu entries on a menu_spec.')
Tk.mainloop

View file

@ -27,6 +27,7 @@ static ID ID_split_tklist;
static ID ID_toUTF8;
static ID ID_fromUTF8;
static ID ID_path;
static ID ID_at_path;
static ID ID_to_eval;
static ID ID_to_s;
static ID ID_install_cmd;
@ -1073,7 +1074,7 @@ static VALUE
tkobj_path(self)
VALUE self;
{
return rb_ivar_get(self, ID_path);
return rb_ivar_get(self, ID_at_path);
}
/*************************************/
@ -1091,6 +1092,7 @@ Init_tkutil()
cMethod = rb_const_get(rb_cObject, rb_intern("Method"));
ID_path = rb_intern("path");
ID_at_path = rb_intern("@path");
ID_to_eval = rb_intern("to_eval");
ID_to_s = rb_intern("to_s");
ID_install_cmd = rb_intern("install_cmd");