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 +4 -4
- data/CHANGELOG.md +9 -2
- data/README.md +16 -8
- data/VERSION +1 -1
- data/glimmer-dsl-tk.gemspec +0 -0
- data/lib/glimmer/data_binding/tk/one_time_observer.rb +39 -0
- data/lib/glimmer/dsl/tk/data_binding_expression.rb +3 -2
- data/lib/glimmer/dsl/tk/widget_expression.rb +5 -1
- data/lib/glimmer/tk/root_proxy.rb +2 -77
- data/lib/glimmer/tk/text_proxy.rb +14 -3
- data/lib/glimmer/tk/toplevel_proxy.rb +119 -0
- data/lib/glimmer/tk/widget_proxy.rb +57 -13
- data/samples/hello/hello_text.rb +53 -2
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 883bb9d265c58ea872a90069aba8e308ee4688653d2ca200fb5289976850dc1c
|
4
|
+
data.tar.gz: 34f92aa593f48fbe0edf1b469ebc5ec0b81e2789a8995d1b04cd77748c72c081
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
3
|
+
## 0.0.31
|
4
4
|
|
5
5
|
- Improve Hello, Text! (toolbar buttons: justify left, justify center, justify right)
|
6
|
-
-
|
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
|
-
- [
|
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
|

|
2152
2155
|
|
2156
|
+

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

|
2628
2633
|
|
2629
2634
|
### Y3network Ruby UI
|
2630
2635
|
|
2631
2636
|
https://github.com/ancorgs/y3network-ruby-ui
|
2632
2637
|
|
2633
|
-
###
|
2638
|
+
### CryptoPunks GUI
|
2634
2639
|
|
2635
|
-
This is a Graphical User Interface for the famous [
|
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
|
-

|
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
|
-
|
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.
|
1
|
+
0.0.31
|
data/glimmer-dsl-tk.gemspec
CHANGED
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/
|
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 <
|
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
|
-
|
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
|
-
|
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
|
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
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
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
|
-
|
425
|
-
|
426
|
-
|
427
|
-
Glimmer::
|
428
|
-
|
429
|
-
|
430
|
-
listener_name
|
431
|
-
|
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
|
data/samples/hello/hello_text.rb
CHANGED
@@ -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.
|
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-
|
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
|