glimmer-dsl-tk 0.0.22 → 0.0.23

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