glimmer-dsl-tk 0.0.22 → 0.0.23

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: f1af2971637c33b4dcebacf0de9239fa24402b92325157df38453a1ba535d99c
4
- data.tar.gz: f327b2f968225d46be3768dc109aba6799ad4b00cd4c77b2584ed3729de57a7d
3
+ metadata.gz: 9d722c9396a9adb7252e4fc65c283fbf923dbe0cb93e17a9d34649ea887f5e56
4
+ data.tar.gz: 20682a6aa497800f683b87fc180754a58a96362a5a286fab3754bc38edd5d084
5
5
  SHA512:
6
- metadata.gz: a94b3eff61254b4b134cd19011c51ea1ec1ca952f6f2a753897840a0586cd39ca41483f4701a6746d8768b186a28790f6a010dfa6ba8f27d38d1698058ee11b4
7
- data.tar.gz: d0fba3f64cb7b54f94ae6c00d7d6dbe4c1fe400cbc66c15c55b3648cfa3d05b0cb2eba123e6a4a9b1e79c78e9f0c9376282a2f9829d8f95013aa9804bcc05609
6
+ metadata.gz: 77c488d614a997861369fd032fc1ebc578bee01aa8367c0fd267b99442ec462769f0218c11e236533b3443558294c2ca0940c773777698f4216df85cd1179243
7
+ data.tar.gz: 521a5c5e3db695b7938fc225619779114e32c06fa2bce870de16f233597d212b3662218a101e95921733c58f4ea02764598167eaa507835bbb25855187566b6a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.23
4
+
5
+ - Hello, Radiobutton!
6
+ - Support `radiobutton` ensuring that sibling radio buttons share the same variable to achieve mutually exclusive selection
7
+ - Improved Hello, Checkbutton! sample to demonstrate alternate checkbutton value (half-checked state)
8
+ - Support `checkbutton` with specified `onvalue` and `offvalue` (when they do not have values 1 and 0)
9
+ - Alias `root` `title` attribute as `text` & add children attribute to widgets
10
+ - Alias `notebook` `frame` `:title` as `:text`
11
+ - Alias message_box `:title` as `:text`
12
+ - Fix reference to `Glimmer::Tk::CheckbuttonProxy` (was `Glimmer::Tk::ChecktbuttonProxy`)
13
+
3
14
  ## 0.0.22
4
15
 
5
16
  - Hello, Checkbutton!
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.23
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)
@@ -88,13 +88,15 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
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
+ - [Checkbutton Data-Binding](#checkbutton-data-binding)
92
+ - [Radiobutton Data-Binding](#radiobutton-data-binding)
92
93
  - [Command Callback](#command-callback)
93
94
  - [Gotchas](#gotchas)
94
95
  - [Samples](#samples)
95
96
  - [Hello, World!](#hello-world)
96
97
  - [Hello, Button!](#hello-button)
97
98
  - [Hello, Checkbutton!](#hello-checkbutton)
99
+ - [Hello, Radiobutton!](#hello-radiobutton)
98
100
  - [Hello, Frame!](#hello-frame)
99
101
  - [Hello, Root!](#hello-root)
100
102
  - [Hello, Notebook!](#hello-notebook)
@@ -140,7 +142,7 @@ gem install glimmer-dsl-tk
140
142
 
141
143
  Add the following to `Gemfile`:
142
144
  ```
143
- gem 'glimmer-dsl-tk', '~> 0.0.21'
145
+ gem 'glimmer-dsl-tk', '~> 0.0.23'
144
146
  ```
145
147
 
146
148
  And, then run:
@@ -250,7 +252,7 @@ root {
250
252
  keyword(args) | attributes | event bindings & callbacks
251
253
  ------------- | ---------- | ---------
252
254
  `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 {}`
255
+ `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
256
  `combobox` | `state`, `text` | `'ComboboxSelected'`
255
257
  `entry` | `width`, `text` | None
256
258
  `frame(text: nil)` | `width`, `height`, `borderwidth`, `relief` (`'flat' (default), 'raised', 'sunken', 'solid', 'ridge', 'groove'`) | None
@@ -258,6 +260,7 @@ keyword(args) | attributes | event bindings & callbacks
258
260
  `list` | `selectmode`, `selection` | None
259
261
  `message_box(type: , message: , detail: , title: , icon: , default: , parent: )` | None | None
260
262
  `notebook` | None | None
263
+ `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
264
  `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'`
262
265
 
263
266
  #### Common Attributes
@@ -473,7 +476,7 @@ It automatically handles all the Tk plumbing behind the scenes.
473
476
 
474
477
  More details can be found in the [Hello, Computed!](#hello-computed) sample below.
475
478
 
476
- ### Checkbox Data-Binding
479
+ ### Checkbutton Data-Binding
477
480
 
478
481
  Example:
479
482
 
@@ -489,8 +492,36 @@ That code binds the `variable` value of the `checkbutton` to the boolean `adult`
489
492
 
490
493
  It automatically handles all the Tk plumbing behind the scenes.
491
494
 
495
+ If you need to display a half-checked `checkbutton`, bind to `alternate` attribute.
496
+
492
497
  More details can be found in the [Hello, Checkbutton!](#hello-checkbutton) sample below.
493
498
 
499
+ ### Radiobutton Data-Binding
500
+
501
+ Example:
502
+
503
+ This assumes a `Person` model with boolean `male` and `female` attributes.
504
+
505
+ ```ruby
506
+ radiobutton {
507
+ text 'Male'
508
+ variable <=> [@person, :male]
509
+ }
510
+
511
+ radiobutton {
512
+ text 'Female'
513
+ variable <=> [@person, :female]
514
+ }
515
+ ```
516
+
517
+ That code binds the `variable` value of the `radiobutton` to the boolean `male` and `female` attributes on the `person` model.
518
+
519
+ 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`.
520
+
521
+ For very rare cases, if you need to display a half-selected `radiobutton`, set `alternate` attribute as `true` when the `variable` value is `false`.
522
+
523
+ More details can be found in the [Hello, Radiobutton!](#hello-radiobutton) sample below.
524
+
494
525
  ## Command Callback
495
526
 
496
527
  `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.
@@ -657,13 +688,47 @@ require 'glimmer-dsl-tk'
657
688
 
658
689
  class HelloCheckbutton
659
690
  class Person
660
- attr_accessor :skiing, :snowboarding, :snowmobiling, :snowshoeing
691
+ attr_accessor :skiing, :snowboarding, :snowmobiling, :snowshoeing, :snow_activities, :snow_activities_alternate
661
692
 
662
693
  def initialize
663
694
  reset_activities!
695
+ individual_observer = Glimmer::DataBinding::Observer.proc do
696
+ unless @updating_group
697
+ @updating_individual = true
698
+ if skiing && snowboarding && snowmobiling && snowshoeing
699
+ self.snow_activities = true
700
+ self.snow_activities_alternate = false
701
+ elsif skiing || snowboarding || snowmobiling || snowshoeing
702
+ self.snow_activities = true
703
+ self.snow_activities_alternate = true
704
+ else
705
+ self.snow_activities = false
706
+ self.snow_activities_alternate = false
707
+ end
708
+ @updating_individual = false
709
+ end
710
+ end
711
+ individual_observer.observe(self, :skiing)
712
+ individual_observer.observe(self, :snowboarding)
713
+ individual_observer.observe(self, :snowmobiling)
714
+ individual_observer.observe(self, :snowshoeing)
715
+
716
+ group_observer = Glimmer::DataBinding::Observer.proc do
717
+ unless @updating_individual
718
+ @updating_group = true
719
+ self.skiing = self.snow_activities
720
+ self.snowboarding = self.snow_activities
721
+ self.snowmobiling = self.snow_activities
722
+ self.snowshoeing = self.snow_activities
723
+ @updating_group = false
724
+ end
725
+ end
726
+ group_observer.observe(self, :snow_activities)
664
727
  end
665
728
 
666
729
  def reset_activities!
730
+ self.snow_activities = true
731
+ self.snow_activities_alternate = true
667
732
  self.skiing = false
668
733
  self.snowboarding = true
669
734
  self.snowmobiling = false
@@ -689,23 +754,31 @@ class HelloCheckbutton
689
754
 
690
755
  frame {
691
756
  checkbutton {
692
- text 'Skiing'
693
- variable <=> [@person, :skiing]
757
+ text 'Snow Activities'
758
+ variable <=> [@person, :snow_activities]
759
+ alternate <=> [@person, :snow_activities_alternate] # binds half-checked state
694
760
  }
695
761
 
696
- checkbutton {
697
- text 'Snowboarding'
698
- variable <=> [@person, :snowboarding]
699
- }
700
-
701
- checkbutton {
702
- text 'Snowmobiling'
703
- variable <=> [@person, :snowmobiling]
704
- }
705
-
706
- checkbutton {
707
- text 'Snowshoeing'
708
- variable <=> [@person, :snowshoeing]
762
+ frame {
763
+ checkbutton {
764
+ text 'Skiing'
765
+ variable <=> [@person, :skiing]
766
+ }
767
+
768
+ checkbutton {
769
+ text 'Snowboarding'
770
+ variable <=> [@person, :snowboarding]
771
+ }
772
+
773
+ checkbutton {
774
+ text 'Snowmobiling'
775
+ variable <=> [@person, :snowmobiling]
776
+ }
777
+
778
+ checkbutton {
779
+ text 'Snowshoeing'
780
+ variable <=> [@person, :snowshoeing]
781
+ }
709
782
  }
710
783
  }
711
784
 
@@ -739,6 +812,120 @@ Glimmer app:
739
812
 
740
813
  ![glimmer dsl tk screenshot sample hello checkbutton](images/glimmer-dsl-tk-screenshot-sample-hello-checkbutton.png)
741
814
 
815
+ ![glimmer dsl tk screenshot sample hello checkbutton](images/glimmer-dsl-tk-screenshot-sample-hello-checkbutton-all-checked.png)
816
+
817
+ ![glimmer dsl tk screenshot sample hello checkbutton](images/glimmer-dsl-tk-screenshot-sample-hello-checkbutton-none-checked.png)
818
+
819
+ ### Hello, Radiobutton!
820
+
821
+ Glimmer code (from [samples/hello/hello_radiobutton.rb](samples/hello/hello_radiobutton.rb)):
822
+
823
+ ```ruby
824
+ require 'glimmer-dsl-tk'
825
+
826
+ class HelloRadiobutton
827
+ class Person
828
+ attr_accessor :male, :female, :child, :teen, :adult, :senior
829
+
830
+ def initialize
831
+ reset!
832
+ end
833
+
834
+ def reset!
835
+ self.male = true
836
+ self.female = nil
837
+ self.child = nil
838
+ self.teen = nil
839
+ self.adult = true
840
+ self.senior = nil
841
+ end
842
+ end
843
+
844
+ include Glimmer
845
+
846
+ def initialize
847
+ @person = Person.new
848
+ end
849
+
850
+ def launch
851
+ root {
852
+ title 'Hello, Radio!'
853
+ background '#ececec' if OS.mac?
854
+
855
+ label {
856
+ text 'Gender:'
857
+ font 'caption'
858
+ }
859
+
860
+ frame {
861
+ radiobutton {
862
+ text 'Male'
863
+ variable <=> [@person, :male]
864
+ }
865
+
866
+ radiobutton {
867
+ text 'Female'
868
+ variable <=> [@person, :female]
869
+ }
870
+ }
871
+
872
+ label {
873
+ text 'Age Group:'
874
+ font 'caption'
875
+ }
876
+
877
+ frame {
878
+ radiobutton {
879
+ text 'Child'
880
+ variable <=> [@person, :child]
881
+ }
882
+
883
+ radiobutton {
884
+ text 'Teen'
885
+ variable <=> [@person, :teen]
886
+ }
887
+
888
+ radiobutton {
889
+ text 'Adult'
890
+ variable <=> [@person, :adult]
891
+ }
892
+
893
+ radiobutton {
894
+ text 'Senior'
895
+ variable <=> [@person, :senior]
896
+ }
897
+ }
898
+
899
+ button {
900
+ text 'Reset'
901
+
902
+ command do
903
+ @person.reset!
904
+ end
905
+ }
906
+ }.open
907
+ end
908
+ end
909
+
910
+ HelloRadiobutton.new.launch
911
+ ```
912
+
913
+ Run with [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
914
+
915
+ ```
916
+ ruby -r glimmer-dsl-tk -e "require 'samples/hello/hello_radiobutton'"
917
+ ```
918
+
919
+ Alternatively, run from cloned project without [glimmer-dsl-tk](https://rubygems.org/gems/glimmer-dsl-tk) gem installed:
920
+
921
+ ```
922
+ ruby -r ./lib/glimmer-dsl-tk.rb ./samples/hello/hello_radiobutton.rb
923
+ ```
924
+
925
+ Glimmer app:
926
+
927
+ ![glimmer dsl tk screenshot sample hello radiobutton](images/glimmer-dsl-tk-screenshot-sample-hello-radiobutton.png)
928
+
742
929
  ### Hello, Frame!
743
930
 
744
931
  Glimmer code (from [samples/hello/hello_frame.rb](samples/hello/hello_frame.rb)):
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.22
1
+ 0.0.23
Binary file
@@ -27,7 +27,10 @@ module Glimmer
27
27
  module Tk
28
28
  class MessageBoxExpression < StaticExpression
29
29
  def interpret(parent, keyword, *args, &block)
30
- args.first[:parent] = args.first[:parent].tk if args.first.is_a?(Hash) && args.first[:parent].is_a?(Glimmer::Tk::RootProxy)
30
+ if args.first.is_a?(Hash)
31
+ args.first[:parent] = args.first[:parent].tk if args.first[:parent].is_a?(Glimmer::Tk::RootProxy)
32
+ args.first[:title] = args.first.delete(:text) if args.first.keys.include?(:text)
33
+ end
31
34
  ::Tk::messageBox(*args)
32
35
  end
33
36
  end
@@ -52,10 +52,3 @@ module Glimmer
52
52
  end
53
53
 
54
54
  require 'glimmer/tk/widget_proxy'
55
- require 'glimmer/tk/notebook_proxy'
56
- require 'glimmer/tk/frame_proxy'
57
- require 'glimmer/tk/button_proxy'
58
- require 'glimmer/tk/label_proxy'
59
- require 'glimmer/tk/list_proxy'
60
- require 'glimmer/tk/entry_proxy'
61
- require 'glimmer/tk/treeview_proxy'
@@ -20,6 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/tk/widget_proxy'
23
+ require 'glimmer/tk/commandable'
23
24
 
24
25
  module Glimmer
25
26
  module Tk
@@ -27,20 +28,7 @@ module Glimmer
27
28
  #
28
29
  # Follows the Proxy Design Pattern
29
30
  class ButtonProxy < WidgetProxy
30
- # TODO extract to a module
31
-
32
- def command_block=(proc)
33
- tk.command(proc)
34
- end
35
-
36
- def handle_listener(listener_name, &listener)
37
- case listener_name.to_s.downcase
38
- when 'command'
39
- command(listener)
40
- else
41
- super
42
- end
43
- end
31
+ include Commandable
44
32
  end
45
33
  end
46
34
  end
@@ -20,25 +20,17 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/tk/widget_proxy'
23
+ require 'glimmer/tk/commandable'
24
+ require 'glimmer/tk/variable_owner'
23
25
 
24
26
  module Glimmer
25
27
  module Tk
26
28
  # Proxy for Tk::Tile::Checkbutton
27
29
  #
28
30
  # Follows the Proxy Design Pattern
29
- class ChecktbuttonProxy < WidgetProxy
30
- def command_block=(proc)
31
- tk.command(proc)
32
- end
33
-
34
- def handle_listener(listener_name, &listener)
35
- case listener_name.to_s.downcase
36
- when 'command'
37
- command(listener)
38
- else
39
- super
40
- end
41
- end
31
+ class CheckbuttonProxy < WidgetProxy
32
+ include Commandable
33
+ include VariableOwner
42
34
  end
43
35
  end
44
36
  end
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2020-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/tk/widget_proxy'
23
+ require 'glimmer/tk/text_variable_owner'
24
+
25
+ module Glimmer
26
+ module Tk
27
+ # Proxy for Tk::Tile::Combobox
28
+ #
29
+ # Follows the Proxy Design Pattern
30
+ class ComboboxProxy < WidgetProxy
31
+ include TextVariableOwner
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2020-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/tk/widget_proxy'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ # Represents widgets that can invoke a command
27
+ module Commandable
28
+ def command_block=(proc)
29
+ tk.command(proc)
30
+ end
31
+
32
+ def handle_listener(listener_name, &listener)
33
+ case listener_name.to_s.downcase
34
+ when 'command'
35
+ command(listener)
36
+ else
37
+ super
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -20,6 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/tk/widget_proxy'
23
+ require 'glimmer/tk/text_variable_owner'
23
24
 
24
25
  module Glimmer
25
26
  module Tk
@@ -27,6 +28,8 @@ module Glimmer
27
28
  #
28
29
  # Follows the Proxy Design Pattern
29
30
  class EntryProxy < WidgetProxy
31
+ include TextVariableOwner
32
+
30
33
  def validatecommand_block=(proc)
31
34
  tk.validatecommand(proc)
32
35
  end
@@ -33,6 +33,7 @@ module Glimmer
33
33
  if parent_proxy.is_a?(NotebookProxy)
34
34
  @tab_options, args[0] = args[0].to_h.partition {|key, value| NotebookProxy::TAB_OPTIONS.include?(key.to_s)}
35
35
  @tab_options = Hash[@tab_options]
36
+ @tab_options[:text] = @tab_options.delete(:title) if @tab_options.keys.include?(:title)
36
37
  args.delete_at(0) if args[0].to_a.empty?
37
38
  end
38
39
  super
@@ -20,6 +20,7 @@
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  require 'glimmer/tk/widget_proxy'
23
+ require 'glimmer/tk/text_variable_owner'
23
24
 
24
25
  module Glimmer
25
26
  module Tk
@@ -27,6 +28,8 @@ module Glimmer
27
28
  #
28
29
  # Follows the Proxy Design Pattern
29
30
  class LabelProxy < WidgetProxy
31
+ include TextVariableOwner
32
+
30
33
  def set_attribute(attribute, *args)
31
34
  if attribute.to_s == 'font'
32
35
  args[0] = "tk_#{args[0]}_font".camelcase(:upper) if (args[0].is_a?(Symbol) || args[0].is_a?(String)) && args[0].to_s == args[0].to_s.downcase
@@ -27,17 +27,12 @@ module Glimmer
27
27
  #
28
28
  # Follows the Proxy Design Pattern
29
29
  class NotebookProxy < WidgetProxy
30
- TAB_OPTIONS = ['state', 'sticky', 'padding', 'text', 'image', 'compound', 'underline']
30
+ TAB_OPTIONS = ['state', 'sticky', 'padding', 'text', 'title', 'image', 'compound', 'underline']
31
31
 
32
- attr_reader :tab_proxies
33
-
34
- def initialize(*args)
35
- @tab_proxies = []
36
- super
37
- end
32
+ alias tab_proxies children
38
33
 
39
34
  def post_initialize_child(child)
40
- @tab_proxies << child
35
+ super
41
36
  @tk.add child.tk, child.tab_options
42
37
  end
43
38
  end
@@ -0,0 +1,46 @@
1
+ # Copyright (c) 2020-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/tk/widget_proxy'
23
+ require 'glimmer/tk/commandable'
24
+
25
+ module Glimmer
26
+ module Tk
27
+ # Proxy for Tk::Tile::Radiobutton
28
+ #
29
+ # Follows the Proxy Design Pattern
30
+ class RadiobuttonProxy < WidgetProxy
31
+ include Commandable
32
+
33
+ def sibling_radio_buttons
34
+ @parent_proxy.children.select {|child| child.is_a?(RadiobuttonProxy)}
35
+ end
36
+
37
+ private
38
+
39
+ def initialize_defaults
40
+ super
41
+ sibling_variable = sibling_radio_buttons.map(&:tk).map(&:variable).compact.first
42
+ tk.variable = sibling_variable.nil? ? ::TkVariable.new : sibling_variable
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2020-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
+ module Glimmer
23
+ module Tk
24
+ module TextVariableOwner
25
+ def initialize_defaults
26
+ super
27
+ tk.textvariable = ::TkVariable.new
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2020-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
+ module Glimmer
23
+ module Tk
24
+ module VariableOwner
25
+ def initialize_defaults
26
+ super
27
+ tk.variable = ::TkVariable.new
28
+ end
29
+ end
30
+ end
31
+ end
@@ -26,8 +26,8 @@ module Glimmer
26
26
  # Follows the Proxy Design Pattern
27
27
  class WidgetProxy
28
28
  class << self
29
- def create(keyword, parent, args)
30
- widget_proxy_class(keyword).new(keyword, parent, args)
29
+ def create(keyword, parent, args, &block)
30
+ widget_proxy_class(keyword).new(keyword, parent, args, &block)
31
31
  end
32
32
 
33
33
  def widget_proxy_class(keyword)
@@ -61,41 +61,31 @@ module Glimmer
61
61
  end
62
62
  end
63
63
 
64
- attr_reader :parent_proxy, :tk, :args, :keyword
64
+ attr_reader :parent_proxy, :tk, :args, :keyword, :children
65
65
 
66
- DEFAULT_INITIALIZERS = {
67
- 'checkbutton' => lambda do |tk|
68
- tk.variable = ::TkVariable.new
69
- end,
70
- 'combobox' => lambda do |tk|
71
- tk.textvariable = ::TkVariable.new
72
- end,
73
- 'label' => lambda do |tk|
74
- tk.textvariable = ::TkVariable.new
75
- end,
76
- 'entry' => lambda do |tk|
77
- tk.textvariable = ::TkVariable.new
78
- end,
79
- }
80
-
81
66
  # Initializes a new Tk Widget
82
67
  #
83
68
  # Styles is a comma separate list of symbols representing Tk styles in lower case
84
- def initialize(underscored_widget_name, parent_proxy, args)
69
+ def initialize(underscored_widget_name, parent_proxy, args, &block)
85
70
  @parent_proxy = parent_proxy
86
71
  @args = args
87
72
  @keyword = underscored_widget_name
73
+ @block = block
88
74
  tk_widget_class = self.class.tk_widget_class_for(underscored_widget_name)
89
75
  @tk = tk_widget_class.new(@parent_proxy.tk, *args)
90
76
  # a common widget initializer
91
- @tk.grid unless @tk.is_a?(::Tk::Toplevel)
92
- DEFAULT_INITIALIZERS[underscored_widget_name]&.call(@tk)
77
+ initialize_defaults
93
78
  @parent_proxy.post_initialize_child(self)
79
+ post_add_content if @block.nil?
80
+ end
81
+
82
+ def children
83
+ @children ||= []
94
84
  end
95
85
 
96
86
  # Subclasses may override to perform post initialization work on an added child
97
87
  def post_initialize_child(child)
98
- # No Op by default
88
+ children << child
99
89
  end
100
90
 
101
91
  # Subclasses may override to perform post add_content work
@@ -208,6 +198,7 @@ module Glimmer
208
198
  end
209
199
 
210
200
  def widget_custom_attribute_mapping
201
+ # TODO consider extracting to modules/subclasses
211
202
  @widget_custom_attribute_mapping ||= {
212
203
  ::Tk::Tile::TButton => {
213
204
  'image' => {
@@ -221,10 +212,24 @@ module Glimmer
221
212
  setter: {name: 'image=', invoker: lambda { |widget, args| @tk.image = image_argument(args) }},
222
213
  },
223
214
  'variable' => {
224
- getter: {name: 'variable', invoker: lambda { |widget, args| @tk.variable&.value.to_i == 1 }},
215
+ getter: {name: 'variable', invoker: lambda { |widget, args| @tk.variable&.value.to_s == @tk.onvalue.to_s }},
225
216
  setter: {name: 'variable=', invoker: lambda { |widget, args| @tk.variable&.value = args.first.is_a?(Integer) ? args.first : (args.first ? 1 : 0) }},
226
217
  },
227
218
  },
219
+ ::Tk::Tile::TRadiobutton => {
220
+ 'image' => {
221
+ getter: {name: 'image', invoker: lambda { |widget, args| @tk.image }},
222
+ setter: {name: 'image=', invoker: lambda { |widget, args| @tk.image = image_argument(args) }},
223
+ },
224
+ 'text' => {
225
+ getter: {name: 'text', invoker: lambda { |widget, args| @tk.text }},
226
+ setter: {name: 'text=', invoker: lambda { |widget, args| @tk.value = @tk.text = args.first }},
227
+ },
228
+ 'variable' => {
229
+ getter: {name: 'variable', invoker: lambda { |widget, args| @tk.variable&.value == @tk.value }},
230
+ setter: {name: 'variable=', invoker: lambda { |widget, args| @tk.variable&.value = args.first ? @tk.value : @tk.variable&.value }},
231
+ },
232
+ },
228
233
  ::Tk::Tile::TCombobox => {
229
234
  'text' => {
230
235
  getter: {name: 'text', invoker: lambda { |widget, args| @tk.textvariable&.value }},
@@ -247,15 +252,22 @@ module Glimmer
247
252
  setter: {name: 'text=', invoker: lambda { |widget, args| @tk.textvariable&.value = args.first unless @text_variable_edit }},
248
253
  },
249
254
  },
255
+ ::Tk::Root => {
256
+ 'text' => {
257
+ getter: {name: 'text', invoker: lambda { |widget, args| @tk.title }},
258
+ setter: {name: 'text=', invoker: lambda { |widget, args| @tk.title = args.first }},
259
+ },
260
+ },
250
261
  }
251
262
  end
252
263
 
253
264
  def widget_attribute_listener_installers
265
+ # TODO consider extracting to modules/subclasses
254
266
  @tk_widget_attribute_listener_installers ||= {
255
267
  ::Tk::Tile::TCheckbutton => {
256
268
  'variable' => lambda do |observer|
257
269
  @tk.command {
258
- observer.call(@tk.variable.value.to_i == 1)
270
+ observer.call(@tk.variable.value.to_s == @tk.onvalue.to_s)
259
271
  }
260
272
  end,
261
273
  },
@@ -286,6 +298,14 @@ module Glimmer
286
298
  }
287
299
  end,
288
300
  },
301
+ ::Tk::Tile::TRadiobutton => {
302
+ 'variable' => lambda do |observer|
303
+ @tk.command {
304
+ pd @tk.variable.value, @tk.value
305
+ observer.call(@tk.variable.value == @tk.value)
306
+ }
307
+ end,
308
+ },
289
309
  }
290
310
  end
291
311
 
@@ -345,6 +365,14 @@ module Glimmer
345
365
  super ||
346
366
  tk.respond_to?(method, *args, &block)
347
367
  end
368
+
369
+ private
370
+
371
+ def initialize_defaults
372
+ @tk.grid unless @tk.is_a?(::Tk::Toplevel)
373
+ end
348
374
  end
349
375
  end
350
376
  end
377
+
378
+ Dir[File.expand_path('./*_proxy.rb', __dir__)].each {|f| require f}
@@ -23,13 +23,47 @@ require 'glimmer-dsl-tk'
23
23
 
24
24
  class HelloCheckbutton
25
25
  class Person
26
- attr_accessor :skiing, :snowboarding, :snowmobiling, :snowshoeing
26
+ attr_accessor :skiing, :snowboarding, :snowmobiling, :snowshoeing, :snow_activities, :snow_activities_alternate
27
27
 
28
28
  def initialize
29
29
  reset_activities!
30
+ individual_observer = Glimmer::DataBinding::Observer.proc do
31
+ unless @updating_group
32
+ @updating_individual = true
33
+ if skiing && snowboarding && snowmobiling && snowshoeing
34
+ self.snow_activities = true
35
+ self.snow_activities_alternate = false
36
+ elsif skiing || snowboarding || snowmobiling || snowshoeing
37
+ self.snow_activities = true
38
+ self.snow_activities_alternate = true
39
+ else
40
+ self.snow_activities = false
41
+ self.snow_activities_alternate = false
42
+ end
43
+ @updating_individual = false
44
+ end
45
+ end
46
+ individual_observer.observe(self, :skiing)
47
+ individual_observer.observe(self, :snowboarding)
48
+ individual_observer.observe(self, :snowmobiling)
49
+ individual_observer.observe(self, :snowshoeing)
50
+
51
+ group_observer = Glimmer::DataBinding::Observer.proc do
52
+ unless @updating_individual
53
+ @updating_group = true
54
+ self.skiing = self.snow_activities
55
+ self.snowboarding = self.snow_activities
56
+ self.snowmobiling = self.snow_activities
57
+ self.snowshoeing = self.snow_activities
58
+ @updating_group = false
59
+ end
60
+ end
61
+ group_observer.observe(self, :snow_activities)
30
62
  end
31
63
 
32
64
  def reset_activities!
65
+ self.snow_activities = true
66
+ self.snow_activities_alternate = true
33
67
  self.skiing = false
34
68
  self.snowboarding = true
35
69
  self.snowmobiling = false
@@ -55,23 +89,31 @@ class HelloCheckbutton
55
89
 
56
90
  frame {
57
91
  checkbutton {
58
- text 'Skiing'
59
- variable <=> [@person, :skiing]
60
- }
61
-
62
- checkbutton {
63
- text 'Snowboarding'
64
- variable <=> [@person, :snowboarding]
92
+ text 'Snow Activities'
93
+ variable <=> [@person, :snow_activities]
94
+ alternate <=> [@person, :snow_activities_alternate] # binds half-checked state
65
95
  }
66
96
 
67
- checkbutton {
68
- text 'Snowmobiling'
69
- variable <=> [@person, :snowmobiling]
70
- }
71
-
72
- checkbutton {
73
- text 'Snowshoeing'
74
- variable <=> [@person, :snowshoeing]
97
+ frame {
98
+ checkbutton {
99
+ text 'Skiing'
100
+ variable <=> [@person, :skiing]
101
+ }
102
+
103
+ checkbutton {
104
+ text 'Snowboarding'
105
+ variable <=> [@person, :snowboarding]
106
+ }
107
+
108
+ checkbutton {
109
+ text 'Snowmobiling'
110
+ variable <=> [@person, :snowmobiling]
111
+ }
112
+
113
+ checkbutton {
114
+ text 'Snowshoeing'
115
+ variable <=> [@person, :snowshoeing]
116
+ }
75
117
  }
76
118
  }
77
119
 
@@ -0,0 +1,87 @@
1
+ require 'glimmer-dsl-tk'
2
+
3
+ class HelloRadiobutton
4
+ class Person
5
+ attr_accessor :male, :female, :child, :teen, :adult, :senior
6
+
7
+ def initialize
8
+ reset!
9
+ end
10
+
11
+ def reset!
12
+ self.male = true
13
+ self.female = nil
14
+ self.child = nil
15
+ self.teen = nil
16
+ self.adult = true
17
+ self.senior = nil
18
+ end
19
+ end
20
+
21
+ include Glimmer
22
+
23
+ def initialize
24
+ @person = Person.new
25
+ end
26
+
27
+ def launch
28
+ root {
29
+ title 'Hello, Radio!'
30
+ background '#ececec' if OS.mac?
31
+
32
+ label {
33
+ text 'Gender:'
34
+ font 'caption'
35
+ }
36
+
37
+ frame {
38
+ radiobutton {
39
+ text 'Male'
40
+ variable <=> [@person, :male]
41
+ }
42
+
43
+ radiobutton {
44
+ text 'Female'
45
+ variable <=> [@person, :female]
46
+ }
47
+ }
48
+
49
+ label {
50
+ text 'Age Group:'
51
+ font 'caption'
52
+ }
53
+
54
+ frame {
55
+ radiobutton {
56
+ text 'Child'
57
+ variable <=> [@person, :child]
58
+ }
59
+
60
+ radiobutton {
61
+ text 'Teen'
62
+ variable <=> [@person, :teen]
63
+ }
64
+
65
+ radiobutton {
66
+ text 'Adult'
67
+ variable <=> [@person, :adult]
68
+ }
69
+
70
+ radiobutton {
71
+ text 'Senior'
72
+ variable <=> [@person, :senior]
73
+ }
74
+ }
75
+
76
+ button {
77
+ text 'Reset'
78
+
79
+ command do
80
+ @person.reset!
81
+ end
82
+ }
83
+ }.open
84
+ end
85
+ end
86
+
87
+ HelloRadiobutton.new.launch
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.22
4
+ version: 0.0.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
@@ -224,13 +224,18 @@ files:
224
224
  - lib/glimmer/dsl/tk/widget_expression.rb
225
225
  - lib/glimmer/tk/button_proxy.rb
226
226
  - lib/glimmer/tk/checkbutton_proxy.rb
227
+ - lib/glimmer/tk/combobox_proxy.rb
228
+ - lib/glimmer/tk/commandable.rb
227
229
  - lib/glimmer/tk/entry_proxy.rb
228
230
  - lib/glimmer/tk/frame_proxy.rb
229
231
  - lib/glimmer/tk/label_proxy.rb
230
232
  - lib/glimmer/tk/list_proxy.rb
231
233
  - lib/glimmer/tk/notebook_proxy.rb
234
+ - lib/glimmer/tk/radiobutton_proxy.rb
232
235
  - lib/glimmer/tk/root_proxy.rb
236
+ - lib/glimmer/tk/text_variable_owner.rb
233
237
  - lib/glimmer/tk/treeview_proxy.rb
238
+ - lib/glimmer/tk/variable_owner.rb
234
239
  - lib/glimmer/tk/widget_proxy.rb
235
240
  - samples/hello/hello_button.rb
236
241
  - samples/hello/hello_checkbutton.rb
@@ -243,6 +248,7 @@ files:
243
248
  - samples/hello/hello_list_single_selection.rb
244
249
  - samples/hello/hello_message_box.rb
245
250
  - samples/hello/hello_notebook.rb
251
+ - samples/hello/hello_radiobutton.rb
246
252
  - samples/hello/hello_root.rb
247
253
  - samples/hello/hello_world.rb
248
254
  - samples/hello/images/denmark.png