glimmer-dsl-tk 0.0.22 → 0.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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'