glimmer-dsl-tk 0.0.30 → 0.0.31

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.
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