glimmer-dsl-tk 0.0.22 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,187 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ require 'glimmer/tk/widget_proxy'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ # Proxy for Tk::Text
27
+ #
28
+ # Follows the Proxy Design Pattern
29
+ class TextProxy < WidgetProxy
30
+ def handle_listener(listener_name, &listener)
31
+ listener_name = listener_name.to_s.downcase
32
+ case listener_name
33
+ when '<<modified>>', '<modified>', 'modified'
34
+ modified_listener = Proc.new do |*args|
35
+ listener.call(*args)
36
+ @tk.modified = false
37
+ end
38
+ bind('<Modified>', modified_listener)
39
+ when '<<selection>>', '<selection>', 'selection'
40
+ bind('<Selection>', listener)
41
+ else
42
+ super
43
+ end
44
+ end
45
+
46
+ def text=(value)
47
+ if value != @text
48
+ if @text && value.start_with?(@text)
49
+ insert('end', value[@text.size..-1])
50
+ else
51
+ delete('1.0', 'end')
52
+ insert('end', value)
53
+ end
54
+ @text = value
55
+ end
56
+ end
57
+
58
+ def text
59
+ @text = get("1.0", 'end')
60
+ end
61
+
62
+ def add_selection_format(option, value)
63
+ process_selection_ranges { |range_start, range_end| add_format(range_start, range_end, option, value) }
64
+ end
65
+
66
+ def remove_selection_format(option, value)
67
+ process_selection_ranges { |range_start, range_end| remove_format(range_start, range_end, option, value) }
68
+ end
69
+
70
+ def toggle_selection_format(option, value)
71
+ process_selection_ranges { |range_start, range_end| toggle_format(range_start, range_end, option, value) }
72
+ end
73
+
74
+ def add_selection_font_format(option, value)
75
+ process_selection_ranges { |range_start, range_end| add_font_format(range_start, range_end, option, value) }
76
+ end
77
+
78
+ def remove_selection_font_format(option, value)
79
+ process_selection_ranges { |range_start, range_end| remove_font_format(range_start, range_end, option, value) }
80
+ end
81
+
82
+ def toggle_selection_font_format(option, value)
83
+ process_selection_ranges { |range_start, range_end| toggle_font_format(range_start, range_end, option, value) }
84
+ end
85
+
86
+ def process_selection_ranges(&processor)
87
+ @tk.tag_ranges('sel').each do |region|
88
+ range_start = region.first
89
+ range_end = region.last
90
+ processor.call(range_start, range_end)
91
+ end
92
+ end
93
+
94
+ def applied_format?(region_start, region_end, option, value)
95
+ !applied_format_tags(region_start, region_end, option, value).empty?
96
+ end
97
+
98
+ def applied_format_tags(region_start, region_end, option, value)
99
+ tag_names = @tk.tag_names - ['sel']
100
+
101
+ tag_names.select do |tag_name|
102
+ @tk.tag_ranges(tag_name).any? do |range|
103
+ if range.first.to_f <= region_start.to_f && range.last.to_f >= region_end.to_f
104
+ @tk.tag_cget(tag_name, option) == value
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def add_format(region_start, region_end, option, value)
111
+ @@tag_number = 0 unless defined?(@@tag_number)
112
+ tag = "tag#{@@tag_number += 1}"
113
+ @tk.tag_configure(tag, {option => value})
114
+ @tk.tag_add(tag, region_start, region_end)
115
+ tag
116
+ end
117
+
118
+ def remove_format(region_start, region_end, option, value)
119
+ partial_intersection_option_applied_tags = tag_names.select do |tag_name|
120
+ @tk.tag_ranges(tag_name).any? do |range|
121
+ if range.first.to_f.between?(region_start.to_f, region_end.to_f) or
122
+ range.last.to_f.between?(region_start.to_f, region_end.to_f) or
123
+ (range.first.to_f <= region_start.to_f && range.last.to_f >= region_end.to_f)
124
+ @tk.tag_cget(tag_name, option) == value
125
+ end
126
+ end
127
+ end
128
+
129
+ partial_intersection_option_applied_tags.each do |tag_name|
130
+ @tk.tag_remove(tag_name, region_start, region_end)
131
+ end
132
+
133
+ nil
134
+ end
135
+
136
+ # toggles option/value tag (removes if already applied)
137
+ def toggle_format(region_start, region_end, option, value)
138
+ if applied_format?(region_start, region_end, option, value)
139
+ remove_format(region_start, region_end, option, value)
140
+ else
141
+ add_format(region_start, region_end, option, value)
142
+ end
143
+ end
144
+
145
+ # def applied_font_format?(region_start, region_end, option, value)
146
+ # !applied_font_format_tags(region_start, region_end, option, value).empty?
147
+ # end
148
+ #
149
+ # def applied_font_format_tags(region_start, region_end, option, value)
150
+ # tag_names = @tk.tag_names - ['sel']
151
+ #
152
+ # tag_names.select do |tag_name|
153
+ # @tk.tag_ranges(tag_name).any? do |range|
154
+ # if range.first.to_f <= region_start.to_f && range.last.to_f >= region_end.to_f
155
+ # @tk.tag_cget(tag_name, option) == value
156
+ # end
157
+ # end
158
+ # end
159
+ # end
160
+ #
161
+ # def add_font_format(region_start, region_end, option, value)
162
+ # end
163
+ #
164
+ # def remove_font_format(region_start, region_end, option, value)
165
+ # end
166
+ #
167
+ ### toggles option/value tag (removes if already applied)
168
+ # def toggle_font_format(region_start, region_end, option, value)
169
+ # if applied_font_format?(region_start, region_end, option, value)
170
+ ### ensure removing from previous font combination (perhaps checking widget font too)
171
+ # remove_font_format(region_start, region_end, option, value)
172
+ # else
173
+ ### ensure adding to previous font combination (perhaps checking widget font too)
174
+ # add_font_format(region_start, region_end, option, value)
175
+ # end
176
+ # end
177
+
178
+ private
179
+
180
+ def initialize_defaults
181
+ super
182
+ self.padx = 5
183
+ self.pady = 5
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ module Glimmer
23
+ module Tk
24
+ module TextVariableOwner
25
+ def initialize_defaults
26
+ super
27
+ tk.textvariable = ::TkVariable.new
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2020-2021 Andy Maleh
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ module Glimmer
23
+ module Tk
24
+ module VariableOwner
25
+ def initialize_defaults
26
+ super
27
+ tk.variable = ::TkVariable.new
28
+ end
29
+ end
30
+ end
31
+ end
@@ -26,8 +26,8 @@ module Glimmer
26
26
  # Follows the Proxy Design Pattern
27
27
  class WidgetProxy
28
28
  class << self
29
- def create(keyword, parent, args)
30
- widget_proxy_class(keyword).new(keyword, parent, args)
29
+ def create(keyword, parent, args, &block)
30
+ widget_proxy_class(keyword).new(keyword, parent, args, &block)
31
31
  end
32
32
 
33
33
  def widget_proxy_class(keyword)
@@ -57,45 +57,35 @@ module Glimmer
57
57
  Glimmer::Config.logger.debug e.full_message
58
58
  end
59
59
  end
60
- tk_widget_class
60
+ tk_widget_class if tk_widget_class.respond_to?(:new)
61
61
  end
62
62
  end
63
63
 
64
- attr_reader :parent_proxy, :tk, :args, :keyword
64
+ attr_reader :parent_proxy, :tk, :args, :keyword, :children
65
65
 
66
- DEFAULT_INITIALIZERS = {
67
- 'checkbutton' => lambda do |tk|
68
- tk.variable = ::TkVariable.new
69
- end,
70
- 'combobox' => lambda do |tk|
71
- tk.textvariable = ::TkVariable.new
72
- end,
73
- 'label' => lambda do |tk|
74
- tk.textvariable = ::TkVariable.new
75
- end,
76
- 'entry' => lambda do |tk|
77
- tk.textvariable = ::TkVariable.new
78
- end,
79
- }
80
-
81
66
  # Initializes a new Tk Widget
82
67
  #
83
68
  # Styles is a comma separate list of symbols representing Tk styles in lower case
84
- def initialize(underscored_widget_name, parent_proxy, args)
69
+ def initialize(underscored_widget_name, parent_proxy, args, &block)
85
70
  @parent_proxy = parent_proxy
86
71
  @args = args
87
72
  @keyword = underscored_widget_name
73
+ @block = block
88
74
  tk_widget_class = self.class.tk_widget_class_for(underscored_widget_name)
89
75
  @tk = tk_widget_class.new(@parent_proxy.tk, *args)
90
76
  # a common widget initializer
91
- @tk.grid unless @tk.is_a?(::Tk::Toplevel)
92
- DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@tk)
93
77
  @parent_proxy.post_initialize_child(self)
78
+ initialize_defaults
79
+ post_add_content if @block.nil?
80
+ end
81
+
82
+ def children
83
+ @children ||= []
94
84
  end
95
85
 
96
86
  # Subclasses may override to perform post initialization work on an added child
97
87
  def post_initialize_child(child)
98
- # No Op by default
88
+ children << child
99
89
  end
100
90
 
101
91
  # Subclasses may override to perform post add_content work
@@ -154,41 +144,55 @@ module Glimmer
154
144
  tk_widget_has_attribute_getter_setter?(attribute) or
155
145
  has_state?(attribute) or
156
146
  has_attributes_attribute?(attribute) or
157
- respond_to?(attribute_setter(attribute), args)
147
+ respond_to?(attribute_setter(attribute), args) or
148
+ respond_to?(attribute_setter(attribute), *args, super_only: true) or
149
+ respond_to?(attribute, *args, super_only: true)
158
150
  end
159
151
 
160
152
  def set_attribute(attribute, *args)
161
- widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]
162
- if widget_custom_attribute
163
- widget_custom_attribute[:setter][:invoker].call(@tk, args)
164
- elsif tk_widget_has_attribute_setter?(attribute)
165
- unless args.size == 1 && @tk.send(attribute) == args.first
166
- if args.size == 1
167
- @tk.send(attribute_setter(attribute), *args)
153
+ begin
154
+ widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]
155
+ if respond_to?(attribute_setter(attribute), super_only: true)
156
+ send(attribute_setter(attribute), *args)
157
+ elsif respond_to?(attribute, super_only: true) && self.class.instance_method(attribute).parameters.size > 0
158
+ send(attribute, *args)
159
+ elsif widget_custom_attribute
160
+ widget_custom_attribute[:setter][:invoker].call(@tk, args)
161
+ elsif tk_widget_has_attribute_setter?(attribute)
162
+ unless args.size == 1 && @tk.send(attribute) == args.first
163
+ if args.size == 1
164
+ @tk.send(attribute_setter(attribute), *args)
165
+ else
166
+ @tk.send(attribute_setter(attribute), args)
167
+ end
168
+ end
169
+ elsif tk_widget_has_attribute_getter_setter?(attribute)
170
+ @tk.send(attribute, *args)
171
+ elsif has_state?(attribute)
172
+ attribute = attribute.sub(/=$/, '')
173
+ if !!args.first
174
+ @tk.tile_state(attribute)
168
175
  else
169
- @tk.send(attribute_setter(attribute), args)
176
+ @tk.tile_state("!#{attribute}")
170
177
  end
171
- end
172
- elsif tk_widget_has_attribute_getter_setter?(attribute)
173
- @tk.send(attribute, *args)
174
- elsif has_state?(attribute)
175
- attribute = attribute.sub(/=$/, '')
176
- if !!args.first
177
- @tk.tile_state(attribute)
178
+ elsif has_attributes_attribute?(attribute)
179
+ attribute = attribute.sub(/=$/, '')
180
+ @tk.attributes(attribute, args.first)
178
181
  else
179
- @tk.tile_state("!#{attribute}")
182
+ raise "#{self} cannot handle attribute #{attribute} with args #{args.inspect}"
180
183
  end
181
- elsif has_attributes_attribute?(attribute)
182
- attribute = attribute.sub(/=$/, '')
183
- @tk.attributes(attribute, args.first)
184
- else
185
- send(attribute_setter(attribute), args)
184
+ rescue => e
185
+ Glimmer::Config.logger.debug {"Failed to set attribute #{attribute} with args #{args.inspect}. Attempting to set through style instead..."}
186
+ Glimmer::Config.logger.debug {e.full_message}
187
+ apply_style(attribute => args.first)
186
188
  end
187
189
  end
188
190
 
189
191
  def get_attribute(attribute)
190
192
  widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute.to_s]
191
- if widget_custom_attribute
193
+ if respond_to?(attribute, super_only: true)
194
+ send(attribute)
195
+ elsif widget_custom_attribute
192
196
  widget_custom_attribute[:getter][:invoker].call(@tk, args)
193
197
  elsif tk_widget_has_attribute_getter_setter?(attribute)
194
198
  @tk.send(attribute)
@@ -207,7 +211,49 @@ module Glimmer
207
211
  "#{attribute}="
208
212
  end
209
213
 
214
+ def style=(styles)
215
+ styles.each do |attribute, value|
216
+ apply_style(attribute => value)
217
+ end
218
+ end
219
+
220
+ def grid(options = {})
221
+ options = options.stringify_keys
222
+ index_in_parent = @parent_proxy.children.index(self)
223
+ options['rowweight'] = options.delete('row_weight') if options.keys.include?('row_weight')
224
+ options['columnweight'] = options.delete('column_weight') if options.keys.include?('column_weight')
225
+ options['columnweight'] = options['rowweight'] = options.delete('weight') if options.keys.include?('weight')
226
+ options['rowminsize'] = options.delete('row_minsize') if options.keys.include?('row_minsize')
227
+ options['rowminsize'] = options.delete('minheight') if options.keys.include?('minheight')
228
+ options['rowminsize'] = options.delete('min_height') if options.keys.include?('min_height')
229
+ options['columnminsize'] = options.delete('column_minsize') if options.keys.include?('column_minsize')
230
+ options['columnminsize'] = options.delete('minwidth') if options.keys.include?('minwidth')
231
+ options['columnminsize'] = options.delete('min_width') if options.keys.include?('min_width')
232
+ options['columnminsize'] = options['rowminsize'] = options.delete('minsize') if options.keys.include?('minsize')
233
+ TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('rowweight')) if options.keys.include?('rowweight')
234
+ TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('rowminsize')) if options.keys.include?('rowminsize')
235
+ TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('columnweight')) if options.keys.include?('columnweight')
236
+ TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('columnminsize')) if options.keys.include?('columnminsize')
237
+ @tk.grid(options)
238
+ end
239
+
240
+ def font=(value)
241
+ @tk.font = value.is_a?(TkFont) ? value : TkFont.new(value)
242
+ rescue => e
243
+ Glimmer::Config.logger.debug {"Failed to set attribute #{attribute} with args #{args.inspect}. Attempting to set through style instead..."}
244
+ Glimmer::Config.logger.debug {e.full_message}
245
+ apply_style({"font" => value})
246
+ end
247
+
248
+ def apply_style(options)
249
+ @@style_number = 0 unless defined?(@@style_number)
250
+ style = "style#{@@style_number}.#{@tk.class.name.split('::').last}"
251
+ ::Tk::Tile::Style.configure(style, options)
252
+ @tk.style = style
253
+ end
254
+
210
255
  def widget_custom_attribute_mapping
256
+ # TODO consider extracting to modules/subclasses
211
257
  @widget_custom_attribute_mapping ||= {
212
258
  ::Tk::Tile::TButton => {
213
259
  'image' => {
@@ -221,10 +267,24 @@ module Glimmer
221
267
  setter: {name: 'image=', invoker: lambda { |widget, args| @tk.image = image_argument(args) }},
222
268
  },
223
269
  'variable' => {
224
- getter: {name: 'variable', invoker: lambda { |widget, args| @tk.variable&.value.to_i == 1 }},
270
+ getter: {name: 'variable', invoker: lambda { |widget, args| @tk.variable&.value.to_s == @tk.onvalue.to_s }},
225
271
  setter: {name: 'variable=', invoker: lambda { |widget, args| @tk.variable&.value = args.first.is_a?(Integer) ? args.first : (args.first ? 1 : 0) }},
226
272
  },
227
273
  },
274
+ ::Tk::Tile::TRadiobutton => {
275
+ 'image' => {
276
+ getter: {name: 'image', invoker: lambda { |widget, args| @tk.image }},
277
+ setter: {name: 'image=', invoker: lambda { |widget, args| @tk.image = image_argument(args) }},
278
+ },
279
+ 'text' => {
280
+ getter: {name: 'text', invoker: lambda { |widget, args| @tk.text }},
281
+ setter: {name: 'text=', invoker: lambda { |widget, args| @tk.value = @tk.text = args.first }},
282
+ },
283
+ 'variable' => {
284
+ getter: {name: 'variable', invoker: lambda { |widget, args| @tk.variable&.value == @tk.value }},
285
+ setter: {name: 'variable=', invoker: lambda { |widget, args| @tk.variable&.value = args.first ? @tk.value : @tk.variable&.value }},
286
+ },
287
+ },
228
288
  ::Tk::Tile::TCombobox => {
229
289
  'text' => {
230
290
  getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
@@ -244,18 +304,31 @@ module Glimmer
244
304
  ::Tk::Tile::TEntry => {
245
305
  'text' => {
246
306
  getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
247
- setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first unless @text_variable_edit }},
307
+ setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first }},
308
+ },
309
+ },
310
+ ::Tk::Tile::TSpinbox => {
311
+ 'text' => {
312
+ getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
313
+ setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first }},
314
+ },
315
+ },
316
+ ::Tk::Root => {
317
+ 'text' => {
318
+ getter: {name: 'text', invoker: lambda { |widget, args| @tk.title }},
319
+ setter: {name: 'text=', invoker: lambda { |widget, args| @tk.title = args.first }},
248
320
  },
249
321
  },
250
322
  }
251
323
  end
252
324
 
253
325
  def widget_attribute_listener_installers
326
+ # TODO consider extracting to modules/subclasses
254
327
  @tk_widget_attribute_listener_installers ||= {
255
328
  ::Tk::Tile::TCheckbutton => {
256
329
  'variable' => lambda do |observer|
257
330
  @tk.command {
258
- observer.call(@tk.variable.value.to_i == 1)
331
+ observer.call(@tk.variable.value.to_s == @tk.onvalue.to_s)
259
332
  }
260
333
  end,
261
334
  },
@@ -273,16 +346,37 @@ module Glimmer
273
346
  },
274
347
  ::Tk::Tile::TEntry => {
275
348
  'text' => lambda do |observer|
276
- tk.validate = 'key'
277
- tk.validatecommand { |new_tk_variable|
278
- @text_variable_edit = new_tk_variable.value != @tk.textvariable.value
279
- if @text_variable_edit
280
- observer.call(new_tk_variable.value)
281
- @text_variable_edit = nil
282
- true
283
- else
284
- false
285
- end
349
+ @tk.textvariable.trace('write') {
350
+ observer.call(@tk.textvariable.value)
351
+ }
352
+ end,
353
+ },
354
+ ::Tk::Tile::TSpinbox => {
355
+ 'text' => lambda do |observer|
356
+ @tk.command {
357
+ observer.call(@tk.textvariable&.value)
358
+ }
359
+ @tk.validate('key')
360
+ @tk.validatecommand { |validate_args|
361
+ observer.call(validate_args.value)
362
+ new_icursor = validate_args.index
363
+ new_icursor += validate_args.string.size if validate_args.action == 1
364
+ @tk.icursor = new_icursor
365
+ true
366
+ }
367
+ end,
368
+ },
369
+ ::Tk::Text => {
370
+ 'text' => lambda do |observer|
371
+ handle_listener('modified') do
372
+ observer.call(text)
373
+ end
374
+ end,
375
+ },
376
+ ::Tk::Tile::TRadiobutton => {
377
+ 'variable' => lambda do |observer|
378
+ @tk.command {
379
+ observer.call(@tk.variable.value == @tk.value)
286
380
  }
287
381
  end,
288
382
  },
@@ -341,10 +435,21 @@ module Glimmer
341
435
  super(method.to_sym, *args, &block)
342
436
  end
343
437
 
344
- def respond_to?(method, *args, &block)
345
- super ||
346
- tk.respond_to?(method, *args, &block)
438
+ def respond_to?(method, *args, super_only: false, &block)
439
+ super(method, true) ||
440
+ !super_only && tk.respond_to?(method, *args, &block)
441
+ end
442
+
443
+ private
444
+
445
+ def initialize_defaults
446
+ options = {}
447
+ options[:sticky] = 'nsew'
448
+ options[:column_weight] = 1 if @parent_proxy.children.count == 1
449
+ grid(options) unless @tk.is_a?(::Tk::Toplevel)
347
450
  end
348
451
  end
349
452
  end
350
453
  end
454
+
455
+ Dir[File.expand_path('./*_proxy.rb', __dir__)].each {|f| require f}
@@ -28,6 +28,7 @@ require 'puts_debuggerer' if ENV['pd'].to_s.downcase == 'true'
28
28
  # require 'super_module'
29
29
  require 'tk'
30
30
  require 'os'
31
+ require 'facets/hash/symbolize_keys'
31
32
 
32
33
  # Internal requires
33
34
  # require 'ext/glimmer/config'