glimmer-dsl-tk 0.0.27 → 0.0.31

Sign up to get free protection for your applications and to get access to all the features.
@@ -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