glimmer-dsl-tk 0.0.27 → 0.0.31

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.
@@ -19,6 +19,8 @@
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/data_binding/tk/one_time_observer'
23
+
22
24
  module Glimmer
23
25
  module Tk
24
26
  # Proxy for Tk Widget objects
@@ -63,6 +65,8 @@ module Glimmer
63
65
  end
64
66
  end
65
67
 
68
+ FONTS_PREDEFINED = %w[default text fixed menu heading caption small_caption icon tooltip]
69
+
66
70
  attr_reader :parent_proxy, :tk, :args, :keyword, :children
67
71
 
68
72
  # Initializes a new Tk Widget
@@ -81,6 +85,27 @@ module Glimmer
81
85
  post_add_content if @block.nil?
82
86
  end
83
87
 
88
+ def root_parent_proxy
89
+ current = self
90
+ current = current.parent_proxy while current.parent_proxy
91
+ current
92
+ end
93
+
94
+ def toplevel_parent_proxy
95
+ ancestor_proxies.find {|widget_proxy| widget_proxy.is_a?(ToplevelProxy)}
96
+ end
97
+
98
+ # returns list of ancestors ordered from direct parent to root parent
99
+ def ancestor_proxies
100
+ ancestors = []
101
+ current = self
102
+ while current.parent_proxy
103
+ ancestors << current.parent_proxy
104
+ current = current.parent_proxy
105
+ end
106
+ ancestors
107
+ end
108
+
84
109
  def children
85
110
  @children ||= []
86
111
  end
@@ -225,7 +250,9 @@ module Glimmer
225
250
 
226
251
  def grid(options = {})
227
252
  options = options.stringify_keys
228
- index_in_parent = @parent_proxy.children.index(self)
253
+ index_in_parent = @parent_proxy&.children&.index(self)
254
+ options['rowspan'] = options.delete('row_span') if options.keys.include?('row_span')
255
+ options['columnspan'] = options.delete('column_span') if options.keys.include?('column_span')
229
256
  options['rowweight'] = options.delete('row_weight') if options.keys.include?('row_weight')
230
257
  options['columnweight'] = options.delete('column_weight') if options.keys.include?('column_weight')
231
258
  options['columnweight'] = options['rowweight'] = options.delete('weight') if options.keys.include?('weight')
@@ -236,21 +263,32 @@ module Glimmer
236
263
  options['columnminsize'] = options.delete('minwidth') if options.keys.include?('minwidth')
237
264
  options['columnminsize'] = options.delete('min_width') if options.keys.include?('min_width')
238
265
  options['columnminsize'] = options['rowminsize'] = options.delete('minsize') if options.keys.include?('minsize')
239
- TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('rowweight')) if options.keys.include?('rowweight')
240
- TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('rowminsize')) if options.keys.include?('rowminsize')
241
- TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('columnweight')) if options.keys.include?('columnweight')
242
- TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('columnminsize')) if options.keys.include?('columnminsize')
266
+ if index_in_parent
267
+ TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('rowweight')) if options.keys.include?('rowweight')
268
+ TkGrid.rowconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('rowminsize')) if options.keys.include?('rowminsize')
269
+ TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'weight'=> options.delete('columnweight')) if options.keys.include?('columnweight')
270
+ TkGrid.columnconfigure(@parent_proxy.tk, index_in_parent, 'minsize'=> options.delete('columnminsize')) if options.keys.include?('columnminsize')
271
+ end
243
272
  @tk.grid(options)
244
273
  end
245
274
 
246
275
  def font=(value)
247
- @tk.font = value.is_a?(TkFont) ? value : TkFont.new(value)
276
+ if (value.is_a?(Symbol) || value.is_a?(String)) && FONTS_PREDEFINED.include?(value.to_s.downcase)
277
+ @tk.font = "tk_#{value}_font".camelcase(:upper)
278
+ else
279
+ @tk.font = value.is_a?(TkFont) ? value : TkFont.new(value)
280
+ end
248
281
  rescue => e
249
282
  Glimmer::Config.logger.debug {"Failed to set attribute #{attribute} with args #{args.inspect}. Attempting to set through style instead..."}
250
283
  Glimmer::Config.logger.debug {e.full_message}
251
284
  apply_style({"font" => value})
252
285
  end
253
286
 
287
+ def destroy
288
+ @tk.destroy
289
+ @on_destroy_procs&.each {|p| p.call(@tk)}
290
+ end
291
+
254
292
  def apply_style(options)
255
293
  @@style_number = 0 unless defined?(@@style_number)
256
294
  style = "style#{@@style_number += 1}.#{@tk.class.name.split('::').last}"
@@ -373,9 +411,9 @@ module Glimmer
373
411
  end,
374
412
  },
375
413
  ::Tk::Text => {
376
- 'text' => lambda do |observer|
414
+ 'value' => lambda do |observer|
377
415
  handle_listener('modified') do
378
- observer.call(text)
416
+ observer.call(value)
379
417
  end
380
418
  end,
381
419
  },
@@ -413,16 +451,31 @@ module Glimmer
413
451
 
414
452
  def handle_listener(listener_name, &listener)
415
453
  listener_name = listener_name.to_s
416
- begin
417
- @tk.bind(listener_name, &listener)
418
- rescue => e
419
- Glimmer::Config.logger.debug {e.full_message}
420
- listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
421
- listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
422
- @tk.bind(listener_name, &listener)
454
+ if listener_name == 'destroy'
455
+ # 'destroy' is a more reliable alternative listener binding to '<Destroy>'
456
+ @on_destroy_procs ||= []
457
+ listener.singleton_class.include(Glimmer::DataBinding::Tk::OneTimeObserver) unless listener.is_a?(Glimmer::DataBinding::Tk::OneTimeObserver)
458
+ @on_destroy_procs << listener
459
+ @tk.bind('<Destroy>', listener)
460
+ parent_proxy.handle_listener(listener_name, &listener) if parent_proxy
461
+ # TODO return a listener registration object that has a deregister method
462
+ else
463
+ begin
464
+ @tk.bind(listener_name, &listener)
465
+ rescue => e
466
+ Glimmer::Config.logger.debug {"Unable to bind to #{listener_name} .. attempting to surround with <>"}
467
+ Glimmer::Config.logger.debug {e.full_message}
468
+ listener_name = "<#{listener_name}" if !listener_name.start_with?('<')
469
+ listener_name = "#{listener_name}>" if !listener_name.end_with?('>')
470
+ @tk.bind(listener_name, &listener)
471
+ end
423
472
  end
424
473
  end
425
474
 
475
+ def on(listener_name, &listener)
476
+ handle_listener(listener_name, &listener)
477
+ end
478
+
426
479
  def content(&block)
427
480
  Glimmer::DSL::Engine.add_content(self, Glimmer::DSL::Tk::WidgetExpression.new, keyword, *args, &block)
428
481
  end
@@ -74,8 +74,8 @@ class MetaSample
74
74
  def launch
75
75
  @root = root {
76
76
  title 'Glimmer Meta-Sample'
77
- width 700
78
- height 500
77
+ width 1280
78
+ height 720
79
79
 
80
80
  frame {
81
81
  grid row: 0, column: 0, column_weight: 0, row_weight: 1
@@ -87,7 +87,7 @@ class MetaSample
87
87
 
88
88
  on('command') do
89
89
  @selected_sample_index = index
90
- @code_text.text = File.read(file_path_for(selected_sample))
90
+ @code_text.value = File.read(file_path_for(selected_sample))
91
91
  end
92
92
  }
93
93
  end
@@ -102,7 +102,7 @@ class MetaSample
102
102
  parent_dir = File.join(Dir.home, '.glimmer-dsl-tk', 'samples', 'hello')
103
103
  FileUtils.mkdir_p(parent_dir)
104
104
  sample_file = File.join(parent_dir, "#{selected_sample.underscore}.rb")
105
- File.write(sample_file, @code_text.text)
105
+ File.write(sample_file, @code_text.value)
106
106
  FileUtils.cp_r(File.expand_path('../../icons', __dir__), File.dirname(File.dirname(parent_dir)))
107
107
  FileUtils.cp_r(File.expand_path('../hello/images', __dir__), parent_dir)
108
108
  sample_namespace_directory = File.expand_path("../hello/#{selected_sample.underscore}", __dir__)
@@ -120,7 +120,7 @@ class MetaSample
120
120
  text 'Reset'
121
121
 
122
122
  on('command') do
123
- @code_text.text = File.read(file_path_for(selected_sample))
123
+ @code_text.value = File.read(file_path_for(selected_sample))
124
124
  end
125
125
  }
126
126
  }
@@ -128,7 +128,7 @@ class MetaSample
128
128
 
129
129
  @code_text = text {
130
130
  grid row: 0, column: 1, column_weight: 1
131
- text File.read(file_path_for(selected_sample))
131
+ value File.read(file_path_for(selected_sample))
132
132
  }
133
133
  }
134
134
  @root.open
@@ -0,0 +1,68 @@
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-dsl-tk'
23
+
24
+ include Glimmer
25
+
26
+ root { |w|
27
+ title 'Hello, Built-in Dialog!'
28
+ width 400
29
+ height 400
30
+ x 150
31
+ y 150
32
+
33
+ frame {
34
+ %w[get_open_file get_multiple_open_file get_save_file choose_directory choose_color].each do |dialog|
35
+ button {
36
+ text dialog.split('_').map(&:capitalize).join(' ')
37
+
38
+ on('command') do
39
+ result = send(dialog, parent: w)
40
+ @result_label.text = [result].flatten.join("\n")
41
+ end
42
+ }
43
+ end
44
+
45
+ button {
46
+ text 'Choose Font'
47
+
48
+ on('command') do
49
+ choose_font(family: 'Courier New', size: '30', weight: 'bold') do |chosen_font|
50
+ @result_label.text = chosen_font
51
+ end
52
+ end
53
+ }
54
+ }
55
+
56
+ frame {
57
+ grid sticky: 'nsew', padx: 15, pady: 15
58
+
59
+ label {
60
+ grid row: 0, column: 0
61
+ text 'Result:'
62
+ }
63
+
64
+ @result_label = label {
65
+ grid row: 0, column: 1
66
+ }
67
+ }
68
+ }.open
@@ -0,0 +1,159 @@
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-dsl-tk"
23
+ require "glimmer/tk/drag_and_drop_extension"
24
+
25
+ include Glimmer
26
+
27
+ root {
28
+ title "Hello, Drag and Drop!"
29
+ frame {
30
+ padding 5
31
+ labelframe {
32
+ text "Drag sources"
33
+ padding 5
34
+ label {
35
+ text "Entry"
36
+ grid :row => 0, :column => 0
37
+ }
38
+ entry {
39
+ text "Drag entry text"
40
+ width 30
41
+ grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
42
+ on_drag_start { |event|
43
+ event.data = event.source.textvariable&.value
44
+ 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
54
+ event.source.configure(:cursor => "hand1")
55
+ else
56
+ event.source.configure(:cursor => "hand2")
57
+ end
58
+ event.tooltip.geometry("+#{event.x_root + 10}+#{event.y_root - 4}")
59
+ }
60
+ }
61
+ label {
62
+ text "Label"
63
+ grid :row => 1, :column => 0
64
+ }
65
+ 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
+ grid :row => 2, :column => 0
74
+ }
75
+ combobox {
76
+ text "Spain"
77
+ values %w[USA Canada Mexico Columbia UK Australia Germany Italy Spain]
78
+ 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
+ }
83
+ }
84
+ label {
85
+ text "Button"
86
+ grid :row => 3, :column => 0
87
+ }
88
+ button {
89
+ text "Drag it"
90
+ grid :row => 3, :column => 1, :pady => 5, :sticky => "w"
91
+ drag_source true
92
+ }
93
+ }
94
+
95
+ labelframe {
96
+ text "Drop targets"
97
+ grid :sticky => "nsew", :pady => 15
98
+ padding 5
99
+ label {
100
+ text "Entry"
101
+ grid :row => 0, :column => 0
102
+ }
103
+ entry {
104
+ width 30
105
+ grid :row => 0, :column => 1, :pady => 5, :sticky => "e"
106
+ on_drop { |event|
107
+ event.target.textvariable.value = event.data
108
+ }
109
+ }
110
+ label {
111
+ text "Label"
112
+ grid :row => 1, :column => 0
113
+ }
114
+ label {
115
+ 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
+ }
122
+ }
123
+ label {
124
+ text "Combobox"
125
+ grid :row => 2, :column => 0
126
+ }
127
+ combobox {
128
+ width 27
129
+ grid :row => 2, :column => 1, :pady => 5, :sticky => "e"
130
+ on_drop { |event|
131
+ event.target.textvariable.value = event.data
132
+ }
133
+ }
134
+ label {
135
+ text "Button"
136
+ grid :row => 3, :column => 0
137
+ }
138
+ button {
139
+ text "Drop here"
140
+ grid :row => 3, :column => 1, :pady => 5, :sticky => "w"
141
+ on_drop { |event|
142
+ event.target.text = event.data
143
+ }
144
+ }
145
+ label {
146
+ text "Checkbutton"
147
+ grid :row => 4, :column => 0
148
+ }
149
+ 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|
153
+ event.target.text = event.data
154
+ event.source.destroy unless event.source.is_a? Tk::Button
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }.open
@@ -27,8 +27,6 @@ root { |r|
27
27
  title 'Hello, Message Box!'
28
28
 
29
29
  frame {
30
- grid sticky: 'nsew', padx: 15, pady: 15
31
-
32
30
  button {
33
31
  text 'Please Click To Win a Surprise'
34
32
 
@@ -80,8 +78,6 @@ root { |r|
80
78
  }
81
79
 
82
80
  frame {
83
- grid sticky: 'nsew', padx: 15, pady: 15
84
-
85
81
  label {
86
82
  grid row: 0, column: 0
87
83
  text 'Result:'
@@ -0,0 +1,69 @@
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-dsl-tk'
23
+
24
+ include Glimmer
25
+
26
+ root {
27
+ title 'Hello, Separator!'
28
+ width 200
29
+ height 200
30
+
31
+ label {
32
+ grid row: 0, column: 0, min_width: 100, min_height: 100, column_weight: 0, sticky: 'nsew'
33
+ text 'Label 1'
34
+ anchor 'center'
35
+ }
36
+
37
+ separator {
38
+ grid row: 0, column: 1
39
+ orient 'vertical'
40
+ }
41
+
42
+ label {
43
+ grid row: 0, column: 2, min_width: 100, min_height: 100, sticky: 'nsew'
44
+ text 'Label 2'
45
+ anchor 'center'
46
+ }
47
+
48
+ separator {
49
+ grid row: 1, column: 0, column_span: 3
50
+ # orient 'horizontal' # default
51
+ }
52
+
53
+ label {
54
+ grid row: 2, column: 0, min_width: 100, min_height: 100, sticky: 'nsew'
55
+ text 'Label 3'
56
+ anchor 'center'
57
+ }
58
+
59
+ separator {
60
+ grid row: 2, column: 1
61
+ orient 'vertical'
62
+ }
63
+
64
+ label {
65
+ grid row: 2, column: 2, min_width: 100, min_height: 100, sticky: 'nsew'
66
+ text 'Label 4'
67
+ anchor 'center'
68
+ }
69
+ }.open