1 #
2 # tk/optionobj.rb : control options for a group of widgets
3 #
4 # NOTE: If you want to use key-only option (no value),
5 # use Tk::None for the value of the key-only option.
6 #
7 # e.g. hash_kv({'aaa'=>1, 'bbb'=>Tk::None, 'ccc'=>3})
8 # => ["-aaa", 1, "-bbb", "-ccc", 3]
9 #
10 require 'tk'
11
12 module Tk
13 class OptionObj < Hash
14 include TkUtil
15
16 def initialize(hash = nil)
17 super()
18 @observ = []
19 update_without_notify(_symbolkey2str(hash)) if hash
20 end
21
22 def observ_info
23 @observ.dup
24 end
25
26 def observs
27 @observ.collect{|win|
28 if win.kind_of?(Array)
29 win[0]
30 else
31 win
32 end
33 }
34 end
35
36 def _remove_win(win)
37 if win.kind_of?(Array)
38 widget, method = win
39 @observ.delete_if{|x|
40 if x.kind_of?(Array)
41 x[0] == widget
42 else
43 x == widget
44 end
45 }
46 else
47 @observ.delete_if{|x|
48 if x.kind_of?(Array)
49 x[0] == win
50 else
51 x == win
52 end
53 }
54 end
55 end
56 private :_remove_win
57
58 def assign(*wins)
59 # win :=
60 # widget #==> call widget.configure(hash)
61 # [widget] #==> call widget.configure(hash)
62 # [widget, nil, {src=>target, ... }]
63 # #==> call widget.configure(hash)
64 # with converting hash-key
65 # [widget, method] #==> call widget.method(hash)
66 # [widget, method, {src=>target, ... }]
67 # #==> call widget.method(hash)
68 # with converting hash-key
69 # [widget [receiver, method, arg, ... ]]
70 # #==> call receiver.method(arg, ... , hash)
71 # [widget [receiver, method, arg, ... ], {src=>target, ... }]
72 # #==> call receiver.method(arg, ... , hash)
73 # with onverting hash-key
74 #
75 # src := option_name_on_optobj
76 #
77 # target :=
78 # nil #==> not use the src
79 # option_name_on_target_widget
80 # [ option_name_on_target_widget, ... ]
81 # #==> set all of them
82 #
83 wins.each{|win|
84 _remove_win(win)
85 @observ << win
86 notify(win)
87 }
88 self
89 end
90
91 def unassign(*wins)
92 wins.each{|win|
93 _remove_win(win)
94 }
95 self
96 end
97
98 def notify(target = nil)
99 if target
100 targets = [target]
101 elsif @observ.empty?
102 return self
103 else
104 targets = @observ.dup
105 end
106
107 return self if empty?
108
109 org_hash = _symbolkey2str(self)
110
111 targets.each{|win|
112 widget = receiver = win
113 hash = org_hash
114 begin
115 if win.kind_of?(Array)
116 widget, method, conv_tbl = win
117 receiver = widget
118
119 if conv_tbl
120 hash = {}
121 org_hash.each{|key, val|
122 key = conv_tbl[key] if conv_tbl.key?(key)
123 next unless key
124 if key.kind_of?(Array)
125 key.each{|k| hash[k] = val}
126 else
127 hash[key] = val
128 end
129 }
130 end
131
132 if method.kind_of?(Array)
133 receiver, method, *args = method
134 receiver.__send__(method, *(args << hash))
135 elsif method
136 widget.__send__(method, hash)
137 else
138 widget.configure(hash)
139 end
140
141 else
142 widget.configure(self)
143 end
144 rescue => e
145 if ( ( widget.kind_of?(TkObject) \
146 && widget.respond_to?('exist?') \
147 && ! receiver.exist? ) \
148 || ( receiver.kind_of?(TkObject) \
149 && receiver.respond_to?('exist?') \
150 && ! receiver.exist? ) )
151 @observ.delete(win)
152 else
153 fail e
154 end
155 end
156 }
157
158 self
159 end
160 alias apply notify
161
162 def +(hash)
163 unless hash.kind_of?(Hash)
164 fail ArgumentError, "expect a Hash"
165 end
166 new_obj = self.dup
167 new_obj.update_without_notify(_symbolkey2str(hash))
168 new_obj
169 end
170
171 alias update_without_notify update
172
173 def update(hash)
174 update_without_notify(_symbolkey2str(hash))
175 notify
176 end
177
178 def configure(key, value=nil)
179 if key.kind_of?(Hash)
180 update(key)
181 else
182 store(key,value)
183 end
184 end
185
186 def [](key)
187 super(key.to_s)
188 end
189 alias cget []
190
191 def store(key, val)
192 key = key.to_s
193 super(key, val)
194 notify
195 end
196 def []=(key, val)
197 store(key,val)
198 end
199
200 def replace(hash)
201 super(_symbolkey2str(hash))
202 notify
203 end
204
205 def default(opt)
206 fail RuntimeError, "unknown option `#{opt}'"
207 end
208 private :default
209
210 undef :default=
211 end
212 end