tkwrapper 1.4.0 → 1.7.1
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.
- checksums.yaml +4 -4
- data/lib/tkwrapper.rb +6 -1
- data/lib/util/array.rb +8 -0
- data/lib/util/hash_recursive.rb +2 -2
- data/lib/util/tk/cell.rb +1 -0
- data/lib/util/tk/finder.rb +42 -25
- data/lib/util/tk/font.rb +14 -0
- data/lib/widgets/auto_resize_entry.rb +4 -4
- data/lib/widgets/auto_resize_text.rb +98 -0
- data/lib/widgets/base/comparator_item_store.rb +10 -1
- data/lib/widgets/base/configuration.rb +14 -8
- data/lib/widgets/base/manager.rb +9 -0
- data/lib/widgets/base/matcher.rb +1 -1
- data/lib/widgets/base/matches.rb +8 -4
- data/lib/widgets/base/padding.rb +60 -0
- data/lib/widgets/base/tk_options.rb +41 -0
- data/lib/widgets/base/widget.rb +68 -26
- data/lib/widgets/base/widget_store.rb +38 -0
- data/lib/widgets/base/window_info.rb +17 -0
- data/lib/widgets/button.rb +9 -0
- data/lib/widgets/entry.rb +3 -1
- data/lib/widgets/frame.rb +11 -1
- data/lib/widgets/grid.rb +5 -1
- data/lib/widgets/label.rb +3 -1
- data/lib/widgets/menu.rb +4 -2
- data/lib/widgets/mount_point.rb +25 -0
- data/lib/widgets/root.rb +3 -1
- data/lib/widgets/text.rb +60 -1
- data/lib/widgets/widgets.rb +3 -0
- metadata +25 -4
- data/lib/tk_extensions.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90b29c12036c765281e148238dd8b97afc06091749eeb5c8a8595ce8a3ddd589
|
4
|
+
data.tar.gz: 8c7b8f7f3b5c9b54a239d9d7d034b14d8cde4e700d848e98d2b77329da03aa8b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 402470958a23a858dbe40ab101e31b61fd7ccbf6c240dbaa83a9c6e6727c94ca1a5e81e9d73ab571fc3c85b0ba275fece636793eacb487a98a60ed85bffc1661
|
7
|
+
data.tar.gz: 3f74e9a050ec620ea4d77bc0e518dff8fe4037e79c37d5ca111d85f33d52288dc663449ba760a963fa26fb5dd2bcafb6d6edd9ecc6b84ac0831f67e1456bdbf1
|
data/lib/tkwrapper.rb
CHANGED
data/lib/util/array.rb
ADDED
data/lib/util/hash_recursive.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Util
|
4
|
-
def self.merge_recursive!(*hashes)
|
4
|
+
def self.merge_recursive!(*hashes, overwrite: true)
|
5
5
|
hashes[0].merge!(*hashes[1..]) do |_key, old, new|
|
6
6
|
if old.is_a?(Hash) && new.is_a?(Hash)
|
7
7
|
merge_recursive!(old, new)
|
8
8
|
else
|
9
|
-
new
|
9
|
+
overwrite ? new : old
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
data/lib/util/tk/cell.rb
CHANGED
data/lib/util/tk/finder.rb
CHANGED
@@ -2,48 +2,65 @@
|
|
2
2
|
|
3
3
|
require "#{LIB_DIR}/widgets/base/manager"
|
4
4
|
require "#{LIB_DIR}/widgets/base/matcher"
|
5
|
-
|
5
|
+
require "#{LIB_DIR}/widgets/base/matches"
|
6
6
|
|
7
7
|
class TkWrapper::Util::Tk::Finder
|
8
|
+
Match = TkWrapper::Widgets::Base::Match
|
8
9
|
Matcher = TkWrapper::Widgets::Base::Matcher
|
10
|
+
Matches = TkWrapper::Widgets::Base::Matches
|
9
11
|
|
10
|
-
def initialize(widgets: nil)
|
12
|
+
def initialize(widgets: nil, lookup: nil)
|
13
|
+
@lookup = lookup
|
11
14
|
@widgets = widgets
|
12
15
|
end
|
13
16
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
end
|
17
|
+
def iter(comparators, widgets = @widgets, lookup = @lookup)
|
18
|
+
comparators = [comparators] unless comparators.is_a?(Array)
|
19
|
+
Enumerator.new do |y|
|
20
|
+
comparators = each_widget_lookup_match(lookup, comparators) { |m| y << m }
|
21
|
+
each_widget_comparator_match(widgets, comparators) { |m| y << m }
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
|
-
def find(comparators, widgets = @widgets)
|
25
|
-
|
26
|
-
|
27
|
-
each_widget_match(widgets, matchers) do |match|
|
28
|
-
return match.widget if match
|
29
|
-
end
|
25
|
+
def find(comparators, widgets = @widgets, lookup = @lookup)
|
26
|
+
iter(comparators, widgets, lookup, &:itself).first
|
30
27
|
end
|
31
28
|
|
32
|
-
def find_all(comparators, widgets = @widgets)
|
33
|
-
|
34
|
-
matches
|
35
|
-
|
36
|
-
each_widget_match(widgets, matchers) do |match|
|
37
|
-
matches.push(match)
|
38
|
-
end
|
39
|
-
|
40
|
-
matches
|
29
|
+
def find_all(comparators, widgets = @widgets, lookup = @lookup)
|
30
|
+
it = iter(comparators, widgets, lookup, &:itself)
|
31
|
+
it.each_with_object(Matches.new) { |match, matches| matches.push(match) }
|
41
32
|
end
|
42
33
|
|
43
34
|
private
|
44
35
|
|
45
36
|
def create_value_matchers(comparators)
|
46
|
-
comparators = [comparators] unless comparators.is_a?(Array)
|
47
37
|
comparators.map { |comparator| Matcher.new(comparator: comparator) }
|
48
38
|
end
|
39
|
+
|
40
|
+
def each_widget_lookup_match(lookup, comparators, &block)
|
41
|
+
return comparators unless lookup
|
42
|
+
|
43
|
+
comparators.filter do |comparator|
|
44
|
+
next true unless [String, Symbol].include?(comparator.class)
|
45
|
+
|
46
|
+
(lookup[comparator] || []).each do |widget|
|
47
|
+
block.call(Match.new(comparator, widget: widget))
|
48
|
+
end
|
49
|
+
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def each_widget_comparator_match(widgets, comparators, &block)
|
55
|
+
matchers = create_value_matchers(comparators)
|
56
|
+
|
57
|
+
widgets.each do |widget|
|
58
|
+
ids = widget.ids.empty? ? [nil] : widget.ids
|
59
|
+
ids.each do |id|
|
60
|
+
matchers.each do |matcher|
|
61
|
+
(match = matcher.match(id, widget)) && block.call(match)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
49
66
|
end
|
data/lib/util/tk/font.rb
CHANGED
@@ -48,4 +48,18 @@ class TkWrapper::Util::Tk::Font
|
|
48
48
|
def update
|
49
49
|
@tk_widget.font = TkFont.new(@config)
|
50
50
|
end
|
51
|
+
|
52
|
+
def char_width
|
53
|
+
measure('0')
|
54
|
+
end
|
55
|
+
|
56
|
+
def linespace
|
57
|
+
metrics['linespace']
|
58
|
+
end
|
59
|
+
|
60
|
+
def metrics
|
61
|
+
@tk_widget.font.metrics.each_with_object({}) do |(key, value), metrics|
|
62
|
+
metrics[key] = value
|
63
|
+
end
|
64
|
+
end
|
51
65
|
end
|
@@ -5,14 +5,14 @@ class TkWrapper::Widgets::AutoResizeEntry < TkWrapper::Widgets::Entry
|
|
5
5
|
attr_accessor :min_width, :add_width
|
6
6
|
|
7
7
|
def initialize(**args)
|
8
|
-
@min_width = args
|
9
|
-
@add_width = args
|
8
|
+
@min_width = args.dig(:config, :min_width) || 0
|
9
|
+
@add_width = args.dig(:config, :add_width) || 0
|
10
10
|
super(**args)
|
11
11
|
end
|
12
12
|
|
13
13
|
def build(parent, **args)
|
14
14
|
super(parent, **args)
|
15
|
-
parent.
|
15
|
+
parent.bind('Configure') { resize }
|
16
16
|
tk_widget.textvariable = TkVariable.new unless tk_widget.textvariable
|
17
17
|
tk_widget.textvariable.trace('write') { resize }
|
18
18
|
resize
|
@@ -27,7 +27,7 @@ class TkWrapper::Widgets::AutoResizeEntry < TkWrapper::Widgets::Entry
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def resize
|
30
|
-
max_width = @cell.bbox[2]
|
30
|
+
max_width = [@cell.bbox[2], 0].max
|
31
31
|
text_width = @font.measure(value)
|
32
32
|
new_width = [[@min_width, text_width + @add_width].max, max_width].min
|
33
33
|
tk_widget.width = 0
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'text'
|
4
|
+
|
5
|
+
class TkWrapper::Widgets::AutoResizeText < TkWrapper::Widgets::Frame
|
6
|
+
attr_reader :text
|
7
|
+
|
8
|
+
def initialize(**args)
|
9
|
+
@min_number_chars = 8
|
10
|
+
@min_number_lines = 2
|
11
|
+
|
12
|
+
super(**args)
|
13
|
+
|
14
|
+
@longest_line_width = 0
|
15
|
+
@config.merge({ grid: :onecell }, overwrite: false)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_childs
|
19
|
+
@text = Text.new(config: {
|
20
|
+
grid: { sticky: 'nsew' },
|
21
|
+
width: @min_number_chars,
|
22
|
+
height: @min_number_lines
|
23
|
+
})
|
24
|
+
end
|
25
|
+
|
26
|
+
def build(parent, **args)
|
27
|
+
super(parent, **args)
|
28
|
+
@text.bind('<Modified>', &method(:autoresize))
|
29
|
+
TkGrid.propagate(tk_widget, 0)
|
30
|
+
resize(lines: @min_number_lines, chars: @min_number_chars)
|
31
|
+
#@text.resize(lines: @min_number_lines, chars: @min_number_chars)
|
32
|
+
end
|
33
|
+
|
34
|
+
# width of cursor + borders (textfield + frame) + padding (textfield + frame)
|
35
|
+
def additional_width_needed_for_textfield
|
36
|
+
@text.opts.insertwidth +
|
37
|
+
@text.accumulated_border_and_padding_width +
|
38
|
+
accumulated_border_and_padding_width
|
39
|
+
end
|
40
|
+
|
41
|
+
def additional_height_needed_for_textfield
|
42
|
+
# TODO: cursor height?
|
43
|
+
@text.accumulated_border_and_padding_height +
|
44
|
+
accumulated_border_and_padding_height
|
45
|
+
end
|
46
|
+
|
47
|
+
def width_needed_for_chars(num_chars)
|
48
|
+
text.font.char_width * num_chars + additional_width_needed_for_textfield
|
49
|
+
end
|
50
|
+
|
51
|
+
def height_needed_for_lines(num_lines)
|
52
|
+
@text.height_of_lines(num_lines) + additional_height_needed_for_textfield
|
53
|
+
end
|
54
|
+
|
55
|
+
def resize_width
|
56
|
+
opts.width = width_needed_for_textfield
|
57
|
+
@parent.tk_widget.update
|
58
|
+
end
|
59
|
+
|
60
|
+
def resize(height: nil, width: nil, lines: nil, chars: nil)
|
61
|
+
width = width_needed_for_chars(chars) if chars
|
62
|
+
height = height_needed_for_lines(lines) if lines
|
63
|
+
|
64
|
+
opts.width = width if width
|
65
|
+
opts.height = height if height
|
66
|
+
end
|
67
|
+
|
68
|
+
def width_needed_for_textfield
|
69
|
+
@text.longest_line_width + additional_width_needed_for_textfield
|
70
|
+
end
|
71
|
+
|
72
|
+
def height_needed_for_textfield
|
73
|
+
@text.height_of_lines + additional_height_needed_for_textfield
|
74
|
+
end
|
75
|
+
|
76
|
+
def max_width
|
77
|
+
[@cell.bbox[2], 0].max
|
78
|
+
end
|
79
|
+
|
80
|
+
def min_width
|
81
|
+
[max_width, width_needed_for_chars(@min_number_chars)].min
|
82
|
+
end
|
83
|
+
|
84
|
+
def min_height
|
85
|
+
height_needed_for_lines(@min_number_lines)
|
86
|
+
end
|
87
|
+
|
88
|
+
def autoresize
|
89
|
+
return unless @text.tk_widget.modified?
|
90
|
+
|
91
|
+
width = [[min_width, width_needed_for_textfield].max, max_width].min
|
92
|
+
height = [min_height, height_needed_for_textfield].max
|
93
|
+
|
94
|
+
resize(height: height, width: width)
|
95
|
+
|
96
|
+
@text.tk_widget.modified(false)
|
97
|
+
end
|
98
|
+
end
|
@@ -10,8 +10,12 @@ class TkWrapper::Widgets::Base::ComparatorItemStore
|
|
10
10
|
@comparator_map = {} # for lookup using comparisons by Matcher class
|
11
11
|
end
|
12
12
|
|
13
|
+
def map_key?(key)
|
14
|
+
[String, Symbol].include?(key)
|
15
|
+
end
|
16
|
+
|
13
17
|
def push(key, *items)
|
14
|
-
if
|
18
|
+
if map_key?(key)
|
15
19
|
(@key_map[key] ||= []).concat(items)
|
16
20
|
else
|
17
21
|
(@comparator_map[key] ||= []).concat(items)
|
@@ -25,6 +29,11 @@ class TkWrapper::Widgets::Base::ComparatorItemStore
|
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
32
|
+
def [](key)
|
33
|
+
items = map_key?(key) ? @key_map[key] : @comparator_map[key]
|
34
|
+
items&.length == 1 ? items.first : items
|
35
|
+
end
|
36
|
+
|
28
37
|
private
|
29
38
|
|
30
39
|
def items_from_key_map(id)
|
@@ -28,14 +28,14 @@ class TkWrapper::Widgets::Base::Configuration
|
|
28
28
|
@config = parse_and_clone(config)
|
29
29
|
end
|
30
30
|
|
31
|
-
def merge(*configurations)
|
31
|
+
def merge(*configurations, overwrite: true)
|
32
32
|
configurations = configurations.map do |configuration|
|
33
33
|
configuration = configuration.config if configuration.is_a?(self.class)
|
34
34
|
|
35
35
|
parse_and_clone(configuration)
|
36
36
|
end
|
37
37
|
|
38
|
-
Util.merge_recursive!(@config, *configurations)
|
38
|
+
Util.merge_recursive!(@config, *configurations, overwrite: overwrite)
|
39
39
|
end
|
40
40
|
|
41
41
|
def [](key)
|
@@ -77,17 +77,23 @@ class TkWrapper::Widgets::Base::Configuration
|
|
77
77
|
@config[:grid].reject { |option, _| NON_TK_OPTIONS.include?(option) }
|
78
78
|
end
|
79
79
|
|
80
|
+
def configure_grid(tk_widget)
|
81
|
+
grid = grid(only_tk_options: true)
|
82
|
+
return if grid.empty?
|
83
|
+
|
84
|
+
tk_widget.grid(grid)
|
85
|
+
end
|
86
|
+
|
80
87
|
def configure_tk_widget(tk_widget)
|
81
88
|
@config.each do |option, value|
|
82
89
|
next if NON_TK_OPTIONS.include?(option)
|
83
90
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
91
|
+
case option
|
92
|
+
when :grid then configure_grid(tk_widget)
|
93
|
+
when :pack then tk_widget.pack(value)
|
94
|
+
when :place then tk_widget.place(value)
|
95
|
+
else tk_widget[option] = value
|
88
96
|
end
|
89
|
-
|
90
|
-
tk_widget[option] = value
|
91
97
|
end
|
92
98
|
|
93
99
|
configure_weights(tk_widget)
|
data/lib/widgets/base/manager.rb
CHANGED
@@ -1,13 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'comparator_item_store'
|
4
|
+
require_relative 'widget_store'
|
4
5
|
|
5
6
|
class TkWrapper::Widgets::Base::Manager
|
6
7
|
ComparatorItemStore = TkWrapper::Widgets::Base::ComparatorItemStore
|
8
|
+
WidgetStore = TkWrapper::Widgets::Base::WidgetStore
|
9
|
+
|
10
|
+
attr_reader :widgets
|
7
11
|
|
8
12
|
def initialize
|
9
13
|
@configurations = ComparatorItemStore.new
|
10
14
|
@modifications = ComparatorItemStore.new
|
15
|
+
@widgets = WidgetStore.new
|
11
16
|
end
|
12
17
|
|
13
18
|
def add_configurations(matcher = nil, configuration = nil, **configurations)
|
@@ -42,6 +47,10 @@ class TkWrapper::Widgets::Base::Manager
|
|
42
47
|
widget.config.merge(*configurations(widget))
|
43
48
|
end
|
44
49
|
|
50
|
+
def tk_widget(id)
|
51
|
+
@widgets[id].tk_widget
|
52
|
+
end
|
53
|
+
|
45
54
|
alias modify add_modification
|
46
55
|
alias config add_configurations
|
47
56
|
end
|
data/lib/widgets/base/matcher.rb
CHANGED
@@ -39,7 +39,7 @@ class TkWrapper::Widgets::Base::Matcher
|
|
39
39
|
when String, Symbol then match_string(value, comparator, widget)
|
40
40
|
when Regexp then match_regex(value, comparator, widget)
|
41
41
|
when Class then match_class(value, comparator, widget)
|
42
|
-
when nil then Match(value,
|
42
|
+
when nil then Match.new(value, widget: widget)
|
43
43
|
else false
|
44
44
|
end
|
45
45
|
end
|
data/lib/widgets/base/matches.rb
CHANGED
@@ -25,10 +25,14 @@ class TkWrapper::Widgets::Base::Matches
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def [](key)
|
28
|
-
case @matches[key]
|
29
|
-
when 0 then nil
|
30
|
-
when 1
|
31
|
-
else
|
28
|
+
case @matches[key]&.size
|
29
|
+
when 0, nil then nil
|
30
|
+
when 1 then @matches[key][0]
|
31
|
+
else @matches[key]
|
32
32
|
end
|
33
33
|
end
|
34
|
+
|
35
|
+
def first
|
36
|
+
@matches.first&.[](1)
|
37
|
+
end
|
34
38
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TkWrapper::Widgets::Base::Padding
|
4
|
+
def initialize(widget)
|
5
|
+
@widget = widget
|
6
|
+
end
|
7
|
+
|
8
|
+
def set(left: nil, top: nil, right: nil, bottom: nil)
|
9
|
+
values = get
|
10
|
+
@widget.tk_widget.padding = [
|
11
|
+
left || values.left,
|
12
|
+
top || values.top,
|
13
|
+
right || values.right,
|
14
|
+
bottom || values.bottom
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
def get
|
19
|
+
(left, top, right, bottom) = @widget.tk_widget.padding.split
|
20
|
+
|
21
|
+
{
|
22
|
+
left: left || 0,
|
23
|
+
top: top || left || 0,
|
24
|
+
right: right || left || 0,
|
25
|
+
bottom: bottom || top || left || 0
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def left
|
30
|
+
get[:left]
|
31
|
+
end
|
32
|
+
|
33
|
+
def top
|
34
|
+
get[:top]
|
35
|
+
end
|
36
|
+
|
37
|
+
def right
|
38
|
+
get[:right]
|
39
|
+
end
|
40
|
+
|
41
|
+
def bottom
|
42
|
+
get[:bottom]
|
43
|
+
end
|
44
|
+
|
45
|
+
def left=(left)
|
46
|
+
set(left: left)
|
47
|
+
end
|
48
|
+
|
49
|
+
def top=(top)
|
50
|
+
set(top: top)
|
51
|
+
end
|
52
|
+
|
53
|
+
def right=(right)
|
54
|
+
set(right: right)
|
55
|
+
end
|
56
|
+
|
57
|
+
def bottom=(bottom)
|
58
|
+
set(bottom: bottom)
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'padding'
|
4
|
+
|
5
|
+
class TkWrapper::Widgets::Base::TkOptions
|
6
|
+
attr_reader :padding
|
7
|
+
|
8
|
+
def self.default_to_zero(*properties)
|
9
|
+
properties.each do |property|
|
10
|
+
define_method(property) do
|
11
|
+
value = @widget.tk_widget[property]
|
12
|
+
value.is_a?(Numeric) ? value : 0
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
default_to_zero :padx, :insertwidth, :borderwidth,
|
18
|
+
:spacing1, :spacing2, :spacing3
|
19
|
+
|
20
|
+
def initialize(widget)
|
21
|
+
@widget = widget
|
22
|
+
@padding = TkWrapper::Widgets::Base::Padding.new(@widget)
|
23
|
+
end
|
24
|
+
|
25
|
+
def padding=(hash)
|
26
|
+
@padding.set(**hash)
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing(key, value = nil)
|
30
|
+
if key[-1] == '='
|
31
|
+
@widget.tk_widget[key[0..-2].to_sym] = value
|
32
|
+
else
|
33
|
+
@widget.tk_widget[key]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def respond_to_missing?(*)
|
38
|
+
# no known way to check if tk_widget[key] exists
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
data/lib/widgets/base/widget.rb
CHANGED
@@ -1,28 +1,49 @@
|
|
1
1
|
require "#{LIB_DIR}/util/tk/cell"
|
2
2
|
require "#{LIB_DIR}/util/tk/finder"
|
3
|
-
require "#{LIB_DIR}/tk_extensions"
|
4
3
|
|
5
4
|
require_relative 'base'
|
5
|
+
require_relative 'window_info'
|
6
|
+
require_relative 'tk_options'
|
6
7
|
|
7
8
|
class TkWrapper::Widgets::Base::Widget
|
8
9
|
extend Forwardable
|
9
|
-
include TkExtensions
|
10
10
|
include Enumerable
|
11
11
|
|
12
12
|
def_delegators :@finder, :find, :find_all
|
13
|
+
def_delegators :tk_widget, :update
|
14
|
+
def_delegator :tk_widget, :bind_append, :bind
|
15
|
+
def_delegator :@manager, :widgets, :managed
|
13
16
|
|
14
17
|
attr_accessor :config
|
15
|
-
attr_reader :parent, :ids, :cell, :childs, :manager
|
18
|
+
attr_reader :parent, :ids, :cell, :childs, :manager, :winfo, :opts, :font
|
16
19
|
|
17
20
|
def tk_class() end
|
18
21
|
|
19
|
-
def initialize(config: {}, childs: [], manager: nil, ids: [])
|
20
|
-
|
21
|
-
@finder = TkWrapper::Util::Tk::Finder.new(widgets: self)
|
22
|
+
def initialize(parent: nil, config: {}, childs: [], manager: nil, ids: [], id: [])
|
23
|
+
initialize_utilities
|
22
24
|
@config = TkWrapper::Widgets::Base::Configuration.new(config)
|
23
|
-
@childs = childs.is_a?(Array) ? childs : [childs]
|
24
25
|
@manager = manager
|
25
|
-
@ids =
|
26
|
+
@ids = init_id(id) + init_id(ids)
|
27
|
+
@parent = parent
|
28
|
+
modify_configuration(@config)
|
29
|
+
@childs = normalize_childs(childs)
|
30
|
+
parent&.push(self)
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize_utilities
|
34
|
+
@cell = TkWrapper::Util::Tk::Cell.new(self)
|
35
|
+
@winfo = TkWrapper::Widgets::Base::WindowInfo.new(self)
|
36
|
+
@opts = TkWrapper::Widgets::Base::TkOptions.new(self)
|
37
|
+
@finder = TkWrapper::Util::Tk::Finder.new(widgets: self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def init_id(id)
|
41
|
+
id.is_a?(Array) ? id : [id]
|
42
|
+
end
|
43
|
+
|
44
|
+
def normalize_childs(childs)
|
45
|
+
childs = create_childs || childs
|
46
|
+
childs.is_a?(Array) ? childs : [childs]
|
26
47
|
end
|
27
48
|
|
28
49
|
def create_tk_widget(parent)
|
@@ -30,7 +51,7 @@ class TkWrapper::Widgets::Base::Widget
|
|
30
51
|
|
31
52
|
return unless tk_class
|
32
53
|
|
33
|
-
|
54
|
+
tk_class.new(parent&.tk_widget)
|
34
55
|
end
|
35
56
|
|
36
57
|
# if parent is provided and self has no tk_class, the tk_widget of the
|
@@ -41,22 +62,6 @@ class TkWrapper::Widgets::Base::Widget
|
|
41
62
|
(@tk_widget = create_tk_widget(parent)) || parent&.tk_widget
|
42
63
|
end
|
43
64
|
|
44
|
-
def build(parent, configure: true, manager: nil)
|
45
|
-
@parent = parent
|
46
|
-
tk_widget # creates the widget if possible and not yet created
|
47
|
-
@font = TkWrapper::Util::Tk::Font.new(tk_widget)
|
48
|
-
@manager ||= manager
|
49
|
-
@config.merge(*@manager.configurations(self)) if @manager
|
50
|
-
self.configure if configure
|
51
|
-
@manager&.execute_modifications(self)
|
52
|
-
@childs.each { |child| child.build(self, manager: @manager) }
|
53
|
-
end
|
54
|
-
|
55
|
-
def configure
|
56
|
-
@config.configure_tk_widget(tk_widget)
|
57
|
-
@config.configure_tearoff
|
58
|
-
end
|
59
|
-
|
60
65
|
def each(&block)
|
61
66
|
nodes_to_walk = [self]
|
62
67
|
until nodes_to_walk.empty?
|
@@ -68,6 +73,43 @@ class TkWrapper::Widgets::Base::Widget
|
|
68
73
|
|
69
74
|
def push(child)
|
70
75
|
@childs.push(child)
|
71
|
-
child.build(self)
|
76
|
+
child.build(self, manager: @manager)
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def build_childs
|
82
|
+
@childs.each { |child| child.build(self, manager: @manager) }
|
83
|
+
end
|
84
|
+
|
85
|
+
def modify_configuration(config) end
|
86
|
+
|
87
|
+
def create_childs() end
|
88
|
+
|
89
|
+
def before_build(**args) end
|
90
|
+
|
91
|
+
def after_build() end
|
92
|
+
|
93
|
+
def inner_build(configure: true, manager: nil)
|
94
|
+
tk_widget # creates the widget if possible and not yet created
|
95
|
+
@font = TkWrapper::Util::Tk::Font.new(tk_widget)
|
96
|
+
@manager ||= manager
|
97
|
+
@config.merge(*@manager.configurations(self), overwrite: false) if @manager
|
98
|
+
self.configure if configure
|
99
|
+
@manager&.execute_modifications(self)
|
100
|
+
@manager&.widgets&.push(self)
|
101
|
+
build_childs
|
102
|
+
end
|
103
|
+
|
104
|
+
def build(parent, configure: true, manager: nil)
|
105
|
+
@parent = parent
|
106
|
+
before_build(configure: configure, manager: manager)
|
107
|
+
inner_build(configure: configure, manager: manager)
|
108
|
+
after_build
|
109
|
+
end
|
110
|
+
|
111
|
+
def configure
|
112
|
+
@config.configure_tk_widget(tk_widget)
|
113
|
+
@config.configure_tearoff
|
72
114
|
end
|
73
115
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "#{LIB_DIR}/util/tk/finder"
|
4
|
+
require_relative 'comparator_item_store'
|
5
|
+
|
6
|
+
class TkWrapper::Widgets::Base::WidgetStore
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
def_delegators :@finder, :find, :find_all, :iter
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@lookup = {}
|
13
|
+
@finder = TkWrapper::Util::Tk::Finder.new(widgets: self, lookup: @lookup)
|
14
|
+
end
|
15
|
+
|
16
|
+
def push(widget)
|
17
|
+
widget.ids.each do |id|
|
18
|
+
(@lookup[id] ||= []).push(widget)
|
19
|
+
end
|
20
|
+
(@lookup[nil] ||= []).push(widget) if widget.ids.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(&block)
|
24
|
+
@lookup.each_value do |widgets|
|
25
|
+
widgets.each { |widget| block.call(widget) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def [](key)
|
30
|
+
@lookup[key]&.size == 1 ? @lookup[key].first : @lookup[key]
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def map_key?(key)
|
36
|
+
[String, Symbol].include?(key)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class TkWrapper::Widgets::Base::WindowInfo
|
2
|
+
def initialize(widget)
|
3
|
+
@widget = widget
|
4
|
+
end
|
5
|
+
|
6
|
+
def method_missing(name, *args)
|
7
|
+
if @widget.tk_widget.respond_to?("winfo_#{name}")
|
8
|
+
@widget.tk_widget.send("winfo_#{name}", *args)
|
9
|
+
else
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def respond_to_missing?(name, *)
|
15
|
+
@widget.tk_widget.respond_to?("winfo_#{name}") || super
|
16
|
+
end
|
17
|
+
end
|
data/lib/widgets/entry.rb
CHANGED
data/lib/widgets/frame.rb
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'tkextlib/tile'
|
4
|
+
|
3
5
|
class TkWrapper::Widgets::Frame < TkWrapper::Widgets::Base::Widget
|
4
6
|
def tk_class
|
5
|
-
|
7
|
+
Tk::Tile::Frame
|
8
|
+
end
|
9
|
+
|
10
|
+
def accumulated_border_and_padding_width
|
11
|
+
opts.padding.left + opts.padding.right + 2 * opts.borderwidth
|
12
|
+
end
|
13
|
+
|
14
|
+
def accumulated_border_and_padding_height
|
15
|
+
opts.padding.top + opts.padding.bottom + 2 * opts.borderwidth
|
6
16
|
end
|
7
17
|
end
|
data/lib/widgets/grid.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'tkextlib/tile'
|
4
|
+
|
3
5
|
# classification of TkGrid
|
4
6
|
class TkWrapper::Widgets::Grid < TkWrapper::Widgets::Base::Widget
|
5
7
|
attr_reader :parent, :matrix
|
@@ -7,14 +9,16 @@ class TkWrapper::Widgets::Grid < TkWrapper::Widgets::Base::Widget
|
|
7
9
|
Widget = TkWrapper::Widgets::Base::Widget
|
8
10
|
|
9
11
|
def tk_class
|
10
|
-
|
12
|
+
Tk::Tile::Frame
|
11
13
|
end
|
12
14
|
|
13
15
|
def initialize(**arguments)
|
16
|
+
parent = arguments.delete(:parent)
|
14
17
|
super(**arguments)
|
15
18
|
@childs.map! { |row| row.is_a?(Array) ? row : [row] }
|
16
19
|
configure_cells_for_grid
|
17
20
|
@childs.flatten! && @childs.select! { |cell| cell.is_a?(Widget) }
|
21
|
+
parent&.push(self)
|
18
22
|
end
|
19
23
|
|
20
24
|
def configure_cells_for_grid
|
data/lib/widgets/label.rb
CHANGED
data/lib/widgets/menu.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'tk'
|
4
|
+
|
3
5
|
class TkWrapper::Widgets::Menu < TkWrapper::Widgets::Base::Widget
|
4
6
|
def tk_class
|
5
|
-
|
7
|
+
TkMenu
|
6
8
|
end
|
7
9
|
|
8
10
|
def build(parent, **args)
|
@@ -12,7 +14,7 @@ class TkWrapper::Widgets::Menu < TkWrapper::Widgets::Base::Widget
|
|
12
14
|
|
13
15
|
class Cascade < TkWrapper::Widgets::Base::Widget
|
14
16
|
def tk_class
|
15
|
-
|
17
|
+
TkMenu
|
16
18
|
end
|
17
19
|
|
18
20
|
def build(parent, **args)
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class TkWrapper::Widgets::MountPoint < TkWrapper::Widgets::Base::Widget
|
4
|
+
def initialize(**args)
|
5
|
+
super(**args)
|
6
|
+
end
|
7
|
+
|
8
|
+
def build_childs(skip: true)
|
9
|
+
super() unless skip
|
10
|
+
end
|
11
|
+
|
12
|
+
def mount=(childs)
|
13
|
+
mount(childs)
|
14
|
+
end
|
15
|
+
|
16
|
+
def mount(childs = nil)
|
17
|
+
if childs
|
18
|
+
@childs = childs.is_a?(Array) ? childs : [childs]
|
19
|
+
end
|
20
|
+
@childs.each do |child|
|
21
|
+
child.config.merge(@config)
|
22
|
+
end
|
23
|
+
build_childs(skip: false)
|
24
|
+
end
|
25
|
+
end
|
data/lib/widgets/root.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'tk'
|
4
|
+
|
3
5
|
class TkWrapper::Widgets::Root < TkWrapper::Widgets::Base::Widget
|
4
6
|
def initialize(**arguments)
|
5
7
|
super(**arguments)
|
@@ -7,6 +9,6 @@ class TkWrapper::Widgets::Root < TkWrapper::Widgets::Base::Widget
|
|
7
9
|
end
|
8
10
|
|
9
11
|
def tk_class
|
10
|
-
|
12
|
+
TkRoot
|
11
13
|
end
|
12
14
|
end
|
data/lib/widgets/text.rb
CHANGED
@@ -1,7 +1,66 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'tk'
|
4
|
+
|
3
5
|
class TkWrapper::Widgets::Text < TkWrapper::Widgets::Base::Widget
|
4
6
|
def tk_class
|
5
|
-
|
7
|
+
TkText
|
8
|
+
end
|
9
|
+
|
10
|
+
def pos(key)
|
11
|
+
match = tk_widget.index(key).match(/(.*)\.(.*)/)
|
12
|
+
[match[1].to_i, match[2].to_i]
|
13
|
+
end
|
14
|
+
|
15
|
+
def count_lines
|
16
|
+
pos('end')[0] - 1
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_line_nr
|
20
|
+
pos('insert')[0]
|
21
|
+
end
|
22
|
+
|
23
|
+
def value=(value)
|
24
|
+
tk_widget.delete('1.0', 'end')
|
25
|
+
tk_widget.insert('1.0', value)
|
26
|
+
end
|
27
|
+
|
28
|
+
def lines(start_pos = '1.0', end_pos = 'end')
|
29
|
+
start_pos = start_pos.is_a?(String) ? start_pos : "#{start_pos}.0"
|
30
|
+
end_pos = end_pos.is_a?(String) ? end_pos : "#{end_pos}.0"
|
31
|
+
tk_widget.get(start_pos, end_pos).split("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
def longest_line_width
|
35
|
+
lines.map { |line| @font.measure(line) }.max || 0
|
36
|
+
end
|
37
|
+
|
38
|
+
# includes spacing1 and spacing2 (add. space above and below line)
|
39
|
+
# does not include spacing3 (additional space between lines)
|
40
|
+
def line_height_including_padding
|
41
|
+
# linespace: max height of characters of the font
|
42
|
+
# spacing1: additional space above line
|
43
|
+
# spacing3: additional space below line
|
44
|
+
@font.linespace + opts.spacing1 + opts.spacing3
|
45
|
+
end
|
46
|
+
|
47
|
+
def height_of_lines(num_lines = lines.size)
|
48
|
+
h = num_lines * line_height_including_padding
|
49
|
+
|
50
|
+
# spacing 3: additional space between lines
|
51
|
+
h + [num_lines - 1, 0].max * opts.spacing3
|
52
|
+
end
|
53
|
+
|
54
|
+
def resize(lines: nil, chars: nil)
|
55
|
+
tk_widget['height'] = lines if lines
|
56
|
+
tk_widget['width'] = chars if chars
|
57
|
+
end
|
58
|
+
|
59
|
+
def accumulated_border_and_padding_width
|
60
|
+
2 * (opts.padx + opts.borderwidth)
|
61
|
+
end
|
62
|
+
|
63
|
+
def accumulated_border_and_padding_height
|
64
|
+
2 * (opts.pady + opts.borderwidth)
|
6
65
|
end
|
7
66
|
end
|
data/lib/widgets/widgets.rb
CHANGED
@@ -9,6 +9,9 @@ require_relative 'frame'
|
|
9
9
|
require_relative 'label'
|
10
10
|
require_relative 'menu'
|
11
11
|
require_relative 'text'
|
12
|
+
require_relative 'auto_resize_text'
|
12
13
|
require_relative 'entry'
|
13
14
|
require_relative 'auto_resize_entry'
|
14
15
|
require_relative 'grid'
|
16
|
+
require_relative 'mount_point'
|
17
|
+
require_relative 'button'
|
metadata
CHANGED
@@ -1,23 +1,37 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tkwrapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Schnitzler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-12-
|
12
|
-
dependencies:
|
11
|
+
date: 2021-12-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: tk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.4'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.4'
|
13
27
|
description:
|
14
28
|
email: reception@e.mail.de
|
15
29
|
executables: []
|
16
30
|
extensions: []
|
17
31
|
extra_rdoc_files: []
|
18
32
|
files:
|
19
|
-
- lib/tk_extensions.rb
|
20
33
|
- lib/tkwrapper.rb
|
34
|
+
- lib/util/array.rb
|
21
35
|
- lib/util/hash_recursive.rb
|
22
36
|
- lib/util/tk/cell.rb
|
23
37
|
- lib/util/tk/finder.rb
|
@@ -25,6 +39,7 @@ files:
|
|
25
39
|
- lib/util/tk/tk.rb
|
26
40
|
- lib/util/virtual_methods.rb
|
27
41
|
- lib/widgets/auto_resize_entry.rb
|
42
|
+
- lib/widgets/auto_resize_text.rb
|
28
43
|
- lib/widgets/base/base.rb
|
29
44
|
- lib/widgets/base/comparator_item_store.rb
|
30
45
|
- lib/widgets/base/configuration.rb
|
@@ -32,12 +47,18 @@ files:
|
|
32
47
|
- lib/widgets/base/match.rb
|
33
48
|
- lib/widgets/base/matcher.rb
|
34
49
|
- lib/widgets/base/matches.rb
|
50
|
+
- lib/widgets/base/padding.rb
|
51
|
+
- lib/widgets/base/tk_options.rb
|
35
52
|
- lib/widgets/base/widget.rb
|
53
|
+
- lib/widgets/base/widget_store.rb
|
54
|
+
- lib/widgets/base/window_info.rb
|
55
|
+
- lib/widgets/button.rb
|
36
56
|
- lib/widgets/entry.rb
|
37
57
|
- lib/widgets/frame.rb
|
38
58
|
- lib/widgets/grid.rb
|
39
59
|
- lib/widgets/label.rb
|
40
60
|
- lib/widgets/menu.rb
|
61
|
+
- lib/widgets/mount_point.rb
|
41
62
|
- lib/widgets/root.rb
|
42
63
|
- lib/widgets/text.rb
|
43
64
|
- lib/widgets/widgets.rb
|
data/lib/tk_extensions.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'tk'
|
2
|
-
require 'tkextlib/tile'
|
3
|
-
|
4
|
-
module TkExtensions
|
5
|
-
# allow a Tk widget to have multiple bindings for the same event
|
6
|
-
module MultiBind
|
7
|
-
def bind(event, &callback)
|
8
|
-
@bindings ||= {}
|
9
|
-
|
10
|
-
unless @bindings[event]
|
11
|
-
@bindings[event] = []
|
12
|
-
super(event) { execute_all_bindings(event) }
|
13
|
-
end
|
14
|
-
|
15
|
-
@bindings[event].push(callback)
|
16
|
-
end
|
17
|
-
|
18
|
-
def execute_all_bindings(event)
|
19
|
-
@bindings[event].each(&:call)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
module TkWidgets
|
24
|
-
# from several Tk widgets create subclasses, which include MultiBind
|
25
|
-
# the reason why we loop over strings and not the classes themselve is, that
|
26
|
-
# the class names may be aliases (e.g. Tk::Tile::Entry is an alias for
|
27
|
-
# Tk::Tile::TEntry)
|
28
|
-
tk_class_names = [
|
29
|
-
'TkRoot', # becomes TkExtensions::TkRoot
|
30
|
-
'TkText', # becomes TkExtensions::TkText
|
31
|
-
'TkMenu', # becomes TkExtensions::TkMenu
|
32
|
-
'Tk::Tile::Entry', # becomes TkExtensions::Entry
|
33
|
-
'Tk::Tile::Frame', # becomes TkExtensions::Frame
|
34
|
-
'Tk::Tile::Label' # becomes TkExtensions::Label
|
35
|
-
]
|
36
|
-
tk_class_names.each do |tk_class_name|
|
37
|
-
# extract last part of the name (e.g. Tk::Tile::Entry => Entry)
|
38
|
-
new_child_class_name = tk_class_name.match(/([^:]*)$/)[1]
|
39
|
-
# get the class from the class constant name
|
40
|
-
tk_class = const_get(tk_class_name)
|
41
|
-
# create a new child class of tk_class and have it include MultiBind, which
|
42
|
-
# overwrites the bind method of that class to allow for multiple bindings
|
43
|
-
new_child_class = Class.new(tk_class) { include(MultiBind) }
|
44
|
-
# make the new class known to the TkExtensions namespace to allow to use it
|
45
|
-
# by e.g. TkExtensions::Entry
|
46
|
-
const_set(new_child_class_name, new_child_class)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|