glimmer-dsl-tk 0.0.44 → 0.0.45

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: 5cb173f133301f49a6f4ddfc86578e450b563ff842b96274b6003b784b2e8acb
4
- data.tar.gz: 810087c40f044768c6394a968b945fdc2e3c4c0d1eb8caac2b3421259c431d61
3
+ metadata.gz: 0a9655c46ab2b4638e96077e0795a6b7201456baf020ade27838d139797d3a44
4
+ data.tar.gz: dc2b2924a180df216a16161aa938b4429f814a59f18e0fba945b73eb40513bd6
5
5
  SHA512:
6
- metadata.gz: 8842b20e509fd9c0f918953942665ac5a0609cbc91b0faf020c808e736890e1d2617abb579b384696711ecb0d40bf7ab82a5a0e669a1ff878bede9ed061c6abb
7
- data.tar.gz: 983740e737d7e066f56411ddea5ab7ab607bf196579d519e41aea07bd4c5e8d24b2dcd178086a3d8f35aa8e6ae7b0b8995cb27e3846516887ad4908e07758847
6
+ metadata.gz: cab872767a730b059ebdaee18a124f0ded5e9fa0d5f980592b2c9fc9a20d756894846a4662b1f20043108987424daf6b79f895df639d1e273b66cad90f8437ae
7
+ data.tar.gz: 5a92bbe321b0ca538fbebc84d5e076047b2a761294f47be236f041853873c60787ce593dd142e7a5ba9671b9cdc7faaf1ca6d9f41c9a45fed1dde8cc55b5f184
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.45
4
+
5
+ - Support `lbl` widget as the non-tile-themed version of `label` (i.e. `::TkLabel` not `::Tk::Tile::TLabel`)
6
+ - Add `#proxy` method to all Tk widgets to return Glimmer widget proxy objects (e.g. `Tk::Tile::TButton#proxy` returns `Glimmer::Tk::WidgetProxy` object)
7
+ - Provide question mark alias of `event.drop_accepted` (i.e. `drop_accepted?`)
8
+ - Have `DragAndDropEvent` `source`/`target` be the enhanced Glimmer widget proxy instead of the unenhanced Tk widget
9
+ - Look into improving code that uses `TkLabel` explicitly in Hello, Drag and Drop! (do `event.tooltip.content {label {...} }` with Glimmer DSL instead)
10
+ - Add Glimmer Style Guide
11
+ - Fix issue with dropping button and list unto checkbox in Hello, Drag and Drop!
12
+
3
13
  ## 0.0.44
4
14
 
5
15
  - Fix issue with not being able to drop list into checkbox in Hello, Drag and Drop! by disabling functionality for list just like button
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.44
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.45
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)
@@ -100,6 +100,7 @@ Other [Glimmer](https://github.com/AndyObtiva/glimmer) DSL gems:
100
100
  - [Radiobutton Data-Binding](#radiobutton-data-binding)
101
101
  - [Command Callback](#command-callback)
102
102
  - [Gotchas](#gotchas)
103
+ - [Glimmer Style Guide](#glimmer-style-guide)
103
104
  - [Samples](#samples)
104
105
  - [Hello, World!](#hello-world)
105
106
  - [Hello, Button!](#hello-button)
@@ -181,7 +182,7 @@ gem install glimmer-dsl-tk
181
182
 
182
183
  Add the following to `Gemfile`:
183
184
  ```
184
- gem 'glimmer-dsl-tk', '0.0.44'
185
+ gem 'glimmer-dsl-tk', '0.0.45'
185
186
  ```
186
187
 
187
188
  And, then run:
@@ -225,6 +226,8 @@ The Glimmer GUI DSL follows these simple concepts in mapping from Tk syntax:
225
226
  - **Content/Options Block**: Any keyword may optionally be followed by a Ruby curly-brace block containing nested widgets (content) and attributes (options). Attributes are simply Tk option keywords followed by arguments and no block (e.g. `title 'Hello, World!'` under a `root`)
226
227
  - **Event Binding Block**: `on(event) {}` keyword receiving a Tk binding event name (e.g. `KeyPress` or `ComboboxSelected`). Surrounding event by `<>` is optional as [Glimmer DSL for Tk](https://rubygems.org/gems/glimmer-dsl-tk) can take care of that automatically.
227
228
 
229
+ Note that Glimmer widgets are proxy objects (wrappers) for Tk widgets. To get wrapped Tk widget from a Glimmer widget, you simply invoke `#tk` method. To get the proxy of a wrapped Tk widget, you may invoke `#proxy` method.
230
+
228
231
  Example of an app written in [Tk](https://www.tcl.tk/) imperative syntax:
229
232
 
230
233
  ```ruby
@@ -303,6 +306,7 @@ keyword(args) | attributes | event bindings & callbacks
303
306
  `spinbox` | `text`, `from`, `to`, `increment`, `format`, [more attributes](https://tcl.tk/man/tcl8.6/TkCmd/text.htm#M116) | `command {}`, `'increment'`, `'decrement'`
304
307
  `frame(text: nil)` | `width`, `height`, `borderwidth`, `relief` (`'flat' (default), 'raised', 'sunken', 'solid', 'ridge', 'groove'`) | None
305
308
  `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
309
+ `lbl` (non-theme version of `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`, `bg`, `bitmap`, [more here](https://tcl.tk/man/tcl8.6/TkCmd/label.htm) | None
306
310
  `list` | `selectmode`, `selection` | None
307
311
  `message_box(type: , message: , detail: , title: , icon: , default: , parent: )` | None | None
308
312
  `menu(label: nil) (label is nil if nested under root/toplevel for menu bar)` | None | None
@@ -824,6 +828,14 @@ More details can be found in the [Hello, Button!](#hello-button) sample below.
824
828
 
825
829
  - Setting `background` attribute on `frame` or `label` does not work in `'aqua'` theme on the Mac (only in `'classic'` theme)
826
830
 
831
+ ## Glimmer Style Guide
832
+
833
+ - Widget arguments are always wrapped by parentheses.
834
+ - Widget blocks are always declared with curly braces `{}` to clearly visualize hierarchical view code and separate from logic code.
835
+ - Widget attribute declarations always have arguments that are never wrapped inside parentheses and never take a block.
836
+ - Widget listeners are always declared with `on` keyword receiving listener event name as an argument. Their multi-line blocks have a `do; end` style to distinguish as logic from widget keywords and attributes.
837
+ - Pure logic multi-line blocks that do not constitute GUI DSL view elements in general always have `do; end` style to clearly separate logic code from view code.
838
+
827
839
  ## Samples
828
840
 
829
841
  The easiest way to run samples is by launching the Glimmer Meta-Sample (the Sample of Samples).
@@ -2699,27 +2711,39 @@ root {
2699
2711
 
2700
2712
  label {
2701
2713
  grid :row => 0, :column => 0
2702
- text "Entry"
2714
+ text "Label"
2715
+ }
2716
+ label {
2717
+ grid :row => 0, :column => 1, :pady => 10, :sticky => "e"
2718
+ text "Drag label text"
2719
+ width 30
2720
+ drag_source true
2703
2721
  }
2704
2722
 
2723
+ label {
2724
+ grid :row => 1, :column => 0
2725
+ text "Entry"
2726
+ }
2705
2727
  entry {
2706
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
2728
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
2707
2729
  text "Drag entry text"
2708
2730
  width 30
2709
2731
 
2732
+ # This is how to do `drag_source true` the manual way for use in exceptional cases
2710
2733
  on_drag_start do |event|
2711
- event.data = event.source.textvariable&.value
2734
+ event.data = event.source.text
2712
2735
  event.source.configure(:cursor => "hand2")
2713
- TkLabel.new(event.tooltip) {
2714
- text event.data + " "
2715
- bg "yellow"
2716
- bitmap "warning"
2717
- compound "right"
2718
- }.pack
2736
+ event.tooltip.content {
2737
+ lbl { # non-tile-theme version of label
2738
+ text event.data + " "
2739
+ bg "yellow"
2740
+ bitmap "warning"
2741
+ compound "right"
2742
+ }
2743
+ }
2719
2744
  end
2720
-
2721
2745
  on_drag_motion do |event|
2722
- if event.drop_accepted
2746
+ if event.drop_accepted?
2723
2747
  event.source.configure(:cursor => "hand1")
2724
2748
  else
2725
2749
  event.source.configure(:cursor => "hand2")
@@ -2728,23 +2752,10 @@ root {
2728
2752
  end
2729
2753
  }
2730
2754
 
2731
- label {
2732
- grid :row => 1, :column => 0
2733
- text "Label"
2734
- }
2735
-
2736
- label {
2737
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
2738
- text "Drag label text"
2739
- width 30
2740
- drag_source true
2741
- }
2742
-
2743
2755
  label {
2744
2756
  grid :row => 2, :column => 0
2745
2757
  text "Combobox"
2746
2758
  }
2747
-
2748
2759
  combobox {
2749
2760
  grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
2750
2761
  text "Spain"
@@ -2752,7 +2763,7 @@ root {
2752
2763
  width 27
2753
2764
 
2754
2765
  on_drag_start do |event|
2755
- event.data = event.source.textvariable&.value
2766
+ event.data = event.source.text
2756
2767
  end
2757
2768
  }
2758
2769
 
@@ -2760,8 +2771,7 @@ root {
2760
2771
  grid :row => 3, :column => 0
2761
2772
  text 'List'
2762
2773
  }
2763
-
2764
- country_list = list {
2774
+ list {
2765
2775
  grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
2766
2776
  selectmode 'browse'
2767
2777
  items %w[USA Canada Mexico]
@@ -2769,7 +2779,7 @@ root {
2769
2779
  height 3
2770
2780
 
2771
2781
  on_drag_start do |event|
2772
- event.data = event.source.selection.to_a.first.text
2782
+ event.data = event.source.selection.first
2773
2783
  end
2774
2784
  }
2775
2785
 
@@ -2777,7 +2787,6 @@ root {
2777
2787
  grid :row => 4, :column => 0
2778
2788
  text "Button"
2779
2789
  }
2780
-
2781
2790
  button {
2782
2791
  grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
2783
2792
  text "Drag it"
@@ -2792,45 +2801,42 @@ root {
2792
2801
 
2793
2802
  label {
2794
2803
  grid :row => 0, :column => 0
2795
- text "Entry"
2804
+ text "Label"
2796
2805
  }
2797
-
2798
- entry {
2799
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
2806
+ label {
2807
+ grid :row => 0, :column => 1, :pady => 10, :sticky => "e"
2800
2808
  width 30
2809
+ borderwidth 2
2810
+ relief "solid"
2801
2811
 
2802
- on_drop { |event|
2803
- event.target.textvariable.value = event.data
2804
- }
2812
+ on_drop do |event|
2813
+ event.target.text = event.data
2814
+ end
2805
2815
  }
2806
2816
 
2807
2817
  label {
2808
2818
  grid :row => 1, :column => 0
2809
- text "Label"
2819
+ text "Entry"
2810
2820
  }
2811
-
2812
- label {
2813
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
2821
+ entry {
2822
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
2814
2823
  width 30
2815
- borderwidth 2
2816
- relief "solid"
2817
2824
 
2818
- on_drop do |event|
2819
- event.target.textvariable.value = event.data
2820
- end
2825
+ on_drop { |event|
2826
+ event.target.text = event.data
2827
+ }
2821
2828
  }
2822
2829
 
2823
2830
  label {
2824
2831
  grid :row => 2, :column => 0
2825
2832
  text "Combobox"
2826
2833
  }
2827
-
2828
2834
  combobox {
2829
2835
  grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
2830
2836
  width 27
2831
2837
 
2832
2838
  on_drop do |event|
2833
- event.target.textvariable.value = event.data
2839
+ event.target.text = event.data
2834
2840
  end
2835
2841
  }
2836
2842
 
@@ -2838,14 +2844,13 @@ root {
2838
2844
  grid :row => 3, :column => 0
2839
2845
  text 'List'
2840
2846
  }
2841
-
2842
2847
  list {
2843
2848
  grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
2844
2849
  selectmode 'browse'
2845
2850
  height 3
2846
2851
 
2847
2852
  on_drop do |event|
2848
- event.target.insert('', 'end', :text => event.data)
2853
+ event.target.items += [event.data]
2849
2854
  end
2850
2855
  }
2851
2856
 
@@ -2853,7 +2858,6 @@ root {
2853
2858
  grid :row => 4, :column => 0
2854
2859
  text "Button"
2855
2860
  }
2856
-
2857
2861
  button {
2858
2862
  grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
2859
2863
  text "Drop here"
@@ -2867,14 +2871,14 @@ root {
2867
2871
  grid :row => 5, :column => 0
2868
2872
  text "Checkbutton"
2869
2873
  }
2870
-
2871
2874
  checkbutton {
2872
2875
  grid :row => 5, :column => 1, :pady => 5, :sticky => "w"
2873
- text "Drop here to destroy a widget\n(except button)"
2876
+ text "Drop here to destroy a widget"
2874
2877
 
2875
2878
  on_drop do |event|
2876
2879
  event.target.text = event.data
2877
- event.source.destroy unless event.source.is_a? Tk::Button
2880
+ # execute asynchronously after 100ms to ensure all events have been processed before destruction
2881
+ ::Tk.after(100) {event.source.destroy}
2878
2882
  end
2879
2883
  }
2880
2884
  }
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.44
1
+ 0.0.45
Binary file
@@ -50,7 +50,7 @@ module Glimmer
50
50
  #TODO check if nested data binding works for list widget and other widgets that need custom data binding
51
51
  list_selection_binding.observe(model, model_binding.property_name_expression)
52
52
 
53
- parent.tk.bind('<TreeviewSelect>') do
53
+ parent.on('<TreeviewSelect>') do
54
54
  model_binding.call(list_selection_binding.evaluate_property)
55
55
  end
56
56
  end
@@ -1,3 +1,24 @@
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
+
1
22
  require "json"
2
23
 
3
24
  module Glimmer
@@ -23,7 +44,7 @@ module Glimmer
23
44
  @on_drop_block = value
24
45
  self.tk.bind("<DropEvent>", proc { |tk_event|
25
46
  drop_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
26
- @on_drop_block.call(drop_event) if self.tk == drop_event.target
47
+ @on_drop_block.call(drop_event) if self == drop_event.target
27
48
  })
28
49
  self.tk.bind("<DropCheckEvent>", proc { |tk_event|
29
50
  drop_check_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
@@ -40,23 +61,30 @@ module Glimmer
40
61
  bind("<DropAcceptedEvent>", proc { |event| drag_event.drop_accepted = true })
41
62
  bind("B1-Motion", proc { |tk_event|
42
63
  if drag_event.nil?
43
- tooltip = TkToplevel.new(root).overrideredirect(1) #create tooltip window to display dragged data
64
+ tooltip = WidgetProxy.new('toplevel', root_parent_proxy, [])
65
+ tooltip.overrideredirect(1) #create tooltip window to display dragged data
44
66
  tooltip.geometry("+#{tk_event.x_root + 10}+#{tk_event.y_root - 2}")
45
- drag_event = DragAndDropEvent.new(self.tk, nil, tooltip, tk_event.x_root, tk_event.y_root, nil, false)
67
+ drag_event = DragAndDropEvent.new(self, nil, tooltip, tk_event.x_root, tk_event.y_root, nil, false)
46
68
  if @drag_source
47
69
  tk_event.widget.configure(:cursor => "hand2")
48
70
  # Default data to drag is text
49
71
  drag_event.data = if textvariable_defined? then tk.textvariable.value elsif has_attribute?(:text) then tk.text end
50
- TkLabel.new(tooltip) { text drag_event.data }.pack
72
+ tooltip_label = WidgetProxy.new('label', tooltip, [])
73
+ tooltip_label.text = drag_event.data
74
+ tooltip_label.pack # TODO look into using grid instead to be consistent with the modern Tk way
51
75
  elsif !@on_drag_start_block.nil?
52
76
  @on_drag_start_block.call(drag_event)
53
- TkLabel.new(tooltip) { text drag_event.data }.pack if tooltip.winfo_children().length == 0
77
+ if tooltip.winfo_children().length == 0
78
+ tooltip_label = WidgetProxy.new('label', tooltip, [])
79
+ tooltip_label.text = drag_event.data
80
+ tooltip_label.pack # TODO look into using grid instead to be consistent with the modern Tk way
81
+ end
54
82
  end
55
83
  else
56
84
  drag_event.x_root, drag_event.y_root = tk_event.x_root, tk_event.y_root
57
85
  drag_event.drop_accepted = false
58
86
  move_over_widget = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root)
59
- drag_event.target = move_over_widget
87
+ drag_event.target = move_over_widget.proxy
60
88
  move_over_widget.event_generate("<DropCheckEvent>", :data => drag_event.to_json)
61
89
  if @on_drag_motion_block.nil?
62
90
  # Default motion behavior:
@@ -75,7 +103,7 @@ module Glimmer
75
103
  })
76
104
  bind("ButtonRelease-1", proc { |tk_event|
77
105
  if drag_event
78
- drag_event.target = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root)
106
+ drag_event.target = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root).proxy
79
107
  drag_event.source.configure(:cursor => "")
80
108
  drag_event.target.event_generate("<DropEvent>", :data => drag_event.to_json)
81
109
  drag_event.tooltip.destroy
@@ -91,6 +119,8 @@ module Glimmer
91
119
  end
92
120
 
93
121
  DragAndDropEvent = Struct.new(:source, :target, :tooltip, :x_root, :y_root, :data, :drop_accepted) do
122
+ alias drop_accepted? drop_accepted
123
+
94
124
  def as_json(*)
95
125
  klass = self.class.name
96
126
  {
@@ -104,9 +134,9 @@ module Glimmer
104
134
  end
105
135
 
106
136
  def self.json_create(object)
107
- new(*[ObjectSpace._id2ref(object["v"][0]), ObjectSpace._id2ref(object["v"][1]), ObjectSpace._id2ref(object["v"][2])].concat(object["v"].drop 3))
137
+ new(*[ObjectSpace._id2ref(object["v"][0]), ObjectSpace._id2ref(object["v"][1]).proxy, ObjectSpace._id2ref(object["v"][2])].concat(object["v"].drop 3))
108
138
  end
109
139
  end
110
140
  end
111
141
  end
112
- end
142
+ end
@@ -0,0 +1,33 @@
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
+ # Non-Themable (non-Tile) Tk Label
27
+ class LblProxy < WidgetProxy
28
+ def build_widget
29
+ @tk = ::TkLabel.new(@parent_proxy.tk, *args).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
30
+ end
31
+ end
32
+ end
33
+ end
@@ -63,20 +63,20 @@ module Glimmer
63
63
  def build_widget
64
64
  if application?
65
65
  if OS.mac?
66
- @tk = ::TkSysMenu_Apple.new(@parent_proxy.tk)
66
+ @tk = ::TkSysMenu_Apple.new(@parent_proxy.tk).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
67
67
  @parent_proxy.tk.add :cascade, :menu => @tk
68
68
  end
69
69
  else
70
70
  if @parent_proxy.parent_proxy.is_a?(ToplevelProxy) && (OS.mac? || OS.linux?) && help?
71
- @tk = ::TkSysMenu_Help.new(@parent_proxy.tk)
71
+ @tk = ::TkSysMenu_Help.new(@parent_proxy.tk).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
72
72
  elsif @parent_proxy.parent_proxy.is_a?(ToplevelProxy) && OS.mac? && window?
73
- @tk = ::Tk::TkSysMenu_Window.new(@parent_proxy.tk)
73
+ @tk = ::Tk::TkSysMenu_Window.new(@parent_proxy.tk).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
74
74
  # Windows system menu does not seem to work
75
75
  # elsif @parent_proxy.parent_proxy.is_a?(ToplevelProxy) && OS.windows? && system?
76
- # @tk = ::TkSysMenu_System.new(@parent_proxy.tk)
76
+ # @tk = ::TkSysMenu_System.new(@parent_proxy.tk).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
77
77
  else
78
78
  tk_widget_class = self.class.tk_widget_class_for(@keyword)
79
- @tk = tk_widget_class.new(@parent_proxy.tk)
79
+ @tk = tk_widget_class.new(@parent_proxy.tk).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
80
80
  end
81
81
  case @parent_proxy
82
82
  when MenuProxy
@@ -28,7 +28,7 @@ module Glimmer
28
28
  # Follows the Proxy Design Pattern
29
29
  class RootProxy < ToplevelProxy
30
30
  def initialize(*args, &block)
31
- @tk = ::TkRoot.new
31
+ @tk = ::TkRoot.new.tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
32
32
  @tk.minsize = DEFAULT_WIDTH, DEFAULT_HEIGHT
33
33
  initialize_defaults
34
34
  post_add_content if block.nil?
@@ -103,7 +103,7 @@ module Glimmer
103
103
  build_yscrollbar
104
104
  build_xscrollbar
105
105
  tk_widget_class = self.class.tk_widget_class_for('frame')
106
- @tk = tk_widget_class.new(@canvas_proxy.tk, *args)
106
+ @tk = tk_widget_class.new(@canvas_proxy.tk, *args).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
107
107
  TkcWindow.new(@canvas_proxy.tk, 0, 0, :anchor => "nw", :window => @tk)
108
108
  end
109
109
 
@@ -0,0 +1,28 @@
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 Widget
25
+ attr_accessor :proxy
26
+ end
27
+ end
28
+ 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/data_binding/tk/one_time_observer'
23
+ require 'glimmer/tk/widget'
23
24
 
24
25
  module Glimmer
25
26
  module Tk
@@ -70,7 +71,8 @@ module Glimmer
70
71
 
71
72
  FONTS_PREDEFINED = %w[default text fixed menu heading caption small_caption icon tooltip]
72
73
 
73
- attr_reader :parent_proxy, :tk, :args, :keyword, :children
74
+ attr_reader :parent_proxy, :tk, :args, :keyword, :children, :bind_ids, :destroyed
75
+ alias destroyed? destroyed
74
76
 
75
77
  # Initializes a new Tk Widget
76
78
  #
@@ -288,8 +290,10 @@ module Glimmer
288
290
  end
289
291
 
290
292
  def destroy
293
+ unbind_all
291
294
  @tk.destroy
292
295
  @on_destroy_procs&.each {|p| p.call(@tk)}
296
+ @destroyed = true
293
297
  end
294
298
 
295
299
  def apply_style(options)
@@ -491,6 +495,16 @@ module Glimmer
491
495
  handle_listener(listener_name, &listener)
492
496
  end
493
497
 
498
+ def unbind_all
499
+ @listeners&.keys&.each do |key|
500
+ if key.to_s.downcase.include?('command')
501
+ @tk.send(key, '')
502
+ else
503
+ @tk.bind(key, '')
504
+ end
505
+ end
506
+ end
507
+
494
508
  def content(&block)
495
509
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::WidgetExpression.new, keyword, *args, &block)
496
510
  end
@@ -514,6 +528,11 @@ module Glimmer
514
528
  !super_only && tk.respond_to?(method, *args, &block)
515
529
  end
516
530
 
531
+ # inspect is overridden to prevent printing very long stack traces
532
+ def inspect
533
+ "#{super[0, 150]}... >"
534
+ end
535
+
517
536
  private
518
537
 
519
538
  # The griddable parent widget proxy to apply grid to (is different from @tk in composite widgets like notebook or scrolledframe)
@@ -528,7 +547,7 @@ module Glimmer
528
547
 
529
548
  def build_widget
530
549
  tk_widget_class = self.class.tk_widget_class_for(@keyword)
531
- @tk = tk_widget_class.new(@parent_proxy.tk, *args)
550
+ @tk = tk_widget_class.new(@parent_proxy.tk, *args).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
532
551
  end
533
552
 
534
553
  def initialize_defaults
@@ -35,27 +35,39 @@ root {
35
35
 
36
36
  label {
37
37
  grid :row => 0, :column => 0
38
- text "Entry"
38
+ text "Label"
39
+ }
40
+ label {
41
+ grid :row => 0, :column => 1, :pady => 10, :sticky => "e"
42
+ text "Drag label text"
43
+ width 30
44
+ drag_source true
39
45
  }
40
46
 
47
+ label {
48
+ grid :row => 1, :column => 0
49
+ text "Entry"
50
+ }
41
51
  entry {
42
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
52
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
43
53
  text "Drag entry text"
44
54
  width 30
45
55
 
56
+ # This is how to do `drag_source true` the manual way for use in exceptional cases
46
57
  on_drag_start do |event|
47
- event.data = event.source.textvariable&.value
58
+ event.data = event.source.text
48
59
  event.source.configure(:cursor => "hand2")
49
- TkLabel.new(event.tooltip) {
50
- text event.data + " "
51
- bg "yellow"
52
- bitmap "warning"
53
- compound "right"
54
- }.pack
60
+ event.tooltip.content {
61
+ lbl { # non-tile-theme version of label
62
+ text event.data + " "
63
+ bg "yellow"
64
+ bitmap "warning"
65
+ compound "right"
66
+ }
67
+ }
55
68
  end
56
-
57
69
  on_drag_motion do |event|
58
- if event.drop_accepted
70
+ if event.drop_accepted?
59
71
  event.source.configure(:cursor => "hand1")
60
72
  else
61
73
  event.source.configure(:cursor => "hand2")
@@ -64,23 +76,10 @@ root {
64
76
  end
65
77
  }
66
78
 
67
- label {
68
- grid :row => 1, :column => 0
69
- text "Label"
70
- }
71
-
72
- label {
73
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
74
- text "Drag label text"
75
- width 30
76
- drag_source true
77
- }
78
-
79
79
  label {
80
80
  grid :row => 2, :column => 0
81
81
  text "Combobox"
82
82
  }
83
-
84
83
  combobox {
85
84
  grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
86
85
  text "Spain"
@@ -88,7 +87,7 @@ root {
88
87
  width 27
89
88
 
90
89
  on_drag_start do |event|
91
- event.data = event.source.textvariable&.value
90
+ event.data = event.source.text
92
91
  end
93
92
  }
94
93
 
@@ -96,8 +95,7 @@ root {
96
95
  grid :row => 3, :column => 0
97
96
  text 'List'
98
97
  }
99
-
100
- country_list = list {
98
+ list {
101
99
  grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
102
100
  selectmode 'browse'
103
101
  items %w[USA Canada Mexico]
@@ -105,7 +103,7 @@ root {
105
103
  height 3
106
104
 
107
105
  on_drag_start do |event|
108
- event.data = event.source.selection.to_a.first.text
106
+ event.data = event.source.selection.first
109
107
  end
110
108
  }
111
109
 
@@ -113,7 +111,6 @@ root {
113
111
  grid :row => 4, :column => 0
114
112
  text "Button"
115
113
  }
116
-
117
114
  button {
118
115
  grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
119
116
  text "Drag it"
@@ -128,45 +125,42 @@ root {
128
125
 
129
126
  label {
130
127
  grid :row => 0, :column => 0
131
- text "Entry"
128
+ text "Label"
132
129
  }
133
-
134
- entry {
135
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
130
+ label {
131
+ grid :row => 0, :column => 1, :pady => 10, :sticky => "e"
136
132
  width 30
133
+ borderwidth 2
134
+ relief "solid"
137
135
 
138
- on_drop { |event|
139
- event.target.textvariable.value = event.data
140
- }
136
+ on_drop do |event|
137
+ event.target.text = event.data
138
+ end
141
139
  }
142
140
 
143
141
  label {
144
142
  grid :row => 1, :column => 0
145
- text "Label"
143
+ text "Entry"
146
144
  }
147
-
148
- label {
149
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
145
+ entry {
146
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
150
147
  width 30
151
- borderwidth 2
152
- relief "solid"
153
148
 
154
- on_drop do |event|
155
- event.target.textvariable.value = event.data
156
- end
149
+ on_drop { |event|
150
+ event.target.text = event.data
151
+ }
157
152
  }
158
153
 
159
154
  label {
160
155
  grid :row => 2, :column => 0
161
156
  text "Combobox"
162
157
  }
163
-
164
158
  combobox {
165
159
  grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
166
160
  width 27
167
161
 
168
162
  on_drop do |event|
169
- event.target.textvariable.value = event.data
163
+ event.target.text = event.data
170
164
  end
171
165
  }
172
166
 
@@ -174,14 +168,13 @@ root {
174
168
  grid :row => 3, :column => 0
175
169
  text 'List'
176
170
  }
177
-
178
171
  list {
179
172
  grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
180
173
  selectmode 'browse'
181
174
  height 3
182
175
 
183
176
  on_drop do |event|
184
- event.target.insert('', 'end', :text => event.data)
177
+ event.target.items += [event.data]
185
178
  end
186
179
  }
187
180
 
@@ -189,7 +182,6 @@ root {
189
182
  grid :row => 4, :column => 0
190
183
  text "Button"
191
184
  }
192
-
193
185
  button {
194
186
  grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
195
187
  text "Drop here"
@@ -203,14 +195,14 @@ root {
203
195
  grid :row => 5, :column => 0
204
196
  text "Checkbutton"
205
197
  }
206
-
207
198
  checkbutton {
208
199
  grid :row => 5, :column => 1, :pady => 5, :sticky => "w"
209
- text "Drop here to destroy a widget\n(except button and list)"
200
+ text "Drop here to destroy a widget"
210
201
 
211
202
  on_drop do |event|
212
203
  event.target.text = event.data
213
- event.source.destroy unless event.source.is_a?(Tk::Button) || event.source.is_a?(Tk::Tile::Treeview)
204
+ # execute asynchronously after 100ms to ensure all events have been processed before destruction
205
+ ::Tk.after(100) {event.source.destroy}
214
206
  end
215
207
  }
216
208
  }
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.44
4
+ version: 0.0.45
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
@@ -212,6 +212,7 @@ files:
212
212
  - lib/glimmer/tk/entry_proxy.rb
213
213
  - lib/glimmer/tk/frame_proxy.rb
214
214
  - lib/glimmer/tk/label_proxy.rb
215
+ - lib/glimmer/tk/lbl_proxy.rb
215
216
  - lib/glimmer/tk/list_proxy.rb
216
217
  - lib/glimmer/tk/menu_item_proxy.rb
217
218
  - lib/glimmer/tk/menu_proxy.rb
@@ -225,6 +226,7 @@ files:
225
226
  - lib/glimmer/tk/toplevel_proxy.rb
226
227
  - lib/glimmer/tk/treeview_proxy.rb
227
228
  - lib/glimmer/tk/variable_owner.rb
229
+ - lib/glimmer/tk/widget.rb
228
230
  - lib/glimmer/tk/widget_proxy.rb
229
231
  - lib/os.rb
230
232
  - samples/elaborate/meta_sample.rb