glimmer-dsl-tk 0.0.2 → 0.0.3
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/README.md +96 -8
- data/VERSION +1 -1
- data/lib/glimmer-dsl-tk.rb +2 -2
- data/lib/glimmer/data_binding/tk/widget_binding.rb +28 -0
- data/lib/glimmer/dsl/tk/bind_expression.rb +36 -0
- data/lib/glimmer/dsl/tk/block_attribute_expression.rb +41 -0
- data/lib/glimmer/dsl/tk/data_binding_expression.rb +32 -0
- data/lib/glimmer/dsl/tk/dsl.rb +2 -0
- data/lib/glimmer/dsl/tk/widget_expression.rb +2 -1
- data/lib/glimmer/tk/button_proxy.rb +35 -0
- data/lib/glimmer/tk/notebook_proxy.rb +1 -1
- data/lib/glimmer/tk/root_proxy.rb +2 -2
- data/lib/glimmer/tk/widget_proxy.rb +61 -18
- data/samples/hello/hello_combo.rb +40 -0
- metadata +65 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f57063e358754b89fbd0a57cb118fb9764595a8965eba5884aeb2988ab2d6b1
|
4
|
+
data.tar.gz: f55e3fc96a9388dd218d7c674cdf1585831c44a3f6412741e0e65f53185e2d98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 272ea64f1a285ebcef28edb4bc2092f1c8ac78bf9ea36e086f1555ba47a454cb09b8c698e06d5ed0aa76abab1fb7946535bae139e9d444663de8185483bba7f4
|
7
|
+
data.tar.gz: e6fa9a29aa2b6a7c096007489a0b0e07d0658f6c79ef836a4cbd4d2fc1300330ef19b97bb6ea62e5d7cac9e00f5a2fca32ee745b167cc8f0d826cacd98a13b1c
|
data/README.md
CHANGED
@@ -1,19 +1,24 @@
|
|
1
|
-
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Tk 0.0.
|
1
|
+
# [<img src="https://raw.githubusercontent.com/AndyObtiva/glimmer/master/images/glimmer-logo-hi-res.png" height=85 />](https://github.com/AndyObtiva/glimmer) Glimmer DSL for Tk 0.0.3 (Desktop GUI)
|
2
2
|
[](http://badge.fury.io/rb/glimmer-dsl-tk)
|
3
|
+
[](https://codeclimate.com/github/AndyObtiva/glimmer-dsl-tk/maintainability)
|
3
4
|
[](https://gitter.im/AndyObtiva/glimmer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
4
5
|
|
5
6
|
[Glimmer](https://github.com/AndyObtiva/glimmer) DSL for [Tk](https://www.tcl.tk/) enables desktop development with [Glimmer](https://github.com/AndyObtiva/glimmer).
|
6
7
|
|
7
8
|
[Tcl/Tk](https://www.tcl.tk/) has evolved into a practical desktop GUI toolkit due to gaining true native widgets on Mac, Windows, and Linux in [Tk version 8.5](https://www.tcl.tk/software/tcltk/8.5.html#:~:text=Highlights%20of%20Tk%208.5&text=Font%20rendering%3A%20Now%20uses%20anti,and%20window%20layout%2C%20and%20more.).
|
8
9
|
|
9
|
-
Additionally, Ruby 3.0 supports truly parallel multi-threading, making both [MRI](https://github.com/ruby/ruby) and [Tk](https://www.tcl.tk/) finally viable for support in [Glimmer](https://github.com/AndyObtiva/glimmer) (Ruby Desktop Development GUI Library).
|
10
|
+
Additionally, [Ruby](https://www.ruby-lang.org/en/) 3.0 Ractor (formerly known as [Guilds](https://olivierlacan.com/posts/concurrency-in-ruby-3-with-guilds/)) supports truly parallel multi-threading, making both [MRI](https://github.com/ruby/ruby) and [Tk](https://www.tcl.tk/) finally viable for support in [Glimmer](https://github.com/AndyObtiva/glimmer) (Ruby Desktop Development GUI Library) as an alternative to [JRuby on SWT](https://github.com/AndyObtiva/glimmer-dsl-swt).
|
11
|
+
|
12
|
+
The trade-off is that while [SWT](https://www.eclipse.org/swt/) provides a plethora of high quality reusable widgets for the Enterprise (such as [Nebula](https://www.eclipse.org/nebula/)), [Tk](https://www.tcl.tk/) enables very fast app startup time via [MRI Ruby](https://www.ruby-lang.org/en/).
|
10
13
|
|
11
14
|
[Glimmer](https://github.com/AndyObtiva/glimmer) provides a DSL to enable more productive desktop development in Ruby with:
|
12
15
|
- Declarative DSL syntax that visually maps to the GUI widget hierarchy
|
13
16
|
- Convention over configuration via smart defaults and automation of low-level details
|
14
17
|
- Requiring the least amount of syntax possible to build GUI
|
18
|
+
- Bidirectional Data-Binding to declaratively wire and automatically synchronize GUI with Business Models
|
15
19
|
- Scaffolding for new custom widgets, apps, and gems
|
16
20
|
- Native-Executable packaging on Mac, Windows, and Linux
|
21
|
+
- Custom Widget support
|
17
22
|
|
18
23
|
**Hello, World!**
|
19
24
|
|
@@ -30,7 +35,7 @@ root {
|
|
30
35
|
Run (with the [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed):
|
31
36
|
|
32
37
|
```
|
33
|
-
ruby -e "require '../samples/hello/hello_world.rb'"
|
38
|
+
ruby -r glimmer-dsl-tk -e "require '../samples/hello/hello_world.rb'"
|
34
39
|
```
|
35
40
|
|
36
41
|
Glimmer app:
|
@@ -38,7 +43,7 @@ Glimmer app:
|
|
38
43
|

|
39
44
|
|
40
45
|
Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
|
41
|
-
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (Desktop GUI
|
46
|
+
- [glimmer-dsl-swt](https://github.com/AndyObtiva/glimmer-dsl-swt): Glimmer DSL for SWT (JRuby Desktop GUI)
|
42
47
|
- [glimmer-dsl-opal](https://github.com/AndyObtiva/glimmer-dsl-opal): Glimmer DSL for Opal (Web GUI Adapter for Desktop Apps)
|
43
48
|
- [glimmer-dsl-xml](https://github.com/AndyObtiva/glimmer-dsl-xml): Glimmer DSL for XML (& HTML)
|
44
49
|
- [glimmer-dsl-css](https://github.com/AndyObtiva/glimmer-dsl-css): Glimmer DSL for CSS (Cascading Style Sheets)
|
@@ -61,6 +66,8 @@ Afterwards, if you open `irb`, you should be able to run `require 'tk'` successf
|
|
61
66
|
|
62
67
|
Run this command to install directly:
|
63
68
|
```
|
69
|
+
gem install logging
|
70
|
+
gem install super_module
|
64
71
|
gem install glimmer-dsl-tk
|
65
72
|
```
|
66
73
|
|
@@ -68,7 +75,9 @@ gem install glimmer-dsl-tk
|
|
68
75
|
|
69
76
|
Add the following to `Gemfile`:
|
70
77
|
```
|
71
|
-
gem '
|
78
|
+
gem 'logging'
|
79
|
+
gem 'super_module'
|
80
|
+
gem 'glimmer-dsl-tk', '~> 0.0.3'
|
72
81
|
```
|
73
82
|
|
74
83
|
And, then run:
|
@@ -99,7 +108,7 @@ The Glimmer GUI DSL provides a declarative syntax for [Tk](https://www.tcl.tk/)
|
|
99
108
|
The Glimmer GUI DSL follows these simple concepts in mapping from Tk syntax:
|
100
109
|
- **Widget Keyword**: Any Tk widget (e.g. `Tk::Tile::Label`) or toplevel window (e.g. `TkRoot`) may be declared by its lower-case underscored name without the namespace (e.g. `label` or `root`). This is called a keyword and is represented in the Glimmer GUI DSL by a Ruby method behind the scenes.
|
101
110
|
- **Args**: Any keyword method may optionally take arguments surrounded by parentheses (e.g. a `frame` nested under a `notebook` may receive tab options like `frame(text: 'Users')`, which gets used behind the scenes by Tk code such as `notebook.add tab, text: 'Users'`)
|
102
|
-
- **Content/Options Block**: Any keyword may optionally be followed by a Ruby curly-brace block
|
111
|
+
- **Content/Options Block**: Any keyword may optionally be followed by a Ruby curly-brace block containing nested widgets (content) and attributes (options). Attributes are simply Tk option keywords followed by arguments and no block (e.g. `title 'Hello, World!'` under a `root`)
|
103
112
|
|
104
113
|
Example of an app written in [Tk](https://www.tcl.tk/) imperative syntax:
|
105
114
|
|
@@ -144,6 +153,46 @@ root {
|
|
144
153
|
}.open
|
145
154
|
```
|
146
155
|
|
156
|
+
### Bidirectional Data-Binding
|
157
|
+
|
158
|
+
Glimmer supports bidirectional data-binding via the `bind` keyword, which takes a model and an attribute.
|
159
|
+
|
160
|
+
Example:
|
161
|
+
|
162
|
+
This assumes a `Person` model with a `country` attribute representing their current country and a `country_options` attribute representing available options for the country attribute.
|
163
|
+
|
164
|
+
```ruby
|
165
|
+
combobox { |proxy|
|
166
|
+
state 'readonly'
|
167
|
+
text bind(person, :country)
|
168
|
+
}
|
169
|
+
```
|
170
|
+
|
171
|
+
That binds the `text` selection of the `combobox` to the `country` property on the `person` model.
|
172
|
+
|
173
|
+
It automatically handles all the Tk plumbing behind the scenes, such as using `TkVariable` and setting `combobox` `values` from `person.country_options` by convention (attribute_name + "_options").
|
174
|
+
|
175
|
+
More details can be found in the [Hello, Combo!](#hello-combo) sample below.
|
176
|
+
|
177
|
+
### Command
|
178
|
+
|
179
|
+
Buttons can set a `command` option to trigger when the user clicks the button. This may be done with the `command` keyword, passing in a block directly (no need for `proc` as per Tk)
|
180
|
+
|
181
|
+
Example:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
button { |proxy|
|
185
|
+
text "Reset Selection"
|
186
|
+
command {
|
187
|
+
person.reset_country
|
188
|
+
}
|
189
|
+
}
|
190
|
+
```
|
191
|
+
|
192
|
+
This resets the person country.
|
193
|
+
|
194
|
+
More details can be found in the [Hello, Combo!](#hello-combo) sample below.
|
195
|
+
|
147
196
|
## Samples
|
148
197
|
|
149
198
|
### Hello, World!
|
@@ -151,6 +200,8 @@ root {
|
|
151
200
|
Glimmer code (from [samples/hello/hello_world.rb](samples/hello/hello_world.rb)):
|
152
201
|
|
153
202
|
```ruby
|
203
|
+
include Glimmer
|
204
|
+
|
154
205
|
root {
|
155
206
|
label {
|
156
207
|
text 'Hello, World!'
|
@@ -161,7 +212,7 @@ root {
|
|
161
212
|
Run (with the [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed):
|
162
213
|
|
163
214
|
```
|
164
|
-
ruby -
|
215
|
+
ruby -r glimmer-dsl-tk -e "require '../samples/hello/hello_world.rb'"
|
165
216
|
```
|
166
217
|
|
167
218
|
Glimmer app:
|
@@ -173,6 +224,8 @@ Glimmer app:
|
|
173
224
|
Glimmer code (from [samples/hello/hello_tab.rb](samples/hello/hello_tab.rb)):
|
174
225
|
|
175
226
|
```ruby
|
227
|
+
include Glimmer
|
228
|
+
|
176
229
|
root {
|
177
230
|
title 'Hello, Tab!'
|
178
231
|
|
@@ -195,7 +248,7 @@ root {
|
|
195
248
|
Run (with the [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed):
|
196
249
|
|
197
250
|
```
|
198
|
-
ruby -
|
251
|
+
ruby -r glimmer-dsl-tk -e "require '../samples/hello/hello_tab.rb'"
|
199
252
|
```
|
200
253
|
|
201
254
|
Glimmer app:
|
@@ -203,6 +256,41 @@ Glimmer app:
|
|
203
256
|

|
204
257
|

|
205
258
|
|
259
|
+
### Hello, Combo!
|
260
|
+
|
261
|
+
Glimmer code (from [samples/hello/hello_combo.rb](samples/hello/hello_combo.rb)):
|
262
|
+
|
263
|
+
```ruby
|
264
|
+
# ... more code precedes
|
265
|
+
root {
|
266
|
+
title 'Hello, Combo!'
|
267
|
+
|
268
|
+
combobox { |proxy|
|
269
|
+
state 'readonly'
|
270
|
+
text bind(person, :country)
|
271
|
+
}
|
272
|
+
|
273
|
+
button { |proxy|
|
274
|
+
text "Reset Selection"
|
275
|
+
command {
|
276
|
+
person.reset_country
|
277
|
+
}
|
278
|
+
}
|
279
|
+
}.open
|
280
|
+
# ... more code follows
|
281
|
+
```
|
282
|
+
|
283
|
+
Run (with the [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed):
|
284
|
+
|
285
|
+
```
|
286
|
+
ruby -r glimmer-dsl-tk -e "require '../samples/hello/hello_combo.rb'"
|
287
|
+
```
|
288
|
+
|
289
|
+
Glimmer app:
|
290
|
+
|
291
|
+

|
292
|
+

|
293
|
+
|
206
294
|
## Help
|
207
295
|
|
208
296
|
### Issues
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/lib/glimmer-dsl-tk.rb
CHANGED
@@ -23,9 +23,9 @@ $LOAD_PATH.unshift(File.expand_path('..', __FILE__))
|
|
23
23
|
|
24
24
|
# External requires
|
25
25
|
require 'glimmer'
|
26
|
-
require 'logging'
|
26
|
+
# require 'logging'
|
27
27
|
require 'puts_debuggerer' if ENV['pd'].to_s.downcase == 'true'
|
28
|
-
require 'super_module'
|
28
|
+
# require 'super_module'
|
29
29
|
require 'tk'
|
30
30
|
|
31
31
|
# Internal requires
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'glimmer/data_binding/observable'
|
2
|
+
require 'glimmer/data_binding/observer'
|
3
|
+
|
4
|
+
module Glimmer
|
5
|
+
module DataBinding
|
6
|
+
module Tk
|
7
|
+
class WidgetBinding
|
8
|
+
include Glimmer
|
9
|
+
include Observable
|
10
|
+
include Observer
|
11
|
+
|
12
|
+
attr_reader :widget, :attribute
|
13
|
+
def initialize(widget, attribute)
|
14
|
+
@widget = widget
|
15
|
+
@attribute = attribute
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(value)
|
19
|
+
@widget.set_attribute(@attribute, value) unless evaluate_attribute == value
|
20
|
+
end
|
21
|
+
|
22
|
+
def evaluate_attribute
|
23
|
+
@widget.get_attribute(@attribute)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'glimmer/dsl/static_expression'
|
2
|
+
require 'glimmer/data_binding/model_binding'
|
3
|
+
|
4
|
+
module Glimmer
|
5
|
+
module DSL
|
6
|
+
module Tk
|
7
|
+
# Responsible for setting up the return value of the bind keyword (command symbol)
|
8
|
+
# as a ModelBinding. It is then used by another command handler like
|
9
|
+
# DataBindingCommandHandler for text and other attributes
|
10
|
+
class BindExpression < StaticExpression
|
11
|
+
def can_interpret?(parent, keyword, *args, &block)
|
12
|
+
(
|
13
|
+
keyword == 'bind' and
|
14
|
+
(
|
15
|
+
(
|
16
|
+
(args.size == 2) and
|
17
|
+
textual?(args[1])
|
18
|
+
) ||
|
19
|
+
(
|
20
|
+
(args.size == 3) and
|
21
|
+
textual?(args[1]) and
|
22
|
+
(args[2].is_a?(Hash))
|
23
|
+
)
|
24
|
+
)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def interpret(parent, keyword, *args, &block)
|
29
|
+
binding_options = args[2] || {}
|
30
|
+
binding_options[:on_read] = binding_options.delete(:on_read) || binding_options.delete('on_read') || block
|
31
|
+
DataBinding::ModelBinding.new(args[0], args[1].to_s, binding_options)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Copyright (c) 2020 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/dsl/expression'
|
23
|
+
|
24
|
+
module Glimmer
|
25
|
+
module DSL
|
26
|
+
module Tk
|
27
|
+
class BlockAttributeExpression < Expression
|
28
|
+
def can_interpret?(parent, keyword, *args, &block)
|
29
|
+
block_given? and
|
30
|
+
args.size == 0 and
|
31
|
+
parent.respond_to?("#{keyword}_block=")
|
32
|
+
end
|
33
|
+
|
34
|
+
def interpret(parent, keyword, *args, &block)
|
35
|
+
parent.send("#{keyword}_block=", block)
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'glimmer/dsl/expression'
|
2
|
+
require 'glimmer/data_binding/model_binding'
|
3
|
+
require 'glimmer/data_binding/tk/widget_binding'
|
4
|
+
|
5
|
+
module Glimmer
|
6
|
+
module DSL
|
7
|
+
module Tk
|
8
|
+
# Responsible for wiring two-way data-binding.
|
9
|
+
# Does so by using the output of the bind(model, property) command in the form
|
10
|
+
# of a ModelBinding, which is then connected to an anonymous widget observer
|
11
|
+
#
|
12
|
+
# Depends on BindCommandHandler
|
13
|
+
class DataBindingExpression < Expression
|
14
|
+
def can_interpret?(parent, keyword, *args, &block)
|
15
|
+
args.size == 1 and
|
16
|
+
args[0].is_a?(DataBinding::ModelBinding)
|
17
|
+
end
|
18
|
+
|
19
|
+
def interpret(parent, keyword, *args, &block)
|
20
|
+
model_binding = args[0]
|
21
|
+
widget_binding_parameters = [parent, keyword]
|
22
|
+
widget_binding = DataBinding::Tk::WidgetBinding.new(*widget_binding_parameters)
|
23
|
+
widget_binding.call(model_binding.evaluate_property)
|
24
|
+
#TODO make this options observer dependent and all similar observers in widget specific data binding handlers
|
25
|
+
widget_binding.observe(model_binding)
|
26
|
+
# TODO simplify this logic and put it where it belongs
|
27
|
+
parent.add_observer(model_binding, keyword) if parent.respond_to?(:add_observer, [model_binding, keyword])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/glimmer/dsl/tk/dsl.rb
CHANGED
@@ -33,7 +33,7 @@ module Glimmer
|
|
33
33
|
|
34
34
|
def can_interpret?(parent, keyword, *args, &block)
|
35
35
|
!EXCLUDED_KEYWORDS.include?(keyword) and
|
36
|
-
parent.respond_to?(:
|
36
|
+
parent.respond_to?(:tk) and
|
37
37
|
Glimmer::Tk::WidgetProxy.widget_exists?(keyword)
|
38
38
|
end
|
39
39
|
|
@@ -54,3 +54,4 @@ end
|
|
54
54
|
require 'glimmer/tk/widget_proxy'
|
55
55
|
require 'glimmer/tk/notebook_proxy'
|
56
56
|
require 'glimmer/tk/frame_proxy'
|
57
|
+
require 'glimmer/tk/button_proxy'
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright (c) 2020 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::Tile::Button
|
27
|
+
#
|
28
|
+
# Follows the Proxy Design Pattern
|
29
|
+
class ButtonProxy < WidgetProxy
|
30
|
+
def command_block=(proc)
|
31
|
+
tk.command(proc)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -29,7 +29,7 @@ module Glimmer
|
|
29
29
|
class RootProxy < WidgetProxy
|
30
30
|
|
31
31
|
def initialize(*args)
|
32
|
-
@
|
32
|
+
@tk = ::TkRoot.new
|
33
33
|
end
|
34
34
|
|
35
35
|
def open
|
@@ -37,7 +37,7 @@ module Glimmer
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def content(&block)
|
40
|
-
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::
|
40
|
+
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::RootExpression.new, &block)
|
41
41
|
end
|
42
42
|
|
43
43
|
# Starts Tk mainloop
|
@@ -25,17 +25,11 @@ module Glimmer
|
|
25
25
|
#
|
26
26
|
# Follows the Proxy Design Pattern
|
27
27
|
class WidgetProxy
|
28
|
-
attr_reader :parent_proxy, :
|
28
|
+
attr_reader :parent_proxy, :tk, :args
|
29
29
|
|
30
30
|
DEFAULT_INITIALIZERS = {
|
31
|
-
'
|
32
|
-
|
33
|
-
end,
|
34
|
-
'frame' => lambda do |widget|
|
35
|
-
widget.grid
|
36
|
-
end,
|
37
|
-
'notebook' => lambda do |widget|
|
38
|
-
widget.grid
|
31
|
+
'combobox' => lambda do |tk|
|
32
|
+
tk.textvariable = ::TkVariable.new
|
39
33
|
end,
|
40
34
|
}
|
41
35
|
|
@@ -61,8 +55,15 @@ module Glimmer
|
|
61
55
|
@parent_proxy = parent_proxy
|
62
56
|
@args = args
|
63
57
|
tk_widget_class = self.class.tk_widget_class_for(underscored_widget_name)
|
64
|
-
@
|
65
|
-
|
58
|
+
@tk = tk_widget_class.new(@parent_proxy.tk, *args)
|
59
|
+
begin
|
60
|
+
# a common widget initializer
|
61
|
+
@tk.grid
|
62
|
+
rescue => e
|
63
|
+
# catching error just in case a widget doesn't support it
|
64
|
+
Glimmer::Config.logger.debug e.full_message
|
65
|
+
end
|
66
|
+
DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@tk)
|
66
67
|
@parent_proxy.post_initialize_child(self)
|
67
68
|
end
|
68
69
|
|
@@ -97,7 +98,7 @@ module Glimmer
|
|
97
98
|
result = nil
|
98
99
|
begin
|
99
100
|
# TK Widget currently doesn't support respond_to? properly, so I have to resort to this trick for now
|
100
|
-
@
|
101
|
+
@tk.send(attribute_setter(attribute_name), @tk.send(attribute_name))
|
101
102
|
result = true
|
102
103
|
rescue => e
|
103
104
|
result = false
|
@@ -110,35 +111,77 @@ module Glimmer
|
|
110
111
|
end
|
111
112
|
|
112
113
|
def set_attribute(attribute_name, *args)
|
113
|
-
|
114
|
-
|
114
|
+
widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute_name.to_s]
|
115
|
+
if widget_custom_attribute
|
116
|
+
widget_custom_attribute[:setter][:invoker].call(@tk, args)
|
117
|
+
elsif tk_widget_has_attribute?(attribute_name)
|
118
|
+
@tk.send(attribute_setter(attribute_name), *args) unless @tk.send(attribute_name) == args.first
|
115
119
|
else
|
116
120
|
send(attribute_setter(attribute_name), args)
|
117
121
|
end
|
118
122
|
end
|
119
123
|
|
120
124
|
def get_attribute(attribute_name)
|
121
|
-
|
125
|
+
widget_custom_attribute = widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][attribute_name.to_s]
|
126
|
+
if widget_custom_attribute
|
127
|
+
widget_custom_attribute[:getter][:invoker].call(@tk, args)
|
128
|
+
else
|
129
|
+
@tk.send(attribute_name)
|
130
|
+
end
|
122
131
|
end
|
123
132
|
|
124
133
|
def attribute_setter(attribute_name)
|
125
134
|
"#{attribute_name}="
|
126
135
|
end
|
136
|
+
|
137
|
+
def widget_custom_attribute_mapping
|
138
|
+
@widget_custom_attribute_mapping ||= {
|
139
|
+
::Tk::Tile::TCombobox => {
|
140
|
+
'text' => {
|
141
|
+
getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
|
142
|
+
setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first }},
|
143
|
+
},
|
144
|
+
},
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def widget_property_listener_installers
|
149
|
+
@tk_widget_property_listener_installers ||= {
|
150
|
+
::Tk::Tile::TCombobox => {
|
151
|
+
:text => lambda do |observer|
|
152
|
+
if observer.is_a?(Glimmer::DataBinding::ModelBinding)
|
153
|
+
model = observer.model
|
154
|
+
options_model_property = observer.property_name + '_options'
|
155
|
+
@tk.values = model.send(options_model_property) if model.respond_to?(options_model_property)
|
156
|
+
end
|
157
|
+
@tk.bind('<ComboboxSelected>') {
|
158
|
+
observer.call(@tk.textvariable.value)
|
159
|
+
}
|
160
|
+
end,
|
161
|
+
}
|
162
|
+
}
|
163
|
+
end
|
164
|
+
|
165
|
+
def add_observer(observer, property_name)
|
166
|
+
property_listener_installers = @tk.class.ancestors.map {|ancestor| widget_property_listener_installers[ancestor]}.compact
|
167
|
+
widget_listener_installers = property_listener_installers.map{|installer| installer[property_name.to_s.to_sym]}.compact if !property_listener_installers.empty?
|
168
|
+
widget_listener_installers.to_a.first&.call(observer)
|
169
|
+
end
|
127
170
|
|
128
171
|
def content(&block)
|
129
172
|
Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::WidgetExpression.new, &block)
|
130
173
|
end
|
131
174
|
|
132
175
|
def method_missing(method, *args, &block)
|
133
|
-
|
176
|
+
tk.send(method, *args, &block)
|
134
177
|
rescue => e
|
135
|
-
Glimmer::Config.logger.debug {"Neither WidgetProxy nor #{
|
178
|
+
Glimmer::Config.logger.debug {"Neither WidgetProxy nor #{tk.class.name} can handle the method ##{method}"}
|
136
179
|
super
|
137
180
|
end
|
138
181
|
|
139
182
|
def respond_to?(method, *args, &block)
|
140
183
|
super ||
|
141
|
-
|
184
|
+
tk.respond_to?(method, *args, &block)
|
142
185
|
end
|
143
186
|
end
|
144
187
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'glimmer-dsl-tk'
|
2
|
+
|
3
|
+
class Person
|
4
|
+
attr_accessor :country, :country_options
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
self.country_options=["", "Canada", "US", "Mexico"]
|
8
|
+
self.country = "Canada"
|
9
|
+
end
|
10
|
+
|
11
|
+
def reset_country
|
12
|
+
self.country = "Canada"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class HelloCombo
|
17
|
+
include Glimmer
|
18
|
+
|
19
|
+
def launch
|
20
|
+
person = Person.new
|
21
|
+
|
22
|
+
root {
|
23
|
+
title 'Hello, Combo!'
|
24
|
+
|
25
|
+
combobox { |proxy|
|
26
|
+
state 'readonly'
|
27
|
+
text bind(person, :country)
|
28
|
+
}
|
29
|
+
|
30
|
+
button { |proxy|
|
31
|
+
text "Reset Selection"
|
32
|
+
command {
|
33
|
+
person.reset_country
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}.open
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
HelloCombo.new.launch
|
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.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- AndyMaleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: glimmer
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.10.3
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: puts_debuggerer
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 0.10.0
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 0.10.0
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: tk
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,20 +80,6 @@ dependencies:
|
|
94
80
|
- - ">="
|
95
81
|
- !ruby/object:Gem::Version
|
96
82
|
version: '1.0'
|
97
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: simplecov
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
83
|
- !ruby/object:Gem::Dependency
|
112
84
|
name: jeweler
|
113
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,6 +114,62 @@ dependencies:
|
|
142
114
|
- - ">="
|
143
115
|
- !ruby/object:Gem::Version
|
144
116
|
version: 0.2.1
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: puts_debuggerer
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 0.10.0
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: 0.10.0
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: coveralls
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - '='
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: 0.8.23
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - '='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: 0.8.23
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: simplecov
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: 0.16.1
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 0.16.1
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: simplecov-lcov
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 0.7.0
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: 0.7.0
|
145
173
|
description: Glimmer DSL for Tk (Ruby Desktop GUI)
|
146
174
|
email: andy.am@gmail.com
|
147
175
|
executables: []
|
@@ -156,14 +184,20 @@ files:
|
|
156
184
|
- README.md
|
157
185
|
- VERSION
|
158
186
|
- lib/glimmer-dsl-tk.rb
|
187
|
+
- lib/glimmer/data_binding/tk/widget_binding.rb
|
159
188
|
- lib/glimmer/dsl/tk/attribute_expression.rb
|
189
|
+
- lib/glimmer/dsl/tk/bind_expression.rb
|
190
|
+
- lib/glimmer/dsl/tk/block_attribute_expression.rb
|
191
|
+
- lib/glimmer/dsl/tk/data_binding_expression.rb
|
160
192
|
- lib/glimmer/dsl/tk/dsl.rb
|
161
193
|
- lib/glimmer/dsl/tk/root_expression.rb
|
162
194
|
- lib/glimmer/dsl/tk/widget_expression.rb
|
195
|
+
- lib/glimmer/tk/button_proxy.rb
|
163
196
|
- lib/glimmer/tk/frame_proxy.rb
|
164
197
|
- lib/glimmer/tk/notebook_proxy.rb
|
165
198
|
- lib/glimmer/tk/root_proxy.rb
|
166
199
|
- lib/glimmer/tk/widget_proxy.rb
|
200
|
+
- samples/hello/hello_combo.rb
|
167
201
|
- samples/hello/hello_tab.rb
|
168
202
|
- samples/hello/hello_world.rb
|
169
203
|
homepage: http://github.com/AndyObtiva/glimmer-dsl-tk
|