glimmer-dsl-tk 0.0.20 → 0.0.21

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