glimmer-dsl-tk 0.0.22 → 0.0.26

Sign up to get free protection for your applications and to get access to all the features.
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.21
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.26
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)
@@ -76,25 +76,28 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
76
76
  - [Supported Widgets](#supported-widgets)
77
77
  - [Common Attributes](#common-attributes)
78
78
  - [Common Themed Widget States](#common-themed-widget-states)
79
- - [Smart Defaults and Convensions](#smart-defaults-and-convensions)
79
+ - [Smart Defaults and Conventions](#smart-defaults-and-conventions)
80
80
  - [Grid Layout](#grid-layout)
81
81
  - [Label/Button Image](#labelbutton-image)
82
82
  - [Notebook Frame](#notebook-frame)
83
83
  - [Icon Photo](#icon-photo)
84
84
  - [The Grid Geometry Manager](#the-grid-geometry-manager)
85
- - [Bidirectional Data-Binding](#bidirectional-data-binding)
85
+ - [Data-Binding](#data-binding)
86
86
  - [Label Data-Binding](#label-data-binding)
87
87
  - [Combobox Data-Binding](#combobox-data-binding)
88
88
  - [List Single Selection Data-Binding](#list-single-selection-data-binding)
89
89
  - [List Multi Selection Data-Binding](#list-multi-selection-data-binding)
90
90
  - [Entry Data-Binding](#entry-data-binding)
91
- - [Checkbox Data-Binding](#checkbox-data-binding)
91
+ - [Spinbox Data-Binding](#spinbox-data-binding)
92
+ - [Checkbutton Data-Binding](#checkbutton-data-binding)
93
+ - [Radiobutton Data-Binding](#radiobutton-data-binding)
92
94
  - [Command Callback](#command-callback)
93
95
  - [Gotchas](#gotchas)
94
96
  - [Samples](#samples)
95
97
  - [Hello, World!](#hello-world)
96
98
  - [Hello, Button!](#hello-button)
97
99
  - [Hello, Checkbutton!](#hello-checkbutton)
100
+ - [Hello, Radiobutton!](#hello-radiobutton)
98
101
  - [Hello, Frame!](#hello-frame)
99
102
  - [Hello, Root!](#hello-root)
100
103
  - [Hello, Notebook!](#hello-notebook)
@@ -103,6 +106,9 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
103
106
  - [Hello, Combobox!](#hello-combobox)
104
107
  - [Hello, List Single Selection!](#hello-list-single-selection)
105
108
  - [Hello, List Multi Selection!](#hello-list-multi-selection)
109
+ - [Hello, Entry!](#hello-entry)
110
+ - [Hello, Text!](#hello-text)
111
+ - [Hello, Spinbox!](#hello-spinbox)
106
112
  - [Hello, Computed!](#hello-computed)
107
113
  - [Help](#help)
108
114
  - [Issues](#issues)
@@ -140,7 +146,7 @@ gem install glimmer-dsl-tk
140
146
 
141
147
  Add the following to `Gemfile`:
142
148
  ```
143
- gem 'glimmer-dsl-tk', '~> 0.0.21'
149
+ gem 'glimmer-dsl-tk', '~> 0.0.26'
144
150
  ```
145
151
 
146
152
  And, then run:
@@ -250,15 +256,18 @@ root {
250
256
  keyword(args) | attributes | event bindings & callbacks
251
257
  ------------- | ---------- | ---------
252
258
  `button` | `text`, `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `default` (`'active', 'normal'`) | `command {}`
253
- `checkbutton` | `text`, `variable` (Boolean), `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `default` (`'active', 'normal'`) | `command {}`
259
+ `checkbutton` | `text`, `variable` (Boolean), `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `onvalue` (default: `1`), `offvalue` (default: `0`) | `command {}`
254
260
  `combobox` | `state`, `text` | `'ComboboxSelected'`
255
- `entry` | `width`, `text` | None
261
+ `entry` | `width`, `text`, `validate`, `show` (`'none', 'focus', 'focusin', 'focusout', 'key', or 'all'`) | `'validate'`, `'invalid'`, `'change'`, `validatecommand {}`, `invalidcommand {}`
262
+ `spinbox` | `text`, `from`, `to`, `increment`, `format`, [more attributes](https://tcl.tk/man/tcl8.6/TkCmd/text.htm#M116) | `command {}`, `'increment'`, `'decrement'`
256
263
  `frame(text: nil)` | `width`, `height`, `borderwidth`, `relief` (`'flat' (default), 'raised', 'sunken', 'solid', 'ridge', 'groove'`) | None
257
264
  `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
258
265
  `list` | `selectmode`, `selection` | None
259
266
  `message_box(type: , message: , detail: , title: , icon: , default: , parent: )` | None | None
260
267
  `notebook` | None | None
268
+ `radiobutton` | `text`, `variable` (Boolean), `image` (optional keyword args: `subsample`, `zoom`, `from`, `to`, `shrink`, `compositingrule`), `compound` (`'center', 'top', 'bottom', 'left', 'right'`), `value` (default: `text`) | `command {}`
261
269
  `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'`
270
+ `text` | `text`, [many more attributes](https://tcl.tk/man/tcl8.6/TkCmd/text.htm#M116) | `'modified'`, `'selection'`
262
271
 
263
272
  #### Common Attributes
264
273
 
@@ -308,15 +317,19 @@ keyword(args) | attributes | event bindings & callbacks
308
317
  - `invalid?`
309
318
  - `hover?`
310
319
 
311
- ### Smart Defaults and Convensions
320
+ ### Smart Defaults and Conventions
312
321
 
313
322
  #### Event Bindings
314
323
 
315
- 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.
324
+ Any events that normally can be accepted by the Tk `bind` or `protocol` methods can be accepted by the `on(event) {}` listener syntax. For actual (non-virtual) events, 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.
316
325
 
317
326
  #### Grid Layout
318
327
 
319
- `grid` layout is the default on most widgets (which support it).
328
+ `grid` layout with `sticky: 'nsew'` is the default on all widgets except toplevel widgets.
329
+
330
+ Also, any widget that is the first in a series of siblings has `column_weight` as `1` to automatically resize with window resizing by default.
331
+
332
+ To override that behavior, you may set alternative `grid` keyword args if needed (e.g. `grid sticky: '', column_weight: 0` disables the smart defaults).
320
333
 
321
334
  #### Label/Button Image
322
335
 
@@ -350,6 +363,10 @@ root {
350
363
  }.open
351
364
  ```
352
365
 
366
+ #### Root Background
367
+
368
+ `root` `background` color attribute is automatically set to `'#ececec'` on the Mac to avoid having a non-native-looking light-colored background.
369
+
353
370
  ## The Grid Geometry Manager
354
371
 
355
372
  The Grid Geometry Manager is supported via the `grid` keyword just as per the [Tk documentation](https://tkdocs.com/tutorial/grid.html), except by nesting under the widget it concerns.
@@ -368,9 +385,17 @@ Example:
368
385
  }
369
386
  ```
370
387
 
388
+ Extra convenience options may be passed to `grid` when using [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk):
389
+ - `min_width`: alias for `columnminsize` being called on `TkGrid.columnconfigure`
390
+ - `min_height`: alias for `rowminsize` being called on `TkGrid.rowconfigure`
391
+ - `column_weight`: alias for `columnweight` being called on `TkGrid.columnconfigure`
392
+ - `row_weight`: alias for `rowweight` being called on `TkGrid.rowconfigure`
393
+
394
+ Note also the [Grid Layout](#grid-layout) conventions (e.g. `column_weight` is automatically set to `1` for the first widget in a series of siblings to automatically have all resize when window resize)
395
+
371
396
  More details can be found in the [Hello, Computed!](#hello-computed) sample below.
372
397
 
373
- ## Bidirectional Data-Binding
398
+ ## Data-Binding
374
399
 
375
400
  Glimmer supports Shine syntax bidirectional data-binding via the `<=>` operator (read-write) and unidirectional data-binding via the `<=` operator (read-only), which takes a model and an attribute (the `bind` keyword may also be used as the old-style of data-binding).
376
401
 
@@ -400,7 +425,7 @@ This assumes a `Person` model with a `country` attribute representing their curr
400
425
 
401
426
  ```ruby
402
427
  combobox {
403
- state 'readonly'
428
+ readonly true # this applies to text editing only (item selection still triggers a write to model)
404
429
  text <=> [person, :country]
405
430
  }
406
431
  ```
@@ -471,9 +496,49 @@ That code binds the `textvariable` value of the `entry` to the `country` attribu
471
496
 
472
497
  It automatically handles all the Tk plumbing behind the scenes.
473
498
 
474
- More details can be found in the [Hello, Computed!](#hello-computed) sample below.
499
+ More details can be found in [Hello, Entry!](#hello-entry) and [Hello, Computed!](#hello-computed) samples below.
500
+
501
+ ### Spinbox Data-Binding
502
+
503
+ Example:
504
+
505
+ This assumes a `Person` model with a `donation` attribute.
506
+
507
+ ```ruby
508
+ spinbox {
509
+ from 1.0 # minimum value
510
+ to 150.0 # maximum value
511
+ increment 5.0 # increment on up and down
512
+ format '%0.2f'
513
+ text <=> [person, :country]
514
+ }
515
+ ```
516
+
517
+ That code binds the `textvariable` value of the `spinbox` to the `donation` attribute on the `person` model.
518
+
519
+ It automatically handles all the Tk plumbing behind the scenes.
520
+
521
+ More details can be found in [Hello, Spinbox!](#hello-spinbox) sample below.
522
+
523
+ ### Text Data-Binding
475
524
 
476
- ### Checkbox Data-Binding
525
+ Example:
526
+
527
+ This assumes a `Person` model with a `address` attribute.
528
+
529
+ ```ruby
530
+ text {
531
+ text <=> [person, :address]
532
+ }
533
+ ```
534
+
535
+ That code binds the text content of `text` to the `address` attribute on the `person` model.
536
+
537
+ It automatically handles all the Tk plumbing behind the scenes (including fine-grained inserts and deletes, abstracting them all away).
538
+
539
+ More details can be found in [Glimmer Meta-Sample](#samples) below.
540
+
541
+ ### Checkbutton Data-Binding
477
542
 
478
543
  Example:
479
544
 
@@ -489,11 +554,39 @@ That code binds the `variable` value of the `checkbutton` to the boolean `adult`
489
554
 
490
555
  It automatically handles all the Tk plumbing behind the scenes.
491
556
 
557
+ If you need to display a half-checked `checkbutton`, bind to `alternate` attribute.
558
+
492
559
  More details can be found in the [Hello, Checkbutton!](#hello-checkbutton) sample below.
493
560
 
561
+ ### Radiobutton Data-Binding
562
+
563
+ Example:
564
+
565
+ This assumes a `Person` model with boolean `male` and `female` attributes.
566
+
567
+ ```ruby
568
+ radiobutton {
569
+ text 'Male'
570
+ variable <=> [@person, :male]
571
+ }
572
+
573
+ radiobutton {
574
+ text 'Female'
575
+ variable <=> [@person, :female]
576
+ }
577
+ ```
578
+
579
+ That code binds the `variable` value of the `radiobutton` to the boolean `male` and `female` attributes on the `person` model.
580
+
581
+ It automatically handles all the Tk plumbing behind the scenes, including setting the `radiobutton` `value` (uses `text` attribute as `value`), enabling an API that works with simple booleans for each `radiobutton`.
582
+
583
+ For very rare cases, if you need to display a half-selected `radiobutton`, set `alternate` attribute as `true` when the `variable` value is `false`.
584
+
585
+ More details can be found in the [Hello, Radiobutton!](#hello-radiobutton) sample below.
586
+
494
587
  ## Command Callback
495
588
 
496
- `button` and `checkbutton` can set a `command` block to trigger when the user clicks the button/checkbutton. This may be done with the `command` keyword, passing in a block directly.
589
+ `button`, `spinbox`, `radiobutton` and `checkbutton` can set a `command` block to trigger when the user clicks the button/checkbutton. This may be done with the `command` keyword, passing in a block directly.
497
590
 
498
591
  Example:
499
592
 
@@ -507,6 +600,18 @@ Example:
507
600
  }
508
601
  ```
509
602
 
603
+ Alternatively, it can be treated as simply an event for consistency with other event bindings:
604
+
605
+ ```ruby
606
+ button {
607
+ text "Reset Selection"
608
+
609
+ on('command') do
610
+ person.reset_country
611
+ end
612
+ }
613
+ ```
614
+
510
615
  More details can be found in the [Hello, Button!](#hello-button) sample below.
511
616
 
512
617
  ## Gotchas
@@ -515,6 +620,22 @@ More details can be found in the [Hello, Button!](#hello-button) sample below.
515
620
 
516
621
  ## Samples
517
622
 
623
+ The easiest way to run samples is by launching the Glimmer Meta-Sample (the Sample of Samples).
624
+
625
+ Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
626
+
627
+ ```
628
+ ruby -r glimmer-dsl-tk -e "require 'samples/elaborate/meta_sample'"
629
+ ```
630
+
631
+ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
632
+
633
+ ```
634
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/elaborate/meta_sample.rb
635
+ ```
636
+
637
+ ![glimmer dsl tk screenshot sample meta sample](images/glimmer-dsl-tk-screenshot-sample-elaborate-meta-sample.png)
638
+
518
639
  ### Hello, World!
519
640
 
520
641
  Glimmer code (from [samples/hello/hello_world.rb](samples/hello/hello_world.rb)):
@@ -542,7 +663,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_world'"
542
663
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
543
664
 
544
665
  ```
545
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_world.rb
666
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_world.rb
546
667
  ```
547
668
 
548
669
  Glimmer app:
@@ -641,7 +762,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_button'"
641
762
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
642
763
 
643
764
  ```
644
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_button.rb
765
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_button.rb
645
766
  ```
646
767
 
647
768
  Glimmer app:
@@ -657,13 +778,47 @@ require 'glimmer-dsl-tk'
657
778
 
658
779
  class HelloCheckbutton
659
780
  class Person
660
- attr_accessor :skiing, :snowboarding, :snowmobiling, :snowshoeing
781
+ attr_accessor :skiing, :snowboarding, :snowmobiling, :snowshoeing, :snow_activities, :snow_activities_alternate
661
782
 
662
783
  def initialize
663
784
  reset_activities!
785
+ individual_observer = Glimmer::DataBinding::Observer.proc do
786
+ unless @updating_group
787
+ @updating_individual = true
788
+ if skiing && snowboarding && snowmobiling && snowshoeing
789
+ self.snow_activities = true
790
+ self.snow_activities_alternate = false
791
+ elsif skiing || snowboarding || snowmobiling || snowshoeing
792
+ self.snow_activities = true
793
+ self.snow_activities_alternate = true
794
+ else
795
+ self.snow_activities = false
796
+ self.snow_activities_alternate = false
797
+ end
798
+ @updating_individual = false
799
+ end
800
+ end
801
+ individual_observer.observe(self, :skiing)
802
+ individual_observer.observe(self, :snowboarding)
803
+ individual_observer.observe(self, :snowmobiling)
804
+ individual_observer.observe(self, :snowshoeing)
805
+
806
+ group_observer = Glimmer::DataBinding::Observer.proc do
807
+ unless @updating_individual
808
+ @updating_group = true
809
+ self.skiing = self.snow_activities
810
+ self.snowboarding = self.snow_activities
811
+ self.snowmobiling = self.snow_activities
812
+ self.snowshoeing = self.snow_activities
813
+ @updating_group = false
814
+ end
815
+ end
816
+ group_observer.observe(self, :snow_activities)
664
817
  end
665
818
 
666
819
  def reset_activities!
820
+ self.snow_activities = true
821
+ self.snow_activities_alternate = true
667
822
  self.skiing = false
668
823
  self.snowboarding = true
669
824
  self.snowmobiling = false
@@ -689,23 +844,31 @@ class HelloCheckbutton
689
844
 
690
845
  frame {
691
846
  checkbutton {
692
- text 'Skiing'
693
- variable <=> [@person, :skiing]
694
- }
695
-
696
- checkbutton {
697
- text 'Snowboarding'
698
- variable <=> [@person, :snowboarding]
699
- }
700
-
701
- checkbutton {
702
- text 'Snowmobiling'
703
- variable <=> [@person, :snowmobiling]
847
+ text 'Snow Activities'
848
+ variable <=> [@person, :snow_activities]
849
+ alternate <=> [@person, :snow_activities_alternate] # binds half-checked state
704
850
  }
705
851
 
706
- checkbutton {
707
- text 'Snowshoeing'
708
- variable <=> [@person, :snowshoeing]
852
+ frame {
853
+ checkbutton {
854
+ text 'Skiing'
855
+ variable <=> [@person, :skiing]
856
+ }
857
+
858
+ checkbutton {
859
+ text 'Snowboarding'
860
+ variable <=> [@person, :snowboarding]
861
+ }
862
+
863
+ checkbutton {
864
+ text 'Snowmobiling'
865
+ variable <=> [@person, :snowmobiling]
866
+ }
867
+
868
+ checkbutton {
869
+ text 'Snowshoeing'
870
+ variable <=> [@person, :snowshoeing]
871
+ }
709
872
  }
710
873
  }
711
874
 
@@ -732,13 +895,127 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_checkbutton'"
732
895
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
733
896
 
734
897
  ```
735
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_checkbutton.rb
898
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_checkbutton.rb
736
899
  ```
737
900
 
738
901
  Glimmer app:
739
902
 
740
903
  ![glimmer dsl tk screenshot sample hello checkbutton](images/glimmer-dsl-tk-screenshot-sample-hello-checkbutton.png)
741
904
 
905
+ ![glimmer dsl tk screenshot sample hello checkbutton](images/glimmer-dsl-tk-screenshot-sample-hello-checkbutton-all-checked.png)
906
+
907
+ ![glimmer dsl tk screenshot sample hello checkbutton](images/glimmer-dsl-tk-screenshot-sample-hello-checkbutton-none-checked.png)
908
+
909
+ ### Hello, Radiobutton!
910
+
911
+ Glimmer code (from [samples/hello/hello_radiobutton.rb](samples/hello/hello_radiobutton.rb)):
912
+
913
+ ```ruby
914
+ require 'glimmer-dsl-tk'
915
+
916
+ class HelloRadiobutton
917
+ class Person
918
+ attr_accessor :male, :female, :child, :teen, :adult, :senior
919
+
920
+ def initialize
921
+ reset!
922
+ end
923
+
924
+ def reset!
925
+ self.male = true
926
+ self.female = nil
927
+ self.child = nil
928
+ self.teen = nil
929
+ self.adult = true
930
+ self.senior = nil
931
+ end
932
+ end
933
+
934
+ include Glimmer
935
+
936
+ def initialize
937
+ @person = Person.new
938
+ end
939
+
940
+ def launch
941
+ root {
942
+ title 'Hello, Radio!'
943
+ background '#ececec' if OS.mac?
944
+
945
+ label {
946
+ text 'Gender:'
947
+ font 'caption'
948
+ }
949
+
950
+ frame {
951
+ radiobutton {
952
+ text 'Male'
953
+ variable <=> [@person, :male]
954
+ }
955
+
956
+ radiobutton {
957
+ text 'Female'
958
+ variable <=> [@person, :female]
959
+ }
960
+ }
961
+
962
+ label {
963
+ text 'Age Group:'
964
+ font 'caption'
965
+ }
966
+
967
+ frame {
968
+ radiobutton {
969
+ text 'Child'
970
+ variable <=> [@person, :child]
971
+ }
972
+
973
+ radiobutton {
974
+ text 'Teen'
975
+ variable <=> [@person, :teen]
976
+ }
977
+
978
+ radiobutton {
979
+ text 'Adult'
980
+ variable <=> [@person, :adult]
981
+ }
982
+
983
+ radiobutton {
984
+ text 'Senior'
985
+ variable <=> [@person, :senior]
986
+ }
987
+ }
988
+
989
+ button {
990
+ text 'Reset'
991
+
992
+ command do
993
+ @person.reset!
994
+ end
995
+ }
996
+ }.open
997
+ end
998
+ end
999
+
1000
+ HelloRadiobutton.new.launch
1001
+ ```
1002
+
1003
+ Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1004
+
1005
+ ```
1006
+ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_radiobutton'"
1007
+ ```
1008
+
1009
+ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1010
+
1011
+ ```
1012
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_radiobutton.rb
1013
+ ```
1014
+
1015
+ Glimmer app:
1016
+
1017
+ ![glimmer dsl tk screenshot sample hello radiobutton](images/glimmer-dsl-tk-screenshot-sample-hello-radiobutton.png)
1018
+
742
1019
  ### Hello, Frame!
743
1020
 
744
1021
  Glimmer code (from [samples/hello/hello_frame.rb](samples/hello/hello_frame.rb)):
@@ -805,7 +1082,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_frame'"
805
1082
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
806
1083
 
807
1084
  ```
808
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_frame.rb
1085
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_frame.rb
809
1086
  ```
810
1087
 
811
1088
  Glimmer app:
@@ -855,7 +1132,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_root'"
855
1132
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
856
1133
 
857
1134
  ```
858
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_root.rb
1135
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_root.rb
859
1136
  ```
860
1137
 
861
1138
  Glimmer app:
@@ -909,7 +1186,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_notebook'"
909
1186
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
910
1187
 
911
1188
  ```
912
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_notebook.rb
1189
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_notebook.rb
913
1190
  ```
914
1191
 
915
1192
  Glimmer app:
@@ -1022,7 +1299,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_label'"
1022
1299
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1023
1300
 
1024
1301
  ```
1025
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_label.rb
1302
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_label.rb
1026
1303
  ```
1027
1304
 
1028
1305
  Glimmer app:
@@ -1124,7 +1401,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_message_box'"
1124
1401
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1125
1402
 
1126
1403
  ```
1127
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_message_box.rb
1404
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_message_box.rb
1128
1405
  ```
1129
1406
 
1130
1407
  Glimmer app:
@@ -1141,12 +1418,12 @@ Glimmer code (from [samples/hello/hello_combobox.rb](samples/hello/hello_combobo
1141
1418
  root {
1142
1419
  title 'Hello, Combobox!'
1143
1420
 
1144
- combobox { |proxy|
1145
- state 'readonly'
1421
+ combobox {
1422
+ readonly true # this applies to text editing only (item selection still triggers a write to model)
1146
1423
  text <=> [person, :country]
1147
1424
  }
1148
1425
 
1149
- button { |proxy|
1426
+ button {
1150
1427
  text "Reset Selection"
1151
1428
  command {
1152
1429
  person.reset_country
@@ -1165,7 +1442,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_combobox'"
1165
1442
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1166
1443
 
1167
1444
  ```
1168
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_combobox.rb
1445
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_combobox.rb
1169
1446
  ```
1170
1447
 
1171
1448
  Glimmer app:
@@ -1205,7 +1482,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_list_single_selection'"
1205
1482
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1206
1483
 
1207
1484
  ```
1208
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_list_single_selection.rb
1485
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_list_single_selection.rb
1209
1486
  ```
1210
1487
 
1211
1488
  Glimmer app:
@@ -1243,13 +1520,302 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_list_multi_selection'"
1243
1520
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1244
1521
 
1245
1522
  ```
1246
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_list_multi_selection.rb
1523
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_list_multi_selection.rb
1247
1524
  ```
1248
1525
 
1249
1526
  Glimmer app:
1250
1527
 
1251
1528
  ![glimmer dsl tk screenshot sample hello list multi selection](images/glimmer-dsl-tk-screenshot-sample-hello-list-multi-selection.png)
1252
1529
 
1530
+ ### Hello, Entry!
1531
+
1532
+ Glimmer code (from [samples/hello/hello_entry.rb](samples/hello/hello_entry.rb)):
1533
+
1534
+ ```ruby
1535
+ require 'glimmer-dsl-tk'
1536
+
1537
+ class HelloEntry
1538
+ include Glimmer
1539
+
1540
+ attr_accessor :default, :password, :telephone, :read_only
1541
+
1542
+ def initialize
1543
+ self.default = 'default'
1544
+ self.password = 'password'
1545
+ self.telephone = '555-555-5555'
1546
+ self.read_only = 'Telephone area code is 555'
1547
+ end
1548
+
1549
+ def launch
1550
+ root {
1551
+ title 'Hello, Entry!'
1552
+
1553
+ label {
1554
+ grid sticky: 'ew'
1555
+ text 'default entry'
1556
+ }
1557
+ entry {
1558
+ grid sticky: 'ew'
1559
+ text <=> [self, :default]
1560
+ }
1561
+
1562
+ label {
1563
+ grid sticky: 'ew'
1564
+ text 'password entry'
1565
+ }
1566
+ entry {
1567
+ grid sticky: 'ew'
1568
+ show '*'
1569
+ text <=> [self, :password]
1570
+ }
1571
+
1572
+ @validated_entry_label = label {
1573
+ grid sticky: 'ew'
1574
+ text 'entry with event handlers'
1575
+ }
1576
+ entry {
1577
+ grid sticky: 'ew'
1578
+ text <=> [self, :telephone]
1579
+ validate 'key'
1580
+
1581
+ ## this event kicks in just after the user typed and before modifying the text variable
1582
+ on('validate') do |new_text_variable|
1583
+ telephone?(new_text_variable.value)
1584
+ end
1585
+
1586
+ ## this event kicks in just after the text variable is validated and before it is modified
1587
+ on('invalid') do |validate_args|
1588
+ @validated_entry_label.text = "#{validate_args.string} is not valid!"
1589
+ @validated_entry_label.foreground = 'red'
1590
+ end
1591
+
1592
+ ## this event kicks in just after the text variable is validated and modified
1593
+ on('change') do |new_text_variable|
1594
+ self.read_only = "Telephone area code is #{new_text_variable.value.gsub(/[^0-9]/, '')[0...3]}"
1595
+ @validated_entry_label.text = 'entry with event handlers'
1596
+ @validated_entry_label.foreground = nil
1597
+ end
1598
+ }
1599
+
1600
+ label {
1601
+ grid sticky: 'ew'
1602
+ text 'read-only entry'
1603
+ }
1604
+ entry {
1605
+ grid sticky: 'ew'
1606
+ text <=> [self, :read_only]
1607
+ readonly true
1608
+ }
1609
+ }.open
1610
+ end
1611
+
1612
+ def telephone?(text)
1613
+ !!text.match(/^\d{0,3}[-.\/]?\d{0,3}[-.\/]?\d{0,4}$/)
1614
+ end
1615
+ end
1616
+
1617
+ HelloEntry.new.launch
1618
+ ```
1619
+
1620
+ Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1621
+
1622
+ ```
1623
+ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_entry'"
1624
+ ```
1625
+
1626
+ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1627
+
1628
+ ```
1629
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_entry.rb
1630
+ ```
1631
+
1632
+ Glimmer app:
1633
+
1634
+ ![glimmer dsl tk screenshot sample hello entry](images/glimmer-dsl-tk-screenshot-sample-hello-entry.png)
1635
+ ![glimmer dsl tk screenshot sample hello entry validated](images/glimmer-dsl-tk-screenshot-sample-hello-entry-validated.png)
1636
+
1637
+ ### Hello, Text!
1638
+
1639
+ [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) automatically provides a `text` attribute for the `text` widget that enables updating its content simply without worrying about whether to manually insert by index, delete, or append.
1640
+
1641
+ Glimmer code (from [samples/hello/hello_text.rb](samples/hello/hello_text.rb)):
1642
+
1643
+ ```ruby
1644
+ require 'glimmer-dsl-tk'
1645
+
1646
+ class HelloText
1647
+ include Glimmer
1648
+
1649
+ COLOR_OPTIONS = %w[black purple blue green orange yellow red white].map(&:capitalize)
1650
+ FOREGROUND_PROMPT = '<select foreground>'
1651
+ BACKGROUND_PROMPT = '<select background>'
1652
+
1653
+ def initialize
1654
+ @foreground = FOREGROUND_PROMPT
1655
+ @background = BACKGROUND_PROMPT
1656
+ end
1657
+
1658
+ attr_accessor :foreground
1659
+
1660
+ def foreground_options
1661
+ [FOREGROUND_PROMPT] + COLOR_OPTIONS
1662
+ end
1663
+
1664
+ attr_accessor :background
1665
+
1666
+ def background_options
1667
+ [BACKGROUND_PROMPT] + COLOR_OPTIONS
1668
+ end
1669
+
1670
+ def launch
1671
+ root {
1672
+ title 'Hello, Text!'
1673
+
1674
+ frame {
1675
+ grid row: 0, column: 0
1676
+
1677
+ combobox {
1678
+ grid row: 0, column: 0, column_weight: 1
1679
+ readonly true
1680
+ text <=> [self, :foreground, after_write: ->(value) { @text.add_selection_format('foreground', value == FOREGROUND_PROMPT ? 'black' : value) }]
1681
+ }
1682
+
1683
+ combobox {
1684
+ grid row: 0, column: 1, column_weight: 1
1685
+ readonly true
1686
+ text <=> [self, :background, after_write: ->(value) { @text.add_selection_format('background', value == BACKGROUND_PROMPT ? 'black' : value) }]
1687
+ }
1688
+ }
1689
+
1690
+ @text = text {
1691
+ grid row: 1, column: 0, row_weight: 1
1692
+ text <<~MULTI_LINE_STRING
1693
+ According to the National Post, a heavy metal-loving high school principal in Canada will be allowed to keep her job, days after a public campaign to oust her made headlines around the globe.
1694
+
1695
+ Parents at Eden High School in St. Catharines, Ontario launched a petition to remove principal Sharon Burns after discovering she's an IRON MAIDEN fan.
1696
+
1697
+ The petition, titled "Eden High School Principal, Sharon Burns, Needs to Be Transferred Immediately!" read, "We are deeply disturbed that the principal assigned to the school blatantly showed Satanic symbols and her allegiance to Satanic practices on her public social media platforms where all the students can see them under @edenprincipal (not her personal account)."
1698
+
1699
+ More than 500 people signed the petition to transfer Burns after she posted a picture of herself flashing the "devil horns" hand sign with a doll of the MAIDEN zombie mascot Eddie behind her as well as a personalized license plate reading "IRNMADEN" and a handwritten note that reads "Eddie 666" on a car's dashboard.
1700
+
1701
+
1702
+ The number 666 is used to represent the devil, and is featured prominently in MAIDEN's artwork by the band, whose classic third album is titled "The Number Of The Beast".
1703
+
1704
+ The petition was later updated to state that the demand for her transfer is not because of her love for metal, but for "openly displaying her own handmade sign with the 666 clearly displayed on it".
1705
+
1706
+ The creator of the original petition wrote: "Sharon knows full well what she did was simply inappropriate, unnecessary and not professional but has yet to publicly admit so and is willing to allow people to believe a completely different story, making very real concerns seem petty."
1707
+
1708
+ Meanwhile, a counter-petition supporting Burns garnered over 20,000 signatures.
1709
+
1710
+ "It is ridiculous that a couple of parents judge her role as a principal only based on an Instagram post. (About liking the band IRON MAIDEN. That's it.) Eden High School is a public school. Not a Christian school," the petition titled "We need Mrs Burns" stated. "She has made Eden a safe space for so many people. She spreads nothing but love and kindness."
1711
+
1712
+ After the complaints were aired, the District School Board of Niagara spoke with Burns and the parents who launched the petition, and the issue is over as far as the board is concerned, Kim Sweeney, the board's chief communications officer, told the National Post. No disciplinary action or policy changes were needed.
1713
+
1714
+ "Our belief is that taste in music is subjective and we support that both students and staff enjoy a wide variety of genres," Sweeney said.
1715
+
1716
+ The original petition has since been removed.
1717
+ MULTI_LINE_STRING
1718
+ }
1719
+ }.open
1720
+ end
1721
+ end
1722
+
1723
+ HelloText.new.launch
1724
+ ```
1725
+
1726
+ Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1727
+
1728
+ ```
1729
+ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_text'"
1730
+ ```
1731
+
1732
+ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1733
+
1734
+ ```
1735
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_text.rb
1736
+ ```
1737
+
1738
+ Glimmer app:
1739
+
1740
+ ![glimmer dsl tk screenshot sample hello text](images/glimmer-dsl-tk-screenshot-sample-hello-text.png)
1741
+
1742
+ ### Hello, Spinbox!
1743
+
1744
+ Glimmer code (from [samples/hello/hello_spinbox.rb](samples/hello/hello_spinbox.rb)):
1745
+
1746
+ ```ruby
1747
+ require 'glimmer-dsl-tk'
1748
+
1749
+ class HelloSpinbox
1750
+ class Person
1751
+ attr_accessor :donation
1752
+ end
1753
+
1754
+ include Glimmer
1755
+
1756
+ def initialize
1757
+ @person = Person.new
1758
+ @person.donation = 5.0 # in dollars
1759
+ end
1760
+
1761
+ def launch
1762
+ root {
1763
+ title 'Hello, Spinbox!'
1764
+
1765
+ label {
1766
+ text 'Please select the amount you would like to donate to the poor:'
1767
+ }
1768
+
1769
+ frame {
1770
+ label {
1771
+ grid row: 0, column: 0
1772
+ text 'Amount:'
1773
+ font 'caption'
1774
+ }
1775
+
1776
+ label {
1777
+ grid row: 0, column: 1
1778
+ text '$'
1779
+ }
1780
+
1781
+ spinbox { |sb|
1782
+ grid row: 0, column: 2
1783
+ from 1.0 # minimum value
1784
+ to 150.0 # maximum value
1785
+ increment 5.0 # increment on up and down
1786
+ format '%0.2f'
1787
+ text <=> [@person, :donation]
1788
+ }
1789
+
1790
+ label {
1791
+ grid row: 1, column: 0, columnspan: 3
1792
+ text <=> [@person, :donation, on_read: ->(value) { "Thank you for your donation of $#{"%.2f" % value.to_f}"}]
1793
+ }
1794
+
1795
+ }
1796
+ }.open
1797
+ end
1798
+ end
1799
+
1800
+ HelloSpinbox.new.launch
1801
+ ```
1802
+
1803
+ Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1804
+
1805
+ ```
1806
+ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_spinbox'"
1807
+ ```
1808
+
1809
+ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1810
+
1811
+ ```
1812
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_spinbox.rb
1813
+ ```
1814
+
1815
+ Glimmer app:
1816
+
1817
+ ![glimmer dsl tk screenshot sample hello spinbox](images/glimmer-dsl-tk-screenshot-sample-hello-spinbox.png)
1818
+
1253
1819
  ### Hello, Computed!
1254
1820
 
1255
1821
  Glimmer code (from [samples/hello/hello_computed.rb](samples/hello/hello_computed.rb)):
@@ -1323,7 +1889,7 @@ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_computed'"
1323
1889
  Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
1324
1890
 
1325
1891
  ```
1326
- ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_computed.rb
1892
+ ruby -r ./lib/glimmer-dsl-tk.rb samples/hello/hello_computed.rb
1327
1893
  ```
1328
1894
 
1329
1895
  Glimmer app: