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# 10require 'tk' 11 12module 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 212end 213