glimmer-dsl-tk 0.0.2 → 0.0.3

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: 3f1d6377c707655c2ae9b49e60f3412e31ef27869aefee78492c30feeba21ef5
4
- data.tar.gz: 02bef3e445ba3e3fce1633d89af37c66860dadbe2ae5aa4472c6dbcbbcd3602c
3
+ metadata.gz: 2f57063e358754b89fbd0a57cb118fb9764595a8965eba5884aeb2988ab2d6b1
4
+ data.tar.gz: f55e3fc96a9388dd218d7c674cdf1585831c44a3f6412741e0e65f53185e2d98
5
5
  SHA512:
6
- metadata.gz: 30f1946ae7324c585309f0986f5a320a427250ca2e6925999856a2bd07958ab420b8ba67e6227d1991f7ab68e43627337fc6644f4b97d81899a7dafaccc8db61
7
- data.tar.gz: cba5744288234fe059aa9c5efe68d9c0404d81211d63096b07a45f89474fcaaa4c57b7faccb018003394c8a50a9750c5bfc4d26f17a5ee16b74f40f5dac60170
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.2 (Desktop GUI)
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
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-tk.svg)](http://badge.fury.io/rb/glimmer-dsl-tk)
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/ce2853efdbecf6ebdc73/maintainability)](https://codeclimate.com/github/AndyObtiva/glimmer-dsl-tk/maintainability)
3
4
  [![Join the chat at https://gitter.im/AndyObtiva/glimmer](https://badges.gitter.im/AndyObtiva/glimmer.svg)](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
  ![glimmer dsl tk screenshot sample hello world](images/glimmer-dsl-tk-screenshot-sample-hello-world.png)
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 via JRuby on SWT)
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 'glimmer-dsl-tk', '~> 0.0.2'
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 -e "gem 'glimmer-dsl-tk'; require '../samples/hello/hello_world.rb'"
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 -e "gem 'glimmer-dsl-tk'; require '../samples/hello/hello_tab.rb'"
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
  ![glimmer dsl tk screenshot sample hello tab English](images/glimmer-dsl-tk-screenshot-sample-hello-tab-english.png)
204
257
  ![glimmer dsl tk screenshot sample hello tab French](images/glimmer-dsl-tk-screenshot-sample-hello-tab-french.png)
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
+ ![glimmer dsl tk screenshot sample hello combo](images/glimmer-dsl-tk-screenshot-sample-hello-combo.png)
292
+ ![glimmer dsl tk screenshot sample hello combo dropdown](images/glimmer-dsl-tk-screenshot-sample-hello-combo-dropdown.png)
293
+
206
294
  ## Help
207
295
 
208
296
  ### Issues
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.2
1
+ 0.0.3
@@ -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
@@ -36,6 +36,8 @@ module Glimmer
36
36
  Engine.add_dynamic_expressions(
37
37
  Tk,
38
38
  %w[
39
+ data_binding
40
+ block_attribute
39
41
  attribute
40
42
  widget
41
43
  ]
@@ -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?(:tk_widget) and
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
@@ -38,7 +38,7 @@ module Glimmer
38
38
 
39
39
  def post_initialize_child(child)
40
40
  @tab_proxies << child
41
- @tk_widget.add child.tk_widget, child.tab_options
41
+ @tk.add child.tk, child.tab_options
42
42
  end
43
43
  end
44
44
  end
@@ -29,7 +29,7 @@ module Glimmer
29
29
  class RootProxy < WidgetProxy
30
30
 
31
31
  def initialize(*args)
32
- @tk_widget = ::TkRoot.new
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::SWT::RootExpression.new, &block)
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, :tk_widget, :args
28
+ attr_reader :parent_proxy, :tk, :args
29
29
 
30
30
  DEFAULT_INITIALIZERS = {
31
- 'label' => lambda do |widget|
32
- widget.grid
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
- @tk_widget = tk_widget_class.new(@parent_proxy.tk_widget, *args)
65
- DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@tk_widget)
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
- @tk_widget.send(attribute_setter(attribute_name), @tk_widget.send(attribute_name))
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
- if tk_widget_has_attribute?(attribute_name)
114
- @tk_widget.send(attribute_setter(attribute_name), *args) unless @tk_widget.send(attribute_name) == args.first
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
- @tk_widget.send(attribute_name)
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
- tk_widget.send(method, *args, &block)
176
+ tk.send(method, *args, &block)
134
177
  rescue => e
135
- Glimmer::Config.logger.debug {"Neither WidgetProxy nor #{tk_widget.class.name} can handle the method ##{method}"}
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
- tk_widget.respond_to?(method, *args, &block)
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.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
- - andy_maleh
7
+ - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-11 00:00:00.000000000 Z
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