glimmer-dsl-tk 0.0.42 → 0.0.46

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: fbb49ce9e435d0313cdec33a81afec3ad4d7716ee6e8363004651417d3535704
4
- data.tar.gz: 9ad46f88ace884c5d670d2449728369af8510b95e24c291a3bda7580cef65820
3
+ metadata.gz: 5313d90447c3c864cdbc16c6704c6bcb07fc2b8adcd51f136d92762be919327e
4
+ data.tar.gz: e4e48e9330f79b4a5c677651336560805485d6d0b036fc7c248f3b0a338e0f82
5
5
  SHA512:
6
- metadata.gz: d58a0179466efe9991f53eefb23c6dd3749c386230d70722e0a6c3f24c85f2affc361e18c21d65b34b2cb37269dfb8c7ceff9953a1bc5059f1db971051b0c4c8
7
- data.tar.gz: bad07c9519d483534306b04be7e4d110fe302c6dc3f03028d85aa5c85fcfe01437c0471d58b49e3db013abc99d6f55535d5aefacc4bdc651df50b30ecda467e0
6
+ metadata.gz: 41b3096f2f320ae2bd277b71f4f98ca8ba0f43e05d50eba9adc1a200106d698c17a67bee78082e2f62cb1179d2185df0765e1e9b4a83fc4de15d367a4701e83d
7
+ data.tar.gz: 74761ae2d6f037d7c237d47da581ff2be8bf5f2c2c6e96a9656b900b5bc19ea39442afc14b16b9d2f5ac5ff370887973262b0d2cc8223a2fa7080972a63c564d
data/CHANGELOG.md CHANGED
@@ -1,10 +1,37 @@
1
1
  # Change Log
2
2
 
3
+ ## 0.0.46
4
+
5
+ - Support `drag_source true` on `list` widget
6
+ - Support `drop_target true` keyword alternative to `on_drop` for cases where it is implied what to drop (text in the case of label, entry, combo, list, and button)
7
+ - Support `on('drag_start')` (instead of `on_drag_start`), `on('drag_motion')`, and `on('drop')` for consistency with Glimmer DSL for general Tk listener style (`on('event')`)
8
+
9
+ ## 0.0.45
10
+
11
+ - Support `lbl` widget as the non-tile-themed version of `label` (i.e. `::TkLabel` not `::Tk::Tile::TLabel`)
12
+ - Add `#proxy` method to all Tk widgets to return Glimmer widget proxy objects (e.g. `Tk::Tile::TButton#proxy` returns `Glimmer::Tk::WidgetProxy` object)
13
+ - Provide question mark alias of `event.drop_accepted` (i.e. `drop_accepted?`)
14
+ - Have `DragAndDropEvent` `source`/`target` be the enhanced Glimmer widget proxy instead of the unenhanced Tk widget
15
+ - Look into improving code that uses `TkLabel` explicitly in Hello, Drag and Drop! (do `event.tooltip.content {label {...} }` with Glimmer DSL instead)
16
+ - Add Glimmer Style Guide
17
+ - Fix issue with dropping button and list unto checkbox in Hello, Drag and Drop!
18
+
19
+ ## 0.0.44
20
+
21
+ - Fix issue with not being able to drop list into checkbox in Hello, Drag and Drop! by disabling functionality for list just like button
22
+
23
+ ## 0.0.43
24
+
25
+ - Modified Hello, Drag and Drop! to include a list
26
+ - Removed the need to require `'glimmer/tk/drag_and_drop_extension'` to do drag and drop; it is automatically included in `require 'glimmer-dsl-tk'` now.
27
+ - Remove 'os' gem due to Tk having the capability to detect the OS it is on using `Tk.windowingsystem` (include Glimmer implementation of `OS` class having `OS.mac?`, `OS.windows?` and `OS.linux?`)
28
+ - Default to 'clam' Tk theme on Linux ('alt' looks a bit too classic with certain widgets)
29
+
3
30
  ## 0.0.42
4
31
 
5
32
  - Add vertical/horizontal scrollbars to Meta-Sample
6
33
  - Keep only vertical scrollbar in Hello, Text!
7
- - Fix issue with including bwidgets and iwidgets in Windows
34
+ - Fix issue with including bwidgets and iwidgets in Windows (by removing from default requires, leaving to users to require manually when needed only and only systems that support them)
8
35
  - Fix Hello, Menu Bar! sample in Windows (by disabling Windows-special System menu, which does not seem to be working in Tk)
9
36
 
10
37
  ## 0.0.41
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.42
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.46
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.42'
185
+ gem 'glimmer-dsl-tk', '0.0.46'
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
@@ -476,14 +480,23 @@ Check out the [Hello, Scrollbar!](#hello-scrollbar) sample for a `text` demo wit
476
480
 
477
481
  #### Drag and Drop API
478
482
 
479
- Drag and drop works by simply designating a widget as a drag source with attribute `drag_source true`
483
+ Drag and drop works by simply designating a widget as a drag source with attribute `drag_source true` and another widget as a drop target with attribute `drop_target true`.
484
+
485
+ Alternatively, add listeners on the drag source:
486
+ - `on('drag_start') {|event| ...}`: fires on drag start receiving an `event` arg to set `data` and configure `source`
487
+ - `on('drag_motion') {|event| ...}`: fires on drag motion receiving an `event` arg to check `event#drop_accepted`, and configure `source` and `tooltip`
480
488
 
481
- Alternatively, add listeners:
482
- - `on_drag_start {|event| ...}`: fires on drag start receiving an `event` arg to set `data` and configure `source`
483
- - `on_drag_motion {|event| ...}`: fires on drag motion receiving an `event` arg to check `event#drop_accepted`, and configure `source` and `tooltip`
489
+ And on the drop target, add listener:
490
+ - `on('drop') { |event| ...}`: fires on drop, receiving an `event` arg with `event#target` and `event#data` (set during drag). You can even destroy the `event#source` if you want to get rid of the dragged widget.
484
491
 
485
- On the drop target, you simply define:
486
- - `on_drop { |event| ...}`: fires on drop, receiving an `event` arg with `event#target` and `event#data` (set during drag). You can even destroy the `event#source` if you want to get rid of the dragged widget.
492
+ These are all the available attributes on event, which is of type `DragAndDropEvent`:
493
+ - `source`: drag source widget proxy
494
+ - `target`: drop target widget proxy
495
+ - `tooltip`: tooltip widget proxy
496
+ - `x_root`: x coordinate from top-left root corner
497
+ - `y_root`: y coordinate from top-left root corner
498
+ - `data`: data being transferred through drag and drop
499
+ - `drop_accepted`: boolean indicating if drop was accepted
487
500
 
488
501
  Learn more at the [Hello, Drag and Drop!](#hello-drag-and-drop) sample.
489
502
 
@@ -824,6 +837,17 @@ More details can be found in the [Hello, Button!](#hello-button) sample below.
824
837
 
825
838
  - Setting `background` attribute on `frame` or `label` does not work in `'aqua'` theme on the Mac (only in `'classic'` theme)
826
839
 
840
+ ## Glimmer Style Guide
841
+
842
+ - Widget arguments are always wrapped by parentheses.
843
+ - Widget blocks are always declared with curly braces `{}` to clearly visualize hierarchical view code and separate from logic code.
844
+ - Widget attribute declarations always have arguments that are never wrapped inside parentheses and never take a block.
845
+ - 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.
846
+ - In a widget's content block, group attributes on top first, with the `grid` geometry management attribute being first, and separate by an empty line from nested widgets and listeners following afterwards.
847
+ - In a widget's content block, after attributes, you may either include nested widgets second and listeners third or vice versa.
848
+ - Unlike attributes, nested widgets and listeners are all separated by an empty line to make readability easier except where it helps to group two widgets together (e.g. label and described entry)
849
+ - 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.
850
+
827
851
  ## Samples
828
852
 
829
853
  The easiest way to run samples is by launching the Glimmer Meta-Sample (the Sample of Samples).
@@ -1026,14 +1050,14 @@ class HelloButton
1026
1050
  text 'Text Button'
1027
1051
  }
1028
1052
 
1029
- button {
1053
+ button { |b|
1030
1054
  text <= [self, :count, on_read: ->(value) { "Click To Increment: #{value} " }]
1031
1055
  default 'active'
1032
1056
  focus true
1033
1057
 
1034
- command {
1058
+ on('command') do
1035
1059
  self.count += 1
1036
- }
1060
+ end
1037
1061
  }
1038
1062
  }
1039
1063
 
@@ -1048,9 +1072,9 @@ class HelloButton
1048
1072
  button {
1049
1073
  image File.expand_path('../../icons/glimmer.png', __dir__), subsample: 5
1050
1074
 
1051
- command {
1075
+ on('command') do
1052
1076
  message_box(title: 'Image Button', message: 'Image Button Clicked!')
1053
- }
1077
+ end
1054
1078
  }
1055
1079
  }
1056
1080
 
@@ -1065,12 +1089,12 @@ class HelloButton
1065
1089
  ['center', 'top', 'bottom', 'left', 'right'].each do |compound_option|
1066
1090
  button {
1067
1091
  image File.expand_path('../../icons/glimmer.png', __dir__), subsample: 5
1068
- text 'Text Image Button'
1092
+ text "#{compound_option.capitalize} Image"
1069
1093
  compound compound_option
1070
1094
 
1071
- command {
1095
+ on('command') do
1072
1096
  message_box(title: 'Text Image Button', message: 'Text Image Button Clicked!', detail: "(#{compound_option})")
1073
- }
1097
+ end
1074
1098
  }
1075
1099
  end
1076
1100
  }
@@ -2683,140 +2707,184 @@ Glimmer app:
2683
2707
  Glimmer code (from [samples/hello/hello_drag_and_drop.rb](samples/hello/hello_drag_and_drop.rb)):
2684
2708
 
2685
2709
  ```ruby
2686
- require "glimmer-dsl-tk"
2687
- require "glimmer/tk/drag_and_drop_extension"
2710
+ require 'glimmer-dsl-tk'
2688
2711
 
2689
2712
  include Glimmer
2690
2713
 
2691
2714
  root {
2692
2715
  title "Hello, Drag and Drop!"
2716
+
2693
2717
  frame {
2694
2718
  padding 5
2719
+
2695
2720
  labelframe {
2696
2721
  text "Drag sources"
2697
2722
  padding 5
2723
+
2698
2724
  label {
2699
- text "Entry"
2700
2725
  grid :row => 0, :column => 0
2726
+ text "Label"
2727
+ }
2728
+ label {
2729
+ grid :row => 0, :column => 1, :pady => 10, :sticky => "e"
2730
+ text "Drag label text"
2731
+ width 30
2732
+ drag_source true
2733
+ }
2734
+
2735
+ label {
2736
+ grid :row => 1, :column => 0
2737
+ text "Entry"
2701
2738
  }
2702
2739
  entry {
2740
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
2703
2741
  text "Drag entry text"
2704
2742
  width 30
2705
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
2706
- on_drag_start { |event|
2707
- event.data = event.source.textvariable&.value
2743
+
2744
+ # drag_source true
2745
+ # This is how to do `drag_source true` the manual way for use in exceptional cases
2746
+ on_drag_start do |event|
2747
+ event.data = event.source.text
2708
2748
  event.source.configure(:cursor => "hand2")
2709
- TkLabel.new(event.tooltip) {
2710
- text event.data + " "
2711
- bg "yellow"
2712
- bitmap "warning"
2713
- compound "right"
2714
- }.pack
2715
- }
2716
- on_drag_motion { |event|
2717
- if event.drop_accepted
2749
+ event.tooltip.content { # re-open tooltip content and add a label
2750
+ lbl { # non-tile-theme version of label
2751
+ text event.data + " "
2752
+ bg "yellow"
2753
+ bitmap "warning"
2754
+ compound "right"
2755
+ }
2756
+ }
2757
+ end
2758
+ on_drag_motion do |event|
2759
+ if event.drop_accepted?
2718
2760
  event.source.configure(:cursor => "hand1")
2719
2761
  else
2720
2762
  event.source.configure(:cursor => "hand2")
2721
2763
  end
2722
2764
  event.tooltip.geometry("+#{event.x_root + 10}+#{event.y_root - 4}")
2723
- }
2724
- }
2725
- label {
2726
- text "Label"
2727
- grid :row => 1, :column => 0
2728
- }
2729
- label {
2730
- text "Drag label text"
2731
- width 30
2732
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
2733
- drag_source true
2765
+ end
2734
2766
  }
2767
+
2735
2768
  label {
2736
- text "Combobox"
2737
2769
  grid :row => 2, :column => 0
2770
+ text "Combobox"
2738
2771
  }
2739
2772
  combobox {
2773
+ grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
2740
2774
  text "Spain"
2741
2775
  values %w[USA Canada Mexico Columbia UK Australia Germany Italy Spain]
2742
2776
  width 27
2743
- grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
2744
- on_drag_start { |event|
2745
- event.data = event.source.textvariable&.value
2746
- }
2777
+
2778
+ drag_source true
2779
+ }
2780
+
2781
+ label {
2782
+ grid :row => 3, :column => 0
2783
+ text 'List'
2784
+ }
2785
+ list {
2786
+ grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
2787
+ selectmode 'browse'
2788
+ items %w[USA Canada Mexico]
2789
+ selection 'Canada'
2790
+ height 3
2791
+
2792
+ # drag_source true
2793
+ # This is another alternative to `drag_source true` with manual specification of transferred data only
2794
+ on_drag_start do |event|
2795
+ event.data = event.source.selection.first
2796
+ end
2747
2797
  }
2798
+
2748
2799
  label {
2800
+ grid :row => 4, :column => 0
2749
2801
  text "Button"
2750
- grid :row => 3, :column => 0
2751
2802
  }
2752
2803
  button {
2804
+ grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
2753
2805
  text "Drag it"
2754
- grid :row => 3, :column => 1, :pady => 5, :sticky => "w"
2755
2806
  drag_source true
2756
2807
  }
2757
2808
  }
2758
2809
 
2759
2810
  labelframe {
2760
- text "Drop targets"
2761
2811
  grid :sticky => "nsew", :pady => 15
2812
+ text "Drop targets"
2762
2813
  padding 5
2814
+
2763
2815
  label {
2764
- text "Entry"
2765
2816
  grid :row => 0, :column => 0
2817
+ text "Label"
2766
2818
  }
2767
- entry {
2819
+ label {
2820
+ grid :row => 0, :column => 1, :pady => 10, :sticky => "e"
2768
2821
  width 30
2769
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
2770
- on_drop { |event|
2771
- event.target.textvariable.value = event.data
2772
- }
2822
+ borderwidth 2
2823
+ relief "solid"
2824
+
2825
+ drop_target true
2773
2826
  }
2827
+
2774
2828
  label {
2775
- text "Label"
2776
2829
  grid :row => 1, :column => 0
2830
+ text "Entry"
2777
2831
  }
2778
- label {
2832
+ entry {
2833
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
2779
2834
  width 30
2780
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
2781
- borderwidth 2
2782
- relief "solid"
2783
- on_drop { |event|
2784
- event.target.textvariable.value = event.data
2785
- }
2835
+
2836
+ drop_target true
2786
2837
  }
2838
+
2787
2839
  label {
2788
- text "Combobox"
2789
2840
  grid :row => 2, :column => 0
2841
+ text "Combobox"
2790
2842
  }
2791
2843
  combobox {
2792
- width 27
2793
2844
  grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
2794
- on_drop { |event|
2795
- event.target.textvariable.value = event.data
2796
- }
2845
+ width 27
2846
+
2847
+ drop_target true
2797
2848
  }
2849
+
2798
2850
  label {
2799
- text "Button"
2800
2851
  grid :row => 3, :column => 0
2852
+ text 'List'
2853
+ }
2854
+ list {
2855
+ grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
2856
+ selectmode 'browse'
2857
+ height 3
2858
+
2859
+ drop_target true
2860
+ }
2861
+
2862
+ label {
2863
+ grid :row => 4, :column => 0
2864
+ text "Button"
2801
2865
  }
2802
2866
  button {
2867
+ grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
2803
2868
  text "Drop here"
2804
- grid :row => 3, :column => 1, :pady => 5, :sticky => "w"
2805
- on_drop { |event|
2806
- event.target.text = event.data
2807
- }
2869
+
2870
+ drop_target true
2808
2871
  }
2872
+
2809
2873
  label {
2874
+ grid :row => 5, :column => 0
2810
2875
  text "Checkbutton"
2811
- grid :row => 4, :column => 0
2812
2876
  }
2813
2877
  checkbutton {
2814
- text "Drop here to destroy a widget\n(except button)"
2815
- grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
2816
- on_drop { |event|
2878
+ grid :row => 5, :column => 1, :pady => 5, :sticky => "w"
2879
+ text "Drop here to destroy a widget"
2880
+
2881
+ # drop_target true
2882
+ # This is an alternative to `drop_target true` with manual consumption of transferred data
2883
+ on_drop do |event|
2817
2884
  event.target.text = event.data
2818
- event.source.destroy unless event.source.is_a? Tk::Button
2819
- }
2885
+ # execute asynchronously after 100ms to ensure all events have been processed before destruction
2886
+ ::Tk.after(100) {event.source.destroy}
2887
+ end
2820
2888
  }
2821
2889
  }
2822
2890
  }
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.42
1
+ 0.0.46
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,9 +1,43 @@
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
4
25
  module Tk
5
- class WidgetProxy
26
+ module DraggableAndDroppable
6
27
  attr_accessor :on_drag_motion_block
28
+
29
+ def handle_listener(listener_name, &listener)
30
+ case listener_name.to_s.downcase
31
+ when 'drag_start'
32
+ self.on_drag_start_block = listener
33
+ when 'drag_motion'
34
+ self.on_drag_motion_block = listener
35
+ when 'drop'
36
+ self.on_drop_block = listener
37
+ else
38
+ super
39
+ end
40
+ end
7
41
 
8
42
  def drag_source=(value)
9
43
  @drag_source = value
@@ -14,6 +48,15 @@ module Glimmer
14
48
  end
15
49
  end
16
50
 
51
+ def drop_target=(value)
52
+ @drop_target = value
53
+ if @drop_target
54
+ make_droppable
55
+ else
56
+ make_non_droppable
57
+ end
58
+ end
59
+
17
60
  def on_drag_start_block=(block)
18
61
  @on_drag_start_block = block
19
62
  make_draggable
@@ -23,7 +66,7 @@ module Glimmer
23
66
  @on_drop_block = value
24
67
  self.tk.bind("<DropEvent>", proc { |tk_event|
25
68
  drop_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
26
- @on_drop_block.call(drop_event) if self.tk == drop_event.target
69
+ @on_drop_block.call(drop_event) if self == drop_event.target
27
70
  })
28
71
  self.tk.bind("<DropCheckEvent>", proc { |tk_event|
29
72
  drop_check_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
@@ -40,23 +83,36 @@ module Glimmer
40
83
  bind("<DropAcceptedEvent>", proc { |event| drag_event.drop_accepted = true })
41
84
  bind("B1-Motion", proc { |tk_event|
42
85
  if drag_event.nil?
43
- tooltip = TkToplevel.new(root).overrideredirect(1) #create tooltip window to display dragged data
86
+ tooltip = WidgetProxy.new('toplevel', root_parent_proxy, [])
87
+ tooltip.overrideredirect(1) #create tooltip window to display dragged data
44
88
  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)
89
+ drag_event = DragAndDropEvent.new(self, nil, tooltip, tk_event.x_root, tk_event.y_root, nil, false)
46
90
  if @drag_source
47
91
  tk_event.widget.configure(:cursor => "hand2")
48
92
  # Default data to drag is text
49
- 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
93
+ drag_event.data = if textvariable_defined?
94
+ tk.textvariable.value
95
+ elsif has_attribute?('text')
96
+ tk.text
97
+ elsif has_attribute?('selection')
98
+ selection.first
99
+ end
100
+ tooltip_label = WidgetProxy.new('label', tooltip, [])
101
+ tooltip_label.text = drag_event.data
102
+ tooltip_label.pack # TODO look into using grid instead to be consistent with the modern Tk way
51
103
  elsif !@on_drag_start_block.nil?
52
104
  @on_drag_start_block.call(drag_event)
53
- TkLabel.new(tooltip) { text drag_event.data }.pack if tooltip.winfo_children().length == 0
105
+ if tooltip.winfo_children().length == 0
106
+ tooltip_label = WidgetProxy.new('label', tooltip, [])
107
+ tooltip_label.text = drag_event.data
108
+ tooltip_label.pack # TODO look into using grid instead to be consistent with the modern Tk way
109
+ end
54
110
  end
55
111
  else
56
112
  drag_event.x_root, drag_event.y_root = tk_event.x_root, tk_event.y_root
57
113
  drag_event.drop_accepted = false
58
114
  move_over_widget = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root)
59
- drag_event.target = move_over_widget
115
+ drag_event.target = move_over_widget.proxy
60
116
  move_over_widget.event_generate("<DropCheckEvent>", :data => drag_event.to_json)
61
117
  if @on_drag_motion_block.nil?
62
118
  # Default motion behavior:
@@ -75,7 +131,7 @@ module Glimmer
75
131
  })
76
132
  bind("ButtonRelease-1", proc { |tk_event|
77
133
  if drag_event
78
- drag_event.target = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root)
134
+ drag_event.target = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root).proxy
79
135
  drag_event.source.configure(:cursor => "")
80
136
  drag_event.target.event_generate("<DropEvent>", :data => drag_event.to_json)
81
137
  drag_event.tooltip.destroy
@@ -90,7 +146,23 @@ module Glimmer
90
146
  @tk.bind_remove("<DropAcceptedEvent>")
91
147
  end
92
148
 
149
+ def make_droppable
150
+ self.on_drop_block = Proc.new do |event|
151
+ event.target.text = event.data if event.target.has_attribute?('text')
152
+ event.target.items += [event.data] if event.target.has_attribute?('items')
153
+ event.target.selection += [event.data] if event.target.has_attribute?('selection')
154
+ end
155
+ end
156
+
157
+ def make_non_droppable
158
+ @tk.bind_remove('<DropEvent>')
159
+ @tk.bind_remove('<DropCheckEvent>')
160
+ @on_drop_block = nil
161
+ end
162
+
93
163
  DragAndDropEvent = Struct.new(:source, :target, :tooltip, :x_root, :y_root, :data, :drop_accepted) do
164
+ alias drop_accepted? drop_accepted
165
+
94
166
  def as_json(*)
95
167
  klass = self.class.name
96
168
  {
@@ -104,9 +176,9 @@ module Glimmer
104
176
  end
105
177
 
106
178
  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))
179
+ new(*[ObjectSpace._id2ref(object["v"][0]), ObjectSpace._id2ref(object["v"][1]).proxy, ObjectSpace._id2ref(object["v"][2])].concat(object["v"].drop 3))
108
180
  end
109
181
  end
110
182
  end
111
183
  end
112
- end
184
+ 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,8 @@
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'
24
+ require 'glimmer/tk/draggable_and_droppable'
23
25
 
24
26
  module Glimmer
25
27
  module Tk
@@ -49,10 +51,10 @@ module Glimmer
49
51
  # TODO consider exposing this via Glimmer::Config
50
52
  potential_tk_widget_class_names = [
51
53
  "::Tk::Tile::#{tk_widget_class_basename}",
52
- "::Tk::BWidget::#{tk_widget_class_basename}",
53
- "::Tk::Iwidgets::#{tk_widget_class_basename}",
54
54
  "::Tk#{tk_widget_class_basename}",
55
55
  "::Tk::#{tk_widget_class_basename}",
56
+ "::Tk::BWidget::#{tk_widget_class_basename}",
57
+ "::Tk::Iwidgets::#{tk_widget_class_basename}",
56
58
  "::Glimmer::Tk::#{tk_widget_class_basename}Proxy",
57
59
  ]
58
60
  tk_widget_class = nil
@@ -68,9 +70,12 @@ module Glimmer
68
70
  end
69
71
  end
70
72
 
73
+ prepend DraggableAndDroppable
74
+
71
75
  FONTS_PREDEFINED = %w[default text fixed menu heading caption small_caption icon tooltip]
72
76
 
73
- attr_reader :parent_proxy, :tk, :args, :keyword, :children
77
+ attr_reader :parent_proxy, :tk, :args, :keyword, :children, :bind_ids, :destroyed
78
+ alias destroyed? destroyed
74
79
 
75
80
  # Initializes a new Tk Widget
76
81
  #
@@ -153,6 +158,7 @@ module Glimmer
153
158
  end
154
159
 
155
160
  def has_state?(attribute)
161
+ attribute = attribute.to_s
156
162
  attribute = attribute.sub(/\?$/, '').sub(/=$/, '')
157
163
  if @tk.respond_to?(:tile_state)
158
164
  begin
@@ -168,6 +174,7 @@ module Glimmer
168
174
  end
169
175
 
170
176
  def has_attributes_attribute?(attribute)
177
+ attribute = attribute.to_s
171
178
  attribute = attribute.sub(/\?$/, '').sub(/=$/, '')
172
179
  @tk.respond_to?(:attributes) && @tk.attributes.keys.include?(attribute.to_s)
173
180
  end
@@ -288,8 +295,10 @@ module Glimmer
288
295
  end
289
296
 
290
297
  def destroy
298
+ unbind_all
291
299
  @tk.destroy
292
300
  @on_destroy_procs&.each {|p| p.call(@tk)}
301
+ @destroyed = true
293
302
  end
294
303
 
295
304
  def apply_style(options)
@@ -491,6 +500,16 @@ module Glimmer
491
500
  handle_listener(listener_name, &listener)
492
501
  end
493
502
 
503
+ def unbind_all
504
+ @listeners&.keys&.each do |key|
505
+ if key.to_s.downcase.include?('command')
506
+ @tk.send(key, '')
507
+ else
508
+ @tk.bind(key, '')
509
+ end
510
+ end
511
+ end
512
+
494
513
  def content(&block)
495
514
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::WidgetExpression.new, keyword, *args, &block)
496
515
  end
@@ -514,6 +533,11 @@ module Glimmer
514
533
  !super_only && tk.respond_to?(method, *args, &block)
515
534
  end
516
535
 
536
+ # inspect is overridden to prevent printing very long stack traces
537
+ def inspect
538
+ "#{super[0, 150]}... >"
539
+ end
540
+
517
541
  private
518
542
 
519
543
  # The griddable parent widget proxy to apply grid to (is different from @tk in composite widgets like notebook or scrolledframe)
@@ -528,7 +552,7 @@ module Glimmer
528
552
 
529
553
  def build_widget
530
554
  tk_widget_class = self.class.tk_widget_class_for(@keyword)
531
- @tk = tk_widget_class.new(@parent_proxy.tk, *args)
555
+ @tk = tk_widget_class.new(@parent_proxy.tk, *args).tap {|tk| tk.singleton_class.include(Glimmer::Tk::Widget); tk.proxy = self}
532
556
  end
533
557
 
534
558
  def initialize_defaults
@@ -48,7 +48,7 @@ Glimmer::Config.excluded_keyword_checkers << lambda do |method_symbol, *args|
48
48
  result ||= method == 'load_iseq'
49
49
  end
50
50
 
51
- Tk::Tile::Style.theme_use 'alt' if OS.linux?
51
+ Tk::Tile::Style.theme_use 'clam' if OS.linux?
52
52
 
53
53
  ::TkOption.add '*tearOff', 0
54
54
 
data/lib/os.rb ADDED
@@ -0,0 +1,36 @@
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
+ class OS
23
+ class << self
24
+ def mac?
25
+ Tk.windowingsystem == 'aqua'
26
+ end
27
+
28
+ def windows?
29
+ Tk.windowingsystem == 'win32'
30
+ end
31
+
32
+ def linux?
33
+ Tk.windowingsystem == 'x11'
34
+ end
35
+ end
36
+ end
@@ -47,9 +47,9 @@ class HelloButton
47
47
  default 'active'
48
48
  focus true
49
49
 
50
- on('command') {
50
+ on('command') do
51
51
  self.count += 1
52
- }
52
+ end
53
53
  }
54
54
  }
55
55
 
@@ -64,9 +64,9 @@ class HelloButton
64
64
  button {
65
65
  image File.expand_path('../../icons/glimmer.png', __dir__), subsample: 5
66
66
 
67
- on('command') {
67
+ on('command') do
68
68
  message_box(title: 'Image Button', message: 'Image Button Clicked!')
69
- }
69
+ end
70
70
  }
71
71
  }
72
72
 
@@ -84,9 +84,9 @@ class HelloButton
84
84
  text "#{compound_option.capitalize} Image"
85
85
  compound compound_option
86
86
 
87
- on('command') {
87
+ on('command') do
88
88
  message_box(title: 'Text Image Button', message: 'Text Image Button Clicked!', detail: "(#{compound_option})")
89
- }
89
+ end
90
90
  }
91
91
  end
92
92
  }
@@ -19,140 +19,184 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- require "glimmer-dsl-tk"
23
- require "glimmer/tk/drag_and_drop_extension"
22
+ require 'glimmer-dsl-tk'
24
23
 
25
24
  include Glimmer
26
25
 
27
26
  root {
28
27
  title "Hello, Drag and Drop!"
28
+
29
29
  frame {
30
30
  padding 5
31
+
31
32
  labelframe {
32
33
  text "Drag sources"
33
34
  padding 5
35
+
34
36
  label {
35
- text "Entry"
36
37
  grid :row => 0, :column => 0
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
45
+ }
46
+
47
+ label {
48
+ grid :row => 1, :column => 0
49
+ text "Entry"
37
50
  }
38
51
  entry {
52
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
39
53
  text "Drag entry text"
40
54
  width 30
41
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
42
- on_drag_start { |event|
43
- event.data = event.source.textvariable&.value
55
+
56
+ # drag_source true
57
+ # This is how to do `drag_source true` the manual way for use in exceptional cases
58
+ on('drag_start') do |event|
59
+ event.data = event.source.text
44
60
  event.source.configure(:cursor => "hand2")
45
- TkLabel.new(event.tooltip) {
46
- text event.data + " "
47
- bg "yellow"
48
- bitmap "warning"
49
- compound "right"
50
- }.pack
51
- }
52
- on_drag_motion { |event|
53
- if event.drop_accepted
61
+ event.tooltip.content { # re-open tooltip content and add a label
62
+ lbl { # non-tile-theme version of label
63
+ text event.data + " "
64
+ bg "yellow"
65
+ bitmap "warning"
66
+ compound "right"
67
+ }
68
+ }
69
+ end
70
+ on('drag_motion') do |event|
71
+ if event.drop_accepted?
54
72
  event.source.configure(:cursor => "hand1")
55
73
  else
56
74
  event.source.configure(:cursor => "hand2")
57
75
  end
58
76
  event.tooltip.geometry("+#{event.x_root + 10}+#{event.y_root - 4}")
59
- }
60
- }
61
- label {
62
- text "Label"
63
- grid :row => 1, :column => 0
77
+ end
64
78
  }
79
+
65
80
  label {
66
- text "Drag label text"
67
- width 30
68
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
69
- drag_source true
70
- }
71
- label {
72
- text "Combobox"
73
81
  grid :row => 2, :column => 0
82
+ text "Combobox"
74
83
  }
75
84
  combobox {
85
+ grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
76
86
  text "Spain"
77
87
  values %w[USA Canada Mexico Columbia UK Australia Germany Italy Spain]
78
88
  width 27
79
- grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
80
- on_drag_start { |event|
81
- event.data = event.source.textvariable&.value
82
- }
89
+
90
+ drag_source true
83
91
  }
92
+
84
93
  label {
85
- text "Button"
86
94
  grid :row => 3, :column => 0
95
+ text 'List'
96
+ }
97
+ list {
98
+ grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
99
+ selectmode 'browse'
100
+ items %w[USA Canada Mexico]
101
+ selection 'Canada'
102
+ height 3
103
+
104
+ # drag_source true
105
+ # This is another alternative to `drag_source true` with manual specification of transferred data only
106
+ on('drag_start') do |event|
107
+ event.data = event.source.selection.first
108
+ end
109
+ }
110
+
111
+ label {
112
+ grid :row => 4, :column => 0
113
+ text "Button"
87
114
  }
88
115
  button {
116
+ grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
89
117
  text "Drag it"
90
- grid :row => 3, :column => 1, :pady => 5, :sticky => "w"
91
118
  drag_source true
92
119
  }
93
120
  }
94
121
 
95
122
  labelframe {
96
- text "Drop targets"
97
123
  grid :sticky => "nsew", :pady => 15
124
+ text "Drop targets"
98
125
  padding 5
126
+
99
127
  label {
100
- text "Entry"
101
128
  grid :row => 0, :column => 0
129
+ text "Label"
102
130
  }
103
- entry {
131
+ label {
132
+ grid :row => 0, :column => 1, :pady => 10, :sticky => "e"
104
133
  width 30
105
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
106
- on_drop { |event|
107
- event.target.textvariable.value = event.data
108
- }
134
+ borderwidth 2
135
+ relief "solid"
136
+
137
+ drop_target true
109
138
  }
139
+
110
140
  label {
111
- text "Label"
112
141
  grid :row => 1, :column => 0
142
+ text "Entry"
113
143
  }
114
- label {
144
+ entry {
145
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
115
146
  width 30
116
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
117
- borderwidth 2
118
- relief "solid"
119
- on_drop { |event|
120
- event.target.textvariable.value = event.data
121
- }
147
+
148
+ drop_target true
122
149
  }
150
+
123
151
  label {
124
- text "Combobox"
125
152
  grid :row => 2, :column => 0
153
+ text "Combobox"
126
154
  }
127
155
  combobox {
128
- width 27
129
156
  grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
130
- on_drop { |event|
131
- event.target.textvariable.value = event.data
132
- }
157
+ width 27
158
+
159
+ drop_target true
133
160
  }
161
+
134
162
  label {
135
- text "Button"
136
163
  grid :row => 3, :column => 0
164
+ text 'List'
165
+ }
166
+ list {
167
+ grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
168
+ selectmode 'browse'
169
+ height 3
170
+
171
+ drop_target true
172
+ }
173
+
174
+ label {
175
+ grid :row => 4, :column => 0
176
+ text "Button"
137
177
  }
138
178
  button {
179
+ grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
139
180
  text "Drop here"
140
- grid :row => 3, :column => 1, :pady => 5, :sticky => "w"
141
- on_drop { |event|
142
- event.target.text = event.data
143
- }
181
+
182
+ drop_target true
144
183
  }
184
+
145
185
  label {
186
+ grid :row => 5, :column => 0
146
187
  text "Checkbutton"
147
- grid :row => 4, :column => 0
148
188
  }
149
189
  checkbutton {
150
- text "Drop here to destroy a widget\n(except button)"
151
- grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
152
- on_drop { |event|
190
+ grid :row => 5, :column => 1, :pady => 5, :sticky => "w"
191
+ text "Drop here to destroy a widget"
192
+
193
+ # drop_target true
194
+ # This is an alternative to `drop_target true` with manual consumption of transferred data
195
+ on('drop') do |event|
153
196
  event.target.text = event.data
154
- event.source.destroy unless event.source.is_a? Tk::Button
155
- }
197
+ # execute asynchronously after 100ms to ensure all events have been processed before destruction
198
+ ::Tk.after(100) {event.source.destroy}
199
+ end
156
200
  }
157
201
  }
158
202
  }
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.42
4
+ version: 0.0.46
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
@@ -38,26 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: 0.13.1
41
- - !ruby/object:Gem::Dependency
42
- name: os
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: 1.0.0
48
- - - "<"
49
- - !ruby/object:Gem::Version
50
- version: 2.0.0
51
- type: :runtime
52
- prerelease: false
53
- version_requirements: !ruby/object:Gem::Requirement
54
- requirements:
55
- - - ">="
56
- - !ruby/object:Gem::Version
57
- version: 1.0.0
58
- - - "<"
59
- - !ruby/object:Gem::Version
60
- version: 2.0.0
61
41
  - !ruby/object:Gem::Dependency
62
42
  name: tk
63
43
  requirement: !ruby/object:Gem::Requirement
@@ -228,10 +208,11 @@ files:
228
208
  - lib/glimmer/dsl/tk/widget_expression.rb
229
209
  - lib/glimmer/tk/checkbutton_proxy.rb
230
210
  - lib/glimmer/tk/combobox_proxy.rb
231
- - lib/glimmer/tk/drag_and_drop_extension.rb
211
+ - lib/glimmer/tk/draggable_and_droppable.rb
232
212
  - lib/glimmer/tk/entry_proxy.rb
233
213
  - lib/glimmer/tk/frame_proxy.rb
234
214
  - lib/glimmer/tk/label_proxy.rb
215
+ - lib/glimmer/tk/lbl_proxy.rb
235
216
  - lib/glimmer/tk/list_proxy.rb
236
217
  - lib/glimmer/tk/menu_item_proxy.rb
237
218
  - lib/glimmer/tk/menu_proxy.rb
@@ -245,7 +226,9 @@ files:
245
226
  - lib/glimmer/tk/toplevel_proxy.rb
246
227
  - lib/glimmer/tk/treeview_proxy.rb
247
228
  - lib/glimmer/tk/variable_owner.rb
229
+ - lib/glimmer/tk/widget.rb
248
230
  - lib/glimmer/tk/widget_proxy.rb
231
+ - lib/os.rb
249
232
  - samples/elaborate/meta_sample.rb
250
233
  - samples/hello/hello_built_in_dialog.rb
251
234
  - samples/hello/hello_button.rb