glimmer-dsl-tk 0.0.20 → 0.0.21

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: 9b35ad7e7ce829ab16c8ded93da64a71120483982e1799afddf538ff0726d686
4
- data.tar.gz: 6a5eec2b8c52f7df03d1f324780cc3b209b2969fe04ab64dc33efc8a1b3d05e7
3
+ metadata.gz: 49a3f4e1f560a01173a20fa1a13fc62f107445c63cad77f353b3b7a9765433c3
4
+ data.tar.gz: 70decda6f2e3a73a24916b2e9d0685ff386fc4fe29b89fff3b4188fab830f21b
5
5
  SHA512:
6
- metadata.gz: 3b462e07684dc68a0c15096ea80cd5a516ac9332a1ba21f2235e85b5343b174561446d62633aa2dfc280557ff01531872fd3a033aafc1bf0eec6386b8b4d9901
7
- data.tar.gz: 79dba86d404165e841ad94d034799bf3ba10e52fc286bdaa2af3d85b80d0ada8a075396f229e2de498fcea61274722cb8dacd762e68fb7243a9754b57e6221fe
6
+ metadata.gz: 7f9b8ee1544898bcb7031eacaf4ebb532ab113ac5852b6606bf247a05e27937b5d22c87833b5947527e6b525d83e2eb5714a42f1cf8f754bf7513d59eaf19ff4
7
+ data.tar.gz: 479e321c66646a97bd5fee7e6844e4b7a862ec88b2ba25697a9f8e1ac231717297258576b4b88facab135094bff30b2a507bd6b1a624fb0288f163ca5dff54c9
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.21
4
+
5
+ - Support event bindings via `on(event) {}` syntax nestable under any widget
6
+ - Support `root` event binding: `'WM_DELETE_WINDOW'` and alias `'DELETE_WINDOW'`
7
+ - Support `root` event binding: `'OPEN_WINDOW'`
8
+ - Support `root` attribute: `background` (any color including `systemTransparent`)
9
+ - Support `root` boolean attribute: `alpha`
10
+ - Support `root` boolean attributes: `fullscreen`, `topmost`, `transparent`
11
+ - Support `root` attributes: `stackorder`, `winfo_screendepth`, `winfo_screenvisual`, `winfo_screenwidth`, `winfo_screenheight`, `winfo_pixels('li')`, `winfo_screen`, `wm_maxsize`
12
+ - Support `root` attribute: `state` (`'normal', 'iconic', 'withdrawn', 'icon', 'zoomed'`)
13
+
3
14
  ## 0.0.20
4
15
 
5
16
  - Hello, Root! sample
data/README.md CHANGED
@@ -1,4 +1,4 @@
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.20
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.21
2
2
  ## MRI Ruby Desktop Development GUI Library
3
3
  [![Gem Version](https://badge.fury.io/rb/glimmer-dsl-tk.svg)](http://badge.fury.io/rb/glimmer-dsl-tk)
4
4
  [![Ruby](https://github.com/AndyObtiva/glimmer-dsl-tk/actions/workflows/ruby.yml/badge.svg)](https://github.com/AndyObtiva/glimmer-dsl-tk/actions/workflows/ruby.yml)
@@ -120,7 +120,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
120
120
  For example, on the Mac, you can:
121
121
  - Install the ActiveTcl Mac package from [ActiveState.com](https://activestate.com)
122
122
  - Install [RVM](https://rvm.io/) by running `\curl -sSL https://get.rvm.io | bash -s stable` (and run `curl -sSL https://rvm.io/pkuczynski.asc | gpg --import -` if needed for mentioned security reasons)
123
- - Run: `rvm install 2.7.1 --enable-shared --enable-pthread --with-tk --with-tcl`
123
+ - Run: `rvm install 3.0.2 --enable-shared --enable-pthread --with-tk --with-tcl`
124
124
  - Run: `gem install tk -v0.4.0`
125
125
 
126
126
  Afterwards, if you open `irb`, you should be able to run `require 'tk'` successfully.
@@ -138,7 +138,7 @@ gem install glimmer-dsl-tk
138
138
 
139
139
  Add the following to `Gemfile`:
140
140
  ```
141
- gem 'glimmer-dsl-tk', '~> 0.0.20'
141
+ gem 'glimmer-dsl-tk', '~> 0.0.21'
142
142
  ```
143
143
 
144
144
  And, then run:
@@ -180,6 +180,7 @@ The Glimmer GUI DSL follows these simple concepts in mapping from Tk syntax:
180
180
  - **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.
181
181
  - **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'`)
182
182
  - **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`)
183
+ - **Event Binding Block**: `on(event) {}` keyword receiving a Tk binding event name (e.g. `KeyPress` or `ComboboxSelected`). No need to surround event by `<>` as [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) takes care of that automatically.
183
184
 
184
185
  Example of an app written in [Tk](https://www.tcl.tk/) imperative syntax:
185
186
 
@@ -199,6 +200,15 @@ notebook.add tab2, text: 'French'
199
200
  label2 = ::Tk::Tile::Label.new(tab2).grid
200
201
  label2.text = 'Bonjour, Univers!'
201
202
 
203
+ root.bind('KeyPress') do |event|
204
+ case event.keysym
205
+ when 'e', 'E'
206
+ notebook.select(0)
207
+ when 'f', 'F'
208
+ notebook.select(1)
209
+ end
210
+ end
211
+
202
212
  root.mainloop
203
213
  ```
204
214
 
@@ -208,7 +218,7 @@ Example of the same app written in [Glimmer](https://github.com/AndyObtiva/glimm
208
218
  root {
209
219
  title 'Hello, Notebook!'
210
220
 
211
- notebook {
221
+ @notebook = notebook {
212
222
  frame(text: 'English') {
213
223
  label {
214
224
  text 'Hello, World!'
@@ -221,6 +231,15 @@ root {
221
231
  }
222
232
  }
223
233
  }
234
+
235
+ on('KeyPress') do |event|
236
+ case event.keysym
237
+ when 'e', 'E'
238
+ @notebook.select(0)
239
+ when 'f', 'F'
240
+ @notebook.select(1)
241
+ end
242
+ end
224
243
  }.open
225
244
  ```
226
245
 
@@ -228,19 +247,51 @@ root {
228
247
 
229
248
  keyword(args) | attributes | event bindings & callbacks
230
249
  ------------- | ---------- | ---------
231
- `button` | `text`, `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `default` (`'active', 'normal'`) | `command`
250
+ `button` | `text`, `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `default` (`'active', 'normal'`) | `command {}`
251
+ `combobox` | `state`, `text` | `'ComboboxSelected'`
232
252
  `entry` | `width`, `text` | None
233
253
  `frame(text: nil)` | `width`, `height`, `borderwidth`, `relief` (`'flat' (default), 'raised', 'sunken', 'solid', 'ridge', 'groove'`) | None
234
254
  `label` | `text`, `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `font` (`'default', 'text', 'fixed', 'menu', 'heading', 'caption', 'small_caption', 'icon', 'tooltip'`), `relief` (`'flat' (default), 'raised', 'sunken', 'solid', 'ridge', 'groove'`), `justify` (`'left', 'center', 'right'`), `foreground`, `background` | None
235
255
  `list` | `selectmode`, `selection` | None
236
256
  `message_box(type: , message: , detail: , title: , icon: , default: , parent: )` | None | None
237
257
  `notebook` | None | None
238
- `root` | `title`, `iconphoto` | None
258
+ `root` | `title`, `iconphoto`, `background`, `alpha`, `fullscreen?`, `topmost?`, `transparent?`, `stackorder`, `winfo_screendepth`, `winfo_screenvisual`, `winfo_screenwidth`, `winfo_screenheight`, `winfo_pixels('li')`, `winfo_screen`, `wm_maxsize`, `state` (`'normal', 'iconic', 'withdrawn', 'icon', 'zoomed'`) | `'DELETE_WINDOW'`, `'OPEN_WINDOW'`
239
259
 
240
260
  #### Common Attributes
241
261
 
242
262
  - `grid`: `Hash` of `:row`, `:column`, `:padx`, `:pady`, `:sticky` (`'e', 'w', 'n', 's'` or any combination of direction letters)
243
263
 
264
+ #### Common Event Bindings
265
+
266
+ - `Activate`
267
+ - `Deactivate`
268
+ - `MouseWheel`
269
+ - `KeyPress`
270
+ - `KeyRelease`
271
+ - `ButtonPress`
272
+ - `ButtonRelease`
273
+ - `Motion`
274
+ - `Configure`
275
+ - `Map`
276
+ - `Unmap`
277
+ - `Visibility`
278
+ - `Expose`
279
+ - `Destroy`
280
+ - `FocusIn`
281
+ - `FocusOut`
282
+ - `Enter`
283
+ - `Leave`
284
+ - `Property`
285
+ - `Colormap`
286
+ - `MapRequest`
287
+ - `CirculateRequest`
288
+ - `ResizeRequest`
289
+ - `ConfigureRequest`
290
+ - `Create`
291
+ - `Gravity`
292
+ - `Reparent`
293
+ - `Circulate`
294
+
244
295
  #### Common Themed Widget States
245
296
 
246
297
  - `active?`
@@ -256,6 +307,10 @@ keyword(args) | attributes | event bindings & callbacks
256
307
 
257
308
  ### Smart Defaults and Convensions
258
309
 
310
+ #### Event Bindings
311
+
312
+ Any events that normally can be accepted by the Tk `bind` or `protocol` methods can be accepted by the `on(event) {}` listener syntax. There is no need to surround event name by `<>` as [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) automatically takes care of that when needed and leaves out when not needed.
313
+
259
314
  #### Grid Layout
260
315
 
261
316
  `grid` layout is the default on most widgets (which support it).
@@ -655,15 +710,28 @@ require 'glimmer-dsl-tk'
655
710
 
656
711
  include Glimmer
657
712
 
658
- root {
713
+ root { |r|
659
714
  title 'Hello, Root!'
715
+ iconphoto File.expand_path('../../icons/glimmer.png', __dir__)
660
716
  width 400
661
717
  height 200
662
- x 150
718
+ x -150
663
719
  y 300
664
720
  resizable true # same as `resizable true, true`, meaning cannot resize horizontally and vertically
665
721
  minsize 200, 100
666
722
  maxsize 600, 400
723
+ background 'lightgrey'
724
+ alpha 0.85 # on the mac, you can set `transparent true` as well
725
+ topmost true
726
+
727
+ on('OPEN_WINDOW') do # custom event that runs right after Tk.mainloop
728
+ message_box(parent: r, title: 'Hi', message: 'Hi')
729
+ end
730
+
731
+ on('DELETE_WINDOW') do |event| # alias for WM_DELETE_WINDOW protocol event
732
+ message_box(parent: r, title: 'Bye', message: 'Bye')
733
+ exit(0)
734
+ end
667
735
  }.open
668
736
  ```
669
737
 
@@ -679,6 +747,14 @@ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems
679
747
  ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_root.rb
680
748
  ```
681
749
 
750
+ Glimmer app:
751
+
752
+ ![glimmer dsl tk screenshot sample hello root hi](images/glimmer-dsl-tk-screenshot-sample-hello-root-hi.png)
753
+
754
+ ![glimmer dsl tk screenshot sample hello root](images/glimmer-dsl-tk-screenshot-sample-hello-root.png)
755
+
756
+ ![glimmer dsl tk screenshot sample hello root bye](images/glimmer-dsl-tk-screenshot-sample-hello-root-bye.png)
757
+
682
758
  ### Hello, Notebook!
683
759
 
684
760
  Glimmer code (from [samples/hello/hello_notebook.rb](samples/hello/hello_notebook.rb)):
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.20
1
+ 0.0.21
Binary file
@@ -0,0 +1,35 @@
1
+ # Copyright (c) 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/dsl/static_expression'
23
+ require 'glimmer/tk/widget_proxy'
24
+
25
+ module Glimmer
26
+ module DSL
27
+ module Tk
28
+ class OnExpression < StaticExpression
29
+ def interpret(parent, keyword, *args, &block)
30
+ parent.handle_listener(args.first, &block)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -126,8 +126,28 @@ module Glimmer
126
126
  set_attribute(:y, value)
127
127
  end
128
128
 
129
+ def handle_listener(listener_name, &listener)
130
+ case listener_name.to_s
131
+ when 'WM_DELETE_WINDOW', 'DELETE_WINDOW'
132
+ listener_name = 'WM_DELETE_WINDOW'
133
+ @tk.protocol(listener_name, &listener)
134
+ when 'WM_OPEN_WINDOW', 'OPEN_WINDOW'
135
+ @on_open_window_procs ||= []
136
+ @on_open_window_procs << listener
137
+ else
138
+ super
139
+ end
140
+ end
141
+
129
142
  # Starts Tk mainloop
130
143
  def start_event_loop
144
+ if @on_open_window_procs.to_a.any?
145
+ ::Tk.after(100) do # ensure root window showed up first
146
+ @on_open_window_procs.to_a.each do |on_open_window|
147
+ ::Tk.after(0, on_open_window)
148
+ end
149
+ end
150
+ end
131
151
  ::Tk.mainloop
132
152
  end
133
153
 
@@ -140,11 +140,17 @@ module Glimmer
140
140
  end
141
141
  end
142
142
 
143
+ def has_attributes_attribute?(attribute)
144
+ attribute = attribute.sub(/\?$/, '').sub(/=$/, '')
145
+ @tk.respond_to?(:attributes) && @tk.attributes.keys.include?(attribute.to_s)
146
+ end
147
+
143
148
  def has_attribute?(attribute, *args)
144
149
  (widget_custom_attribute_mapping[tk.class] and widget_custom_attribute_mapping[tk.class][attribute.to_s]) or
145
150
  tk_widget_has_attribute_setter?(attribute) or
146
151
  tk_widget_has_attribute_getter_setter?(attribute) or
147
152
  has_state?(attribute) or
153
+ has_attributes_attribute?(attribute) or
148
154
  respond_to?(attribute_setter(attribute), args)
149
155
  end
150
156
 
@@ -169,6 +175,9 @@ module Glimmer
169
175
  else
170
176
  @tk.tile_state("!#{attribute}")
171
177
  end
178
+ elsif has_attributes_attribute?(attribute)
179
+ attribute = attribute.sub(/=$/, '')
180
+ @tk.attributes(attribute, args.first)
172
181
  else
173
182
  send(attribute_setter(attribute), args)
174
183
  end
@@ -182,6 +191,10 @@ module Glimmer
182
191
  @tk.send(attribute)
183
192
  elsif has_state?(attribute)
184
193
  @tk.tile_instate(attribute.sub(/\?$/, ''))
194
+ elsif has_attributes_attribute?(attribute)
195
+ result = @tk.attributes[attribute.sub(/\?$/, '')]
196
+ result = result == 1 if result.is_a?(Integer)
197
+ result
185
198
  else
186
199
  send(attribute)
187
200
  end
@@ -277,16 +290,28 @@ module Glimmer
277
290
  widget_listener_installers = attribute_listener_installers.map{|installer| installer[attribute.to_s]}.compact if !attribute_listener_installers.empty?
278
291
  widget_listener_installers.to_a.first&.call(observer)
279
292
  end
280
-
293
+
294
+ def handle_listener(listener_name, &listener)
295
+ listener_name = listener_name.to_s
296
+ begin
297
+ @tk.bind(listener_name, &listener)
298
+ rescue => e
299
+ Glimmer::Config.logger.debug {e.full_message}
300
+ listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
301
+ listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
302
+ @tk.bind(listener_name, &listener)
303
+ end
304
+ end
305
+
281
306
  def content(&block)
282
307
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::WidgetExpression.new, keyword, *args, &block)
283
308
  end
284
309
 
285
310
  def method_missing(method, *args, &block)
286
311
  method = method.to_s
287
- if args.empty? && block.nil? && ((widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][method]) || has_state?(method))
312
+ if args.empty? && block.nil? && ((widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][method]) || has_state?(method) || has_attributes_attribute?(method))
288
313
  get_attribute(method)
289
- elsif method.end_with?('=') && block.nil? && ((widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][method.sub(/=$/, '')]) || has_state?(method))
314
+ elsif method.end_with?('=') && block.nil? && ((widget_custom_attribute_mapping[tk.class] && widget_custom_attribute_mapping[tk.class][method.sub(/=$/, '')]) || has_state?(method) || has_attributes_attribute?(method))
290
315
  set_attribute(method.sub(/=$/, ''), *args)
291
316
  else
292
317
  tk.send(method, *args, &block)
@@ -27,7 +27,7 @@ class HelloNotebook
27
27
  def launch
28
28
  root {
29
29
  title 'Hello, Notebook!'
30
-
30
+
31
31
  notebook {
32
32
  frame(text: 'English') {
33
33
  label {
@@ -23,13 +23,26 @@ require 'glimmer-dsl-tk'
23
23
 
24
24
  include Glimmer
25
25
 
26
- root {
26
+ root { |r|
27
27
  title 'Hello, Root!'
28
+ iconphoto File.expand_path('../../icons/glimmer.png', __dir__)
28
29
  width 400
29
30
  height 200
30
- x 150
31
+ x -150
31
32
  y 300
32
33
  resizable true # same as `resizable true, true`, meaning cannot resize horizontally and vertically
33
34
  minsize 200, 100
34
35
  maxsize 600, 400
36
+ background 'lightgrey'
37
+ alpha 0.85 # on the mac, you can set `transparent true` as well
38
+ topmost true
39
+
40
+ on('OPEN_WINDOW') do # custom event that runs right after Tk.mainloop
41
+ message_box(parent: r, title: 'Hi', message: 'Hi')
42
+ end
43
+
44
+ on('DELETE_WINDOW') do |event| # alias for WM_DELETE_WINDOW protocol event
45
+ message_box(parent: r, title: 'Bye', message: 'Bye')
46
+ exit(0)
47
+ end
35
48
  }.open
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: glimmer-dsl-tk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.20
4
+ version: 0.0.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
@@ -198,6 +198,7 @@ files:
198
198
  - lib/glimmer/dsl/tk/dsl.rb
199
199
  - lib/glimmer/dsl/tk/list_selection_data_binding_expression.rb
200
200
  - lib/glimmer/dsl/tk/message_box_expression.rb
201
+ - lib/glimmer/dsl/tk/on_expression.rb
201
202
  - lib/glimmer/dsl/tk/root_expression.rb
202
203
  - lib/glimmer/dsl/tk/shine_data_binding_expression.rb
203
204
  - lib/glimmer/dsl/tk/widget_expression.rb