glimmer-dsl-tk 0.0.30 → 0.0.31

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c90a3de5c636e2d9fcce122eaa07691e49842721d356a6266e75ff3f77b15ed
4
- data.tar.gz: 82927885f588122a63c984c6acbd13110bc93197a075e8d3ef522bce98162ac9
3
+ metadata.gz: 883bb9d265c58ea872a90069aba8e308ee4688653d2ca200fb5289976850dc1c
4
+ data.tar.gz: 34f92aa593f48fbe0edf1b469ebc5ec0b81e2789a8995d1b04cd77748c72c081
5
5
  SHA512:
6
- metadata.gz: ba0ba8c92a2294998b6b43ac7397a9f27d499becc7603d8e51823aac0a4f442152208ae316829c019ed5bdb3ee763c8165a7309c3789c3009328a64851aabb27
7
- data.tar.gz: b0a1bfe8894b410bbcf5781721fb3a044d0534b5f31260a128f9232db89d331ea7ec1843d288abc1ab16f17f046f3f869739d14c11bf74aa30bb7dbc59f9c551
6
+ metadata.gz: a8a0d78446483775e82da34e94ede3a1566b2e1201cd5c3bbbfaa1ed27f424bcb1d61826b7f600616550e999bcec117560d52742f3a4779d94dd8aa7adf18661
7
+ data.tar.gz: fbc6ad5515dc20099c7e1c1827738f7d2edc133575f030afa69c2256c3e2bc6981986e494ada3498eeda6e4809bc5409dd7a61cc91666898d0dd48d7f1805277
data/CHANGELOG.md CHANGED
@@ -1,10 +1,17 @@
1
1
  # Change Log
2
2
 
3
- ## 0.0.30
3
+ ## 0.0.31
4
4
 
5
5
  - Improve Hello, Text! (toolbar buttons: justify left, justify center, justify right)
6
- - Fixed Hello, Built-in Dialog! Font Dialog issue
6
+ - `on('destroy') {|widget| ...}` support in widgets to better track calls to "destroy" method and `'<Destroy>'` binding event (as opposed to the unreliable tracking of '<Destroy>' alone)
7
+ - Support observing `text` general events (e.g. `'<KeyPress>'`) through `on(event) {}` (was not working before because it required applying a tag, a general `__all__` tag is applied automatically now on full range (`1.0` to `end`))
8
+ - Ensure unregistering observers (like data-binding observers) when destroying a widget
9
+ - Add `Glimmer::Tk::ToplevelProxy` widget proxy support similar to `Glimmer::Tk::RootProxy`
7
10
 
11
+ ## 0.0.30
12
+
13
+ - Improve Hello, Text! (toolbar buttons: find dialog)
14
+ - Fixed Hello, Built-in Dialog! Font Dialog issue
8
15
  ## 0.0.29
9
16
 
10
17
  - Hello, Built-in Dialog! (demonstrating all built-in dialogs like get_open_file and choose_color)
data/README.md CHANGED
@@ -120,8 +120,9 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
120
120
  - [Applications](#applications)
121
121
  - [Glimmer Tk Calculator](#glimmer-tk-calculator)
122
122
  - [Y3network Ruby UI](#y3network-ruby-ui)
123
- - [Cryptopunks GUI](#cryptopunks-gui)
123
+ - [CryptoPunks GUI](#cryptopunks-gui)
124
124
  - [Process](#process)
125
+ - [Resources](#resources)
125
126
  - [Help](#help)
126
127
  - [Issues](#issues)
127
128
  - [Chat](#chat)
@@ -1868,6 +1869,8 @@ Glimmer app:
1868
1869
 
1869
1870
  ### Hello, Text!
1870
1871
 
1872
+ You may use the META+F shortcut to bring up the Find Dialog.
1873
+
1871
1874
  Icons used in this sample were made by <a href="https://www.flaticon.com/authors/freepik" title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" title="Flaticon"> www.flaticon.com</a>
1872
1875
 
1873
1876
  Glimmer code (from [samples/hello/hello_text.rb](samples/hello/hello_text.rb)):
@@ -2150,6 +2153,8 @@ Glimmer app:
2150
2153
 
2151
2154
  ![glimmer dsl tk screenshot sample hello text](images/glimmer-dsl-tk-screenshot-sample-hello-text.png)
2152
2155
 
2156
+ ![glimmer dsl tk screenshot sample hello text find dialog](images/glimmer-dsl-tk-screenshot-sample-hello-text-find-dialog.png)
2157
+
2153
2158
  ### Hello, Spinbox!
2154
2159
 
2155
2160
  Glimmer code (from [samples/hello/hello_spinbox.rb](samples/hello/hello_spinbox.rb)):
@@ -2624,31 +2629,34 @@ Glimmer app:
2624
2629
 
2625
2630
  https://github.com/ancorgs/glimmer-tk-calculator
2626
2631
 
2627
- https://raw.githubusercontent.com/ancorgs/glimmer-tk-calculator/master/screenshot.png
2632
+ ![Glimmer Tk Calculator Screenshot](https://raw.githubusercontent.com/ancorgs/glimmer-tk-calculator/master/screenshot.png)
2628
2633
 
2629
2634
  ### Y3network Ruby UI
2630
2635
 
2631
2636
  https://github.com/ancorgs/y3network-ruby-ui
2632
2637
 
2633
- ### Cryptopunks GUI
2638
+ ### CryptoPunks GUI
2634
2639
 
2635
- This is a Graphical User Interface for the famous [Cryptopunks Ruby gem](https://github.com/cryptopunksnotdead/cryptopunks/tree/master/cryptopunks).
2640
+ This is a Graphical User Interface for the famous [cryptopunks Ruby gem](https://github.com/cryptopunksnotdead/cryptopunks/tree/master/cryptopunks).
2636
2641
 
2637
2642
  https://github.com/AndyObtiva/cryptopunks-gui
2638
2643
 
2639
- ![Cryptopunks GUI Screenshot](https://raw.githubusercontent.com/AndyObtiva/cryptopunks-gui/master/screenshots/cryptopunks-gui-screenshot.png)
2644
+ ![CryptoPunks GUI Screenshot](https://raw.githubusercontent.com/AndyObtiva/cryptopunks-gui/master/screenshots/cryptopunks-gui-screenshot.png)
2640
2645
 
2641
2646
  ## Process
2642
2647
 
2643
2648
  [Glimmer Process](https://github.com/AndyObtiva/glimmer/blob/master/PROCESS.md)
2644
2649
 
2650
+ ## Resources
2651
+
2652
+ - [Tk Tutorial](https://tkdocs.com/tutorial/index.html)
2653
+ - [Code Master Blog](https://andymaleh.blogspot.com/search/label/Tk)
2654
+
2645
2655
  ## Help
2646
2656
 
2647
2657
  ### Issues
2648
2658
 
2649
- You may submit [issues](https://github.com/AndyObtiva/glimmer/issues) on [GitHub](https://github.com/AndyObtiva/glimmer/issues).
2650
-
2651
- [Click here to submit an issue.](https://github.com/AndyObtiva/glimmer/issues)
2659
+ If you encounter [issues](https://github.com/AndyObtiva/glimmer-dsl-tk/issues) that are not reported, discover missing features that are not mentioned in [TODO.md](TODO.md), or think up better ways to use [Tk](https://www.tcl.tk/) than what is possible with [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk), you may submit an [issue](https://github.com/AndyObtiva/glimmer-dsl-tk/issues/new) or [pull request](https://github.com/AndyObtiva/glimmer-dsl-tk/compare) on [GitHub](https://github.com).
2652
2660
 
2653
2661
  ### Chat
2654
2662
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.30
1
+ 0.0.31
Binary file
@@ -0,0 +1,39 @@
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/data_binding/observer'
23
+
24
+ module Glimmer
25
+ module DataBinding
26
+ module Tk
27
+ # Decorator for Observer that ensures it is only called once
28
+ # (subsequent invocations of call method do nothing)
29
+ module OneTimeObserver
30
+ def call(value)
31
+ unless @called
32
+ super
33
+ @called = true
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -38,12 +38,13 @@ module Glimmer
38
38
  end
39
39
 
40
40
  def interpret(parent, keyword, *args, &block)
41
- parent.class
42
41
  model_binding = args[0]
43
42
  widget_binding_parameters = [parent, keyword]
44
43
  widget_binding = DataBinding::Tk::WidgetBinding.new(*widget_binding_parameters)
45
44
  #TODO make this options observer dependent and all similar observers in widget specific data binding handlers
46
- widget_binding.observe(model_binding)
45
+ registration = widget_binding.observe(model_binding)
46
+ parent.on('destroy') { registration.deregister }
47
+
47
48
  # TODO simplify this logic and put it where it belongs
48
49
  parent.add_observer(model_binding, keyword) if parent.respond_to?(:add_observer, [model_binding, keyword])
49
50
  widget_binding.call(model_binding.evaluate_property)
@@ -33,11 +33,15 @@ module Glimmer
33
33
 
34
34
  def can_interpret?(parent, keyword, *args, &block)
35
35
  !EXCLUDED_KEYWORDS.include?(keyword) and
36
- parent.respond_to?(:tk) and
37
36
  Glimmer::Tk::WidgetProxy.widget_exists?(keyword)
37
+ (parent.respond_to?(:tk) or args.first.respond_to?(:tk))
38
38
  end
39
39
 
40
40
  def interpret(parent, keyword, *args, &block)
41
+ if keyword == 'toplevel' && args.first.respond_to?(:tk)
42
+ parent = args.first
43
+ args[0] = args.first.tk
44
+ end
41
45
  Glimmer::Tk::WidgetProxy.create(keyword, parent, args, &block)
42
46
  end
43
47
 
@@ -19,18 +19,14 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- require 'glimmer/tk/widget_proxy'
22
+ require 'glimmer/tk/toplevel_proxy'
23
23
 
24
24
  module Glimmer
25
25
  module Tk
26
26
  # Proxy for TkRoot
27
27
  #
28
28
  # Follows the Proxy Design Pattern
29
- class RootProxy < WidgetProxy
30
- REGEX_GEOMETRY = /[x+-]/
31
- DEFAULT_WIDTH = 190
32
- DEFAULT_HEIGHT = 95
33
-
29
+ class RootProxy < ToplevelProxy
34
30
  def initialize(*args, &block)
35
31
  @tk = ::TkRoot.new
36
32
  @tk.minsize = DEFAULT_WIDTH, DEFAULT_HEIGHT
@@ -50,10 +46,6 @@ module Glimmer
50
46
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::RootExpression.new, keyword, *args, &block)
51
47
  end
52
48
 
53
- def has_attribute?(attribute, *args)
54
- %w[width height x y].include?(attribute.to_s) || super
55
- end
56
-
57
49
  def set_attribute(attribute, *args)
58
50
  case attribute.to_s
59
51
  when 'iconphoto'
@@ -70,45 +62,8 @@ module Glimmer
70
62
  end
71
63
  end
72
64
 
73
- def width
74
- geometry.split(REGEX_GEOMETRY)[0].to_i
75
- end
76
-
77
- def height
78
- geometry.split(REGEX_GEOMETRY)[1].to_i
79
- end
80
-
81
- def x
82
- sign_number(x_sign, geometry.split(REGEX_GEOMETRY)[2].to_i)
83
- end
84
-
85
- def y
86
- sign_number(y_sign, geometry.split(REGEX_GEOMETRY)[3].to_i)
87
- end
88
-
89
- def width=(value)
90
- @width = value.to_i
91
- self.geometry = "#{value.to_i}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{y_sign}#{abs_y}"
92
- end
93
-
94
- def height=(value)
95
- @height = value.to_i
96
- self.geometry = "#{@width || DEFAULT_WIDTH}x#{value.to_i}#{x_sign}#{abs_x}#{y_sign}#{abs_y}"
97
- end
98
-
99
- def x=(value)
100
- self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{value.to_i > 0 ? '+' : '-'}#{value.to_i.abs}#{y_sign}#{abs_y}"
101
- end
102
-
103
- def y=(value)
104
- self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{value.to_i > 0 ? '+' : '-'}#{value.to_i.abs}"
105
- end
106
-
107
65
  def handle_listener(listener_name, &listener)
108
66
  case listener_name.to_s.upcase
109
- when 'WM_DELETE_WINDOW', 'DELETE_WINDOW'
110
- listener_name = 'WM_DELETE_WINDOW'
111
- @tk.protocol(listener_name, &listener)
112
67
  when 'WM_OPEN_WINDOW', 'OPEN_WINDOW'
113
68
  @on_open_window_procs ||= []
114
69
  @on_open_window_procs << listener
@@ -128,36 +83,6 @@ module Glimmer
128
83
  end
129
84
  ::Tk.mainloop
130
85
  end
131
-
132
- private
133
-
134
- def sign_number(sign, number)
135
- "#{sign}1".to_i * number
136
- end
137
-
138
- def abs_x
139
- geometry.split(REGEX_GEOMETRY)[2].to_i
140
- end
141
-
142
- def abs_y
143
- geometry.split(REGEX_GEOMETRY)[3].to_i
144
- end
145
-
146
- def x_sign
147
- geometry_signs[0]
148
- end
149
-
150
- def y_sign
151
- geometry_signs[1]
152
- end
153
-
154
- def geometry_signs
155
- geometry.chars.select {|char| char.match(/[+-]/)}
156
- end
157
-
158
- def initialize_defaults
159
- self.background = '#ececec' if OS.mac?
160
- end
161
86
  end
162
87
  end
163
88
  end
@@ -28,8 +28,7 @@ module Glimmer
28
28
  # Follows the Proxy Design Pattern
29
29
  class TextProxy < WidgetProxy
30
30
  def handle_listener(listener_name, &listener)
31
- listener_name = listener_name.to_s.downcase
32
- case listener_name
31
+ case listener_name.to_s.downcase
33
32
  when '<<modified>>', '<modified>', 'modified'
34
33
  modified_listener = Proc.new do |*args|
35
34
  listener.call(*args)
@@ -38,8 +37,20 @@ module Glimmer
38
37
  bind('<Modified>', modified_listener)
39
38
  when '<<selection>>', '<selection>', 'selection'
40
39
  bind('<Selection>', listener)
41
- else
40
+ when 'destroy'
42
41
  super
42
+ else
43
+ @tk.tag_add('__all__', '1.0', 'end') unless @tk.tag_names.include?('__all__')
44
+ # TODO make listener pass an event that has a modifiers attribute for easy representation of :shift, :meta, :control, etc... while a letter button is pressed
45
+ begin
46
+ @tk.tag_bind('__all__', listener_name, &listener)
47
+ rescue => e
48
+ Glimmer::Config.logger.debug {"Unable to bind to #{listener_name} .. attempting to surround with <>"}
49
+ Glimmer::Config.logger.debug {e.full_message}
50
+ listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
51
+ listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
52
+ @tk.tag_bind('__all__', listener_name, &listener)
53
+ end
43
54
  end
44
55
  end
45
56
 
@@ -0,0 +1,119 @@
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 TkToplevel
27
+ #
28
+ # Follows the Proxy Design Pattern
29
+ class ToplevelProxy < WidgetProxy
30
+ REGEX_GEOMETRY = /[x+-]/
31
+ DEFAULT_WIDTH = 190
32
+ DEFAULT_HEIGHT = 95
33
+
34
+ attr_reader :tk
35
+
36
+ def has_attribute?(attribute, *args)
37
+ %w[width height x y].include?(attribute.to_s) || super
38
+ end
39
+
40
+ def width
41
+ geometry.split(REGEX_GEOMETRY)[0].to_i
42
+ end
43
+
44
+ def height
45
+ geometry.split(REGEX_GEOMETRY)[1].to_i
46
+ end
47
+
48
+ def x
49
+ sign_number(x_sign, geometry.split(REGEX_GEOMETRY)[2].to_i)
50
+ end
51
+
52
+ def y
53
+ sign_number(y_sign, geometry.split(REGEX_GEOMETRY)[3].to_i)
54
+ end
55
+
56
+ def width=(value)
57
+ @width = value.to_i
58
+ self.geometry = "#{value.to_i}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{y_sign}#{abs_y}"
59
+ end
60
+
61
+ def height=(value)
62
+ @height = value.to_i
63
+ self.geometry = "#{@width || DEFAULT_WIDTH}x#{value.to_i}#{x_sign}#{abs_x}#{y_sign}#{abs_y}"
64
+ end
65
+
66
+ def x=(value)
67
+ self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{value.to_i > 0 ? '+' : '-'}#{value.to_i.abs}#{y_sign}#{abs_y}"
68
+ end
69
+
70
+ def y=(value)
71
+ self.geometry = "#{@width || DEFAULT_WIDTH}x#{@height || DEFAULT_HEIGHT}#{x_sign}#{abs_x}#{value.to_i > 0 ? '+' : '-'}#{value.to_i.abs}"
72
+ end
73
+
74
+ def handle_listener(listener_name, &listener)
75
+ case listener_name.to_s.upcase
76
+ when 'WM_DELETE_WINDOW', 'DELETE_WINDOW'
77
+ listener_name = 'WM_DELETE_WINDOW'
78
+ @tk.protocol(listener_name, &listener)
79
+ else
80
+ super
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def sign_number(sign, number)
87
+ "#{sign}1".to_i * number
88
+ end
89
+
90
+ def abs_x
91
+ geometry.split(REGEX_GEOMETRY)[2].to_i
92
+ end
93
+
94
+ def abs_y
95
+ geometry.split(REGEX_GEOMETRY)[3].to_i
96
+ end
97
+
98
+ def x_sign
99
+ geometry_signs[0]
100
+ end
101
+
102
+ def y_sign
103
+ geometry_signs[1]
104
+ end
105
+
106
+ def geometry_signs
107
+ geometry.chars.select {|char| char.match(/[+-]/)}
108
+ end
109
+
110
+ def initialize_defaults
111
+ self.background = '#ececec' if OS.mac?
112
+ on('DELETE_WINDOW') do
113
+ grab_release
114
+ destroy
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -19,6 +19,8 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
+ require 'glimmer/data_binding/tk/one_time_observer'
23
+
22
24
  module Glimmer
23
25
  module Tk
24
26
  # Proxy for Tk Widget objects
@@ -83,6 +85,27 @@ module Glimmer
83
85
  post_add_content if @block.nil?
84
86
  end
85
87
 
88
+ def root_parent_proxy
89
+ current = self
90
+ current = current.parent_proxy while current.parent_proxy
91
+ current
92
+ end
93
+
94
+ def toplevel_parent_proxy
95
+ ancestor_proxies.find {|widget_proxy| widget_proxy.is_a?(ToplevelProxy)}
96
+ end
97
+
98
+ # returns list of ancestors ordered from direct parent to root parent
99
+ def ancestor_proxies
100
+ ancestors = []
101
+ current = self
102
+ while current.parent_proxy
103
+ ancestors << current.parent_proxy
104
+ current = current.parent_proxy
105
+ end
106
+ ancestors
107
+ end
108
+
86
109
  def children
87
110
  @children ||= []
88
111
  end
@@ -227,7 +250,7 @@ module Glimmer
227
250
 
228
251
  def grid(options = {})
229
252
  options = options.stringify_keys
230
- index_in_parent = @parent_proxy.children.index(self)
253
+ index_in_parent = @parent_proxy&.children&.index(self)
231
254
  options['rowspan'] = options.delete('row_span') if options.keys.include?('row_span')
232
255
  options['columnspan'] = options.delete('column_span') if options.keys.include?('column_span')
233
256
  options['rowweight'] = options.delete('row_weight') if options.keys.include?('row_weight')
@@ -240,10 +263,12 @@ module Glimmer
240
263
  options['columnminsize'] = options.delete('minwidth') if options.keys.include?('minwidth')
241
264
  options['columnminsize'] = options.delete('min_width') if options.keys.include?('min_width')
242
265
  options['columnminsize'] = options['rowminsize'] = options.delete('minsize') if options.keys.include?('minsize')
243
- TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('rowweight')) if options.keys.include?('rowweight')
244
- TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('rowminsize')) if options.keys.include?('rowminsize')
245
- TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('columnweight')) if options.keys.include?('columnweight')
246
- TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('columnminsize')) if options.keys.include?('columnminsize')
266
+ if index_in_parent
267
+ TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('rowweight')) if options.keys.include?('rowweight')
268
+ TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('rowminsize')) if options.keys.include?('rowminsize')
269
+ TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('columnweight')) if options.keys.include?('columnweight')
270
+ TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('columnminsize')) if options.keys.include?('columnminsize')
271
+ end
247
272
  @tk.grid(options)
248
273
  end
249
274
 
@@ -259,6 +284,11 @@ module Glimmer
259
284
  apply_style({"font" => value})
260
285
  end
261
286
 
287
+ def destroy
288
+ @tk.destroy
289
+ @on_destroy_procs&.each {|p| p.call(@tk)}
290
+ end
291
+
262
292
  def apply_style(options)
263
293
  @@style_number = 0 unless defined?(@@style_number)
264
294
  style = "style#{@@style_number += 1}.#{@tk.class.name.split('::').last}"
@@ -421,17 +451,31 @@ module Glimmer
421
451
 
422
452
  def handle_listener(listener_name, &listener)
423
453
  listener_name = listener_name.to_s
424
- begin
425
- @tk.bind(listener_name, &listener)
426
- rescue => e
427
- Glimmer::Config.logger.debug {"Unable to bind to #{listener_name} .. attempting to surround with <>"}
428
- Glimmer::Config.logger.debug {e.full_message}
429
- listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
430
- listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
431
- @tk.bind(listener_name, &listener)
454
+ if listener_name == 'destroy'
455
+ # 'destroy' is a more reliable alternative listener binding to '<Destroy>'
456
+ @on_destroy_procs ||= []
457
+ listener.singleton_class.include(Glimmer::DataBinding::Tk::OneTimeObserver) unless listener.is_a?(Glimmer::DataBinding::Tk::OneTimeObserver)
458
+ @on_destroy_procs << listener
459
+ @tk.bind('<Destroy>', listener)
460
+ parent_proxy.handle_listener(listener_name, &listener) if parent_proxy
461
+ # TODO return a listener registration object that has a deregister method
462
+ else
463
+ begin
464
+ @tk.bind(listener_name, &listener)
465
+ rescue => e
466
+ Glimmer::Config.logger.debug {"Unable to bind to #{listener_name} .. attempting to surround with <>"}
467
+ Glimmer::Config.logger.debug {e.full_message}
468
+ listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
469
+ listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
470
+ @tk.bind(listener_name, &listener)
471
+ end
432
472
  end
433
473
  end
434
474
 
475
+ def on(listener_name, &listener)
476
+ handle_listener(listener_name, &listener)
477
+ end
478
+
435
479
  def content(&block)
436
480
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::WidgetExpression.new, keyword, *args, &block)
437
481
  end
@@ -64,7 +64,7 @@ class HelloText
64
64
  MULTI_LINE_STRING
65
65
  end
66
66
 
67
- attr_accessor :document
67
+ attr_accessor :document, :find_text
68
68
 
69
69
  attr_accessor :foreground
70
70
 
@@ -90,8 +90,16 @@ class HelloText
90
90
  [FONT_SIZE_PROMPT] + (9..64).to_a.map(&:to_s)
91
91
  end
92
92
 
93
+ def find
94
+ text_index = @text.search(/#{find_text}/i, @text.tag_ranges('sel')&.first&.last || @text.index('insert'))
95
+ unless text_index.to_s.empty?
96
+ @text.tag_remove('sel', '1.0', 'end')
97
+ @text.tag_add('sel', text_index, "#{text_index} + #{find_text.size} chars")
98
+ end
99
+ end
100
+
93
101
  def launch
94
- root {
102
+ root { |r|
95
103
  title 'Hello, Text!'
96
104
  width 1280
97
105
  height 800
@@ -272,6 +280,49 @@ class HelloText
272
280
  wrap 'word'
273
281
  undo true
274
282
  value <=> [self, :document]
283
+
284
+ on('KeyPress') do |event|
285
+ if event.state == 8 && event.char == 'f'
286
+ toplevel(r) { |tl|
287
+ title 'Find'
288
+
289
+ label {
290
+ text 'Text:'
291
+ }
292
+ entry { |e|
293
+ focus true
294
+ text <=> [
295
+ self,
296
+ :find_text,
297
+ after_write: lambda do
298
+ text_index = @text.search(/#{find_text}/i, 'insert')
299
+ unless text_index.to_s.empty?
300
+ @text.tag_remove('sel', '1.0', 'end')
301
+ @text.tag_add('sel', text_index, "#{text_index} + #{find_text.size} chars")
302
+ end
303
+ end
304
+ ]
305
+
306
+ on('KeyPress') do |event|
307
+ if event.keysym == 'Return'
308
+ find
309
+ elsif event.keysym == 'Escape'
310
+ tl.grab_release
311
+ tl.destroy
312
+ end
313
+ end
314
+ }
315
+ button {
316
+ text 'Find'
317
+ default 'active'
318
+
319
+ on('command') do
320
+ find
321
+ end
322
+ }
323
+ }
324
+ end
325
+ end
275
326
  }
276
327
  }.open
277
328
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-tk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.30
4
+ version: 0.0.31
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-23 00:00:00.000000000 Z
11
+ date: 2021-10-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -211,6 +211,7 @@ files:
211
211
  - icons/glimmer.png
212
212
  - lib/glimmer-dsl-tk.rb
213
213
  - lib/glimmer/data_binding/tk/list_selection_binding.rb
214
+ - lib/glimmer/data_binding/tk/one_time_observer.rb
214
215
  - lib/glimmer/data_binding/tk/widget_binding.rb
215
216
  - lib/glimmer/dsl/tk/attribute_expression.rb
216
217
  - lib/glimmer/dsl/tk/bind_expression.rb
@@ -240,6 +241,7 @@ files:
240
241
  - lib/glimmer/tk/spinbox_proxy.rb
241
242
  - lib/glimmer/tk/text_proxy.rb
242
243
  - lib/glimmer/tk/text_variable_owner.rb
244
+ - lib/glimmer/tk/toplevel_proxy.rb
243
245
  - lib/glimmer/tk/treeview_proxy.rb
244
246
  - lib/glimmer/tk/variable_owner.rb
245
247
  - lib/glimmer/tk/widget_proxy.rb