glimmer-dsl-tk 0.0.44 → 0.0.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
@@ -0,0 +1,48 @@
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 'tk'
23
+
24
+ module Glimmer
25
+ module Tk
26
+ class OS
27
+ class << self
28
+ def mac?
29
+ ::Tk.windowingsystem == 'aqua'
30
+ end
31
+
32
+ def windows?
33
+ ::Tk.windowingsystem == 'win32'
34
+ end
35
+
36
+ def linux?
37
+ ::Tk.windowingsystem == 'x11'
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ begin
45
+ OS
46
+ rescue
47
+ ::OS = Glimmer::Tk::OS
48
+ end
@@ -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
 
@@ -19,18 +19,10 @@
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
- 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'
22
+ module Glimmer
23
+ module Tk
24
+ module Widget
25
+ attr_accessor :proxy
34
26
  end
35
27
  end
36
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
@@ -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
@@ -29,7 +29,6 @@ require 'puts_debuggerer' if ENV['pd'].to_s.downcase == 'true'
29
29
  require 'tk'
30
30
  #require 'tkextlib/bwidget' # does not work on Windows
31
31
  #require 'tkextlib/iwidgets' # does not work on Windows
32
- require 'os'
33
32
  require 'facets/hash/symbolize_keys'
34
33
  require 'facets/string/underscore'
35
34
  require 'facets/string/camelcase'
@@ -38,8 +37,8 @@ require 'delegate'
38
37
  # Internal requires
39
38
  # require 'ext/glimmer/config'
40
39
  # require 'ext/glimmer'
40
+ require 'glimmer/tk/os'
41
41
  require 'glimmer/dsl/tk/dsl'
42
- require 'glimmer/tk/drag_and_drop_extension'
43
42
 
44
43
  Glimmer::Config.loop_max_count = -1
45
44
 
@@ -49,11 +48,11 @@ Glimmer::Config.excluded_keyword_checkers << lambda do |method_symbol, *args|
49
48
  result ||= method == 'load_iseq'
50
49
  end
51
50
 
52
- Tk::Tile::Style.theme_use 'clam' if OS.linux?
51
+ ::Tk::Tile::Style.theme_use 'clam' if OS.linux?
53
52
 
54
53
  ::TkOption.add '*tearOff', 0
55
54
 
56
- class ::Tk::TkSysMenu_Window < Tk::Menu
57
- include Tk::SystemMenu
55
+ class ::Tk::TkSysMenu_Window < ::Tk::Menu
56
+ include ::Tk::SystemMenu
58
57
  SYSMENU_NAME = 'window'
59
58
  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
  }
@@ -35,27 +35,40 @@ 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
 
46
- on_drag_start do |event|
47
- event.data = event.source.textvariable&.value
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
48
60
  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
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
+ }
55
69
  end
56
-
57
- on_drag_motion do |event|
58
- if event.drop_accepted
70
+ on('drag_motion') do |event|
71
+ if event.drop_accepted?
59
72
  event.source.configure(:cursor => "hand1")
60
73
  else
61
74
  event.source.configure(:cursor => "hand2")
@@ -64,48 +77,34 @@ root {
64
77
  end
65
78
  }
66
79
 
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
80
  label {
80
81
  grid :row => 2, :column => 0
81
82
  text "Combobox"
82
83
  }
83
-
84
84
  combobox {
85
85
  grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
86
86
  text "Spain"
87
87
  values %w[USA Canada Mexico Columbia UK Australia Germany Italy Spain]
88
88
  width 27
89
89
 
90
- on_drag_start do |event|
91
- event.data = event.source.textvariable&.value
92
- end
90
+ drag_source true
93
91
  }
94
92
 
95
93
  label {
96
94
  grid :row => 3, :column => 0
97
95
  text 'List'
98
96
  }
99
-
100
- country_list = list {
97
+ list {
101
98
  grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
102
99
  selectmode 'browse'
103
100
  items %w[USA Canada Mexico]
104
101
  selection 'Canada'
105
102
  height 3
106
103
 
107
- on_drag_start do |event|
108
- event.data = event.source.selection.to_a.first.text
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
109
108
  end
110
109
  }
111
110
 
@@ -113,7 +112,6 @@ root {
113
112
  grid :row => 4, :column => 0
114
113
  text "Button"
115
114
  }
116
-
117
115
  button {
118
116
  grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
119
117
  text "Drag it"
@@ -128,89 +126,76 @@ root {
128
126
 
129
127
  label {
130
128
  grid :row => 0, :column => 0
131
- text "Entry"
129
+ text "Label"
132
130
  }
133
-
134
- entry {
135
- grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
131
+ label {
132
+ grid :row => 0, :column => 1, :pady => 10, :sticky => "e"
136
133
  width 30
134
+ borderwidth 2
135
+ relief "solid"
137
136
 
138
- on_drop { |event|
139
- event.target.textvariable.value = event.data
140
- }
137
+ drop_target true
141
138
  }
142
139
 
143
140
  label {
144
141
  grid :row => 1, :column => 0
145
- text "Label"
142
+ text "Entry"
146
143
  }
147
-
148
- label {
149
- grid :row => 1, :column => 1, :pady => 10, :sticky => "e"
144
+ entry {
145
+ grid :row => 1, :column => 1, :pady => 5, :sticky => "e"
150
146
  width 30
151
- borderwidth 2
152
- relief "solid"
153
147
 
154
- on_drop do |event|
155
- event.target.textvariable.value = event.data
156
- end
148
+ drop_target true
157
149
  }
158
150
 
159
151
  label {
160
152
  grid :row => 2, :column => 0
161
153
  text "Combobox"
162
154
  }
163
-
164
155
  combobox {
165
156
  grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
166
157
  width 27
167
158
 
168
- on_drop do |event|
169
- event.target.textvariable.value = event.data
170
- end
159
+ drop_target true
171
160
  }
172
161
 
173
162
  label {
174
163
  grid :row => 3, :column => 0
175
164
  text 'List'
176
165
  }
177
-
178
166
  list {
179
167
  grid :row => 3, :column => 1, :pady => 5, :sticky => "e"
180
168
  selectmode 'browse'
181
169
  height 3
182
170
 
183
- on_drop do |event|
184
- event.target.insert('', 'end', :text => event.data)
185
- end
171
+ drop_target true
186
172
  }
187
173
 
188
174
  label {
189
175
  grid :row => 4, :column => 0
190
176
  text "Button"
191
177
  }
192
-
193
178
  button {
194
179
  grid :row => 4, :column => 1, :pady => 5, :sticky => "w"
195
180
  text "Drop here"
196
181
 
197
- on_drop do |event|
198
- event.target.text = event.data
199
- end
182
+ drop_target true
200
183
  }
201
184
 
202
185
  label {
203
186
  grid :row => 5, :column => 0
204
187
  text "Checkbutton"
205
188
  }
206
-
207
189
  checkbutton {
208
190
  grid :row => 5, :column => 1, :pady => 5, :sticky => "w"
209
- text "Drop here to destroy a widget\n(except button and list)"
210
-
211
- on_drop do |event|
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|
212
196
  event.target.text = event.data
213
- event.source.destroy unless event.source.is_a?(Tk::Button) || event.source.is_a?(Tk::Tile::Treeview)
197
+ # execute asynchronously after 100ms to ensure all events have been processed before destruction
198
+ ::Tk.after(100) {event.source.destroy}
214
199
  end
215
200
  }
216
201
  }
metadata CHANGED
@@ -1,14 +1,14 @@
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.48
5
5
  platform: ruby
6
6
  authors:
7
7
  - AndyMaleh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-17 00:00:00.000000000 Z
11
+ date: 2021-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: glimmer
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 2.4.0
19
+ version: 2.5.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 2.4.0
26
+ version: 2.5.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: puts_debuggerer
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -208,14 +208,17 @@ files:
208
208
  - lib/glimmer/dsl/tk/widget_expression.rb
209
209
  - lib/glimmer/tk/checkbutton_proxy.rb
210
210
  - lib/glimmer/tk/combobox_proxy.rb
211
- - lib/glimmer/tk/drag_and_drop_extension.rb
211
+ - lib/glimmer/tk/drag_and_drop_event.rb
212
+ - lib/glimmer/tk/draggable_and_droppable.rb
212
213
  - lib/glimmer/tk/entry_proxy.rb
213
214
  - lib/glimmer/tk/frame_proxy.rb
214
215
  - lib/glimmer/tk/label_proxy.rb
216
+ - lib/glimmer/tk/lbl_proxy.rb
215
217
  - lib/glimmer/tk/list_proxy.rb
216
218
  - lib/glimmer/tk/menu_item_proxy.rb
217
219
  - lib/glimmer/tk/menu_proxy.rb
218
220
  - lib/glimmer/tk/notebook_proxy.rb
221
+ - lib/glimmer/tk/os.rb
219
222
  - lib/glimmer/tk/radiobutton_proxy.rb
220
223
  - lib/glimmer/tk/root_proxy.rb
221
224
  - lib/glimmer/tk/scrollbar_frame_proxy.rb
@@ -225,8 +228,8 @@ files:
225
228
  - lib/glimmer/tk/toplevel_proxy.rb
226
229
  - lib/glimmer/tk/treeview_proxy.rb
227
230
  - lib/glimmer/tk/variable_owner.rb
231
+ - lib/glimmer/tk/widget.rb
228
232
  - lib/glimmer/tk/widget_proxy.rb
229
- - lib/os.rb
230
233
  - samples/elaborate/meta_sample.rb
231
234
  - samples/hello/hello_built_in_dialog.rb
232
235
  - samples/hello/hello_button.rb
@@ -291,7 +294,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
291
294
  - !ruby/object:Gem::Version
292
295
  version: '0'
293
296
  requirements: []
294
- rubygems_version: 3.2.31
297
+ rubygems_version: 3.2.22
295
298
  signing_key:
296
299
  specification_version: 4
297
300
  summary: Glimmer DSL for Tk
@@ -1,112 +0,0 @@
1
- require "json"
2
-
3
- module Glimmer
4
- module Tk
5
- class WidgetProxy
6
- attr_accessor :on_drag_motion_block
7
-
8
- def drag_source=(value)
9
- @drag_source = value
10
- if @drag_source
11
- make_draggable
12
- else
13
- make_non_draggable
14
- end
15
- end
16
-
17
- def on_drag_start_block=(block)
18
- @on_drag_start_block = block
19
- make_draggable
20
- end
21
-
22
- def on_drop_block=(value)
23
- @on_drop_block = value
24
- self.tk.bind("<DropEvent>", proc { |tk_event|
25
- drop_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
26
- @on_drop_block.call(drop_event) if self.tk == drop_event.target
27
- })
28
- self.tk.bind("<DropCheckEvent>", proc { |tk_event|
29
- drop_check_event = DragAndDropEvent.json_create(JSON.parse("{" + tk_event.detail + "}"))
30
- drop_check_event.source.event_generate("<DropAcceptedEvent>")
31
- })
32
- end
33
-
34
- def textvariable_defined?
35
- tk_widget_has_attribute_setter?(:textvariable) && !tk.textvariable.nil?
36
- end
37
-
38
- def make_draggable
39
- drag_event = nil
40
- bind("<DropAcceptedEvent>", proc { |event| drag_event.drop_accepted = true })
41
- bind("B1-Motion", proc { |tk_event|
42
- if drag_event.nil?
43
- tooltip = TkToplevel.new(root).overrideredirect(1) #create tooltip window to display dragged data
44
- 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)
46
- if @drag_source
47
- tk_event.widget.configure(:cursor => "hand2")
48
- # 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
51
- elsif !@on_drag_start_block.nil?
52
- @on_drag_start_block.call(drag_event)
53
- TkLabel.new(tooltip) { text drag_event.data }.pack if tooltip.winfo_children().length == 0
54
- end
55
- else
56
- drag_event.x_root, drag_event.y_root = tk_event.x_root, tk_event.y_root
57
- drag_event.drop_accepted = false
58
- move_over_widget = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root)
59
- drag_event.target = move_over_widget
60
- move_over_widget.event_generate("<DropCheckEvent>", :data => drag_event.to_json)
61
- if @on_drag_motion_block.nil?
62
- # Default motion behavior:
63
- # 1.Change cursor to show whether text can be dropped.
64
- # 2.Move tooltip with dragged data.
65
- if drag_event.drop_accepted
66
- tk_event.widget.configure(:cursor => "hand1")
67
- else
68
- tk_event.widget.configure(:cursor => "hand2")
69
- end
70
- drag_event.tooltip.geometry("+#{tk_event.x_root + 10}+#{tk_event.y_root - 2}")
71
- else
72
- @on_drag_motion_block.call(drag_event)
73
- end
74
- end
75
- })
76
- bind("ButtonRelease-1", proc { |tk_event|
77
- if drag_event
78
- drag_event.target = tk_event.widget.winfo_containing(tk_event.x_root, tk_event.y_root)
79
- drag_event.source.configure(:cursor => "")
80
- drag_event.target.event_generate("<DropEvent>", :data => drag_event.to_json)
81
- drag_event.tooltip.destroy
82
- drag_event = nil
83
- end
84
- })
85
- end
86
-
87
- def make_non_draggable
88
- @tk.bind_remove("B1-Motion")
89
- @tk.bind_remove("ButtonRelease-1")
90
- @tk.bind_remove("<DropAcceptedEvent>")
91
- end
92
-
93
- DragAndDropEvent = Struct.new(:source, :target, :tooltip, :x_root, :y_root, :data, :drop_accepted) do
94
- def as_json(*)
95
- klass = self.class.name
96
- {
97
- JSON.create_id => klass,
98
- "v" => [values[0].object_id, values[1].object_id, values[2].object_id].concat(values.drop 3),
99
- }
100
- end
101
-
102
- def to_json(*args)
103
- as_json.to_json(*args)
104
- end
105
-
106
- 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))
108
- end
109
- end
110
- end
111
- end
112
- end