tkwrapper 1.2.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/tk_extensions.rb +7 -6
- data/lib/tkwrapper.rb +7 -1
- data/lib/util/tk/cell.rb +37 -0
- data/lib/util/tk/finder.rb +66 -0
- data/lib/util/tk/font.rb +51 -0
- data/lib/util/tk/tk.rb +8 -0
- data/lib/widgets/auto_resize_entry.rb +8 -42
- data/lib/widgets/base/base.rb +1 -0
- data/lib/widgets/base/comparator_item_store.rb +50 -0
- data/lib/widgets/base/configuration.rb +15 -7
- data/lib/widgets/base/manager.rb +32 -38
- data/lib/widgets/base/match.rb +18 -0
- data/lib/widgets/base/matcher.rb +58 -0
- data/lib/widgets/base/matches.rb +38 -0
- data/lib/widgets/base/widget.rb +35 -98
- data/lib/widgets/base/widget_store.rb +38 -0
- data/lib/widgets/base/window_info.rb +13 -0
- data/lib/widgets/button.rb +7 -0
- data/lib/widgets/grid.rb +2 -2
- data/lib/widgets/menu.rb +8 -5
- data/lib/widgets/mount_point.rb +25 -0
- data/lib/widgets/widgets.rb +2 -0
- metadata +29 -4
- data/lib/widgets/base/widgets.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25ebb6c8831b18ae3b55f4d98896cc5cf824d628fd4bc245b6fc1ed9fd8c5ef0
|
4
|
+
data.tar.gz: b90ca62d87faa02e1a07f5f1145e175d55dfcfeacd71782c709a484038701dfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4d1820254e60b3d9ce4be52a8875b0acbda213dac7aa200352d794ff1146611e84ac1f9bb16589f6fa6d61ba3b65468c940cf27d965ead1e3913fbc5b1cce7e
|
7
|
+
data.tar.gz: fd00a3c5ae1c29aa66762f554a43223a5ce32ef538c340a8549ba56fb12853743f80ae90862aac30f99383be61497fe1744bbb85e7ca7ef1e83d32785e4f5133
|
data/lib/tk_extensions.rb
CHANGED
@@ -26,12 +26,13 @@ module TkExtensions
|
|
26
26
|
# the class names may be aliases (e.g. Tk::Tile::Entry is an alias for
|
27
27
|
# Tk::Tile::TEntry)
|
28
28
|
tk_class_names = [
|
29
|
-
'TkRoot',
|
30
|
-
'TkText',
|
31
|
-
'TkMenu',
|
32
|
-
'Tk::Tile::Entry',
|
33
|
-
'Tk::Tile::Frame',
|
34
|
-
'Tk::Tile::Label' # becomes TkExtensions::Label
|
29
|
+
'TkRoot', # becomes TkExtensions::TkWidgets::TkRoot
|
30
|
+
'TkText', # becomes TkExtensions::TkWidgets::TkText
|
31
|
+
'TkMenu', # becomes TkExtensions::TkWidgets::TkMenu
|
32
|
+
'Tk::Tile::Entry', # becomes TkExtensions::TkWidgets::Entry
|
33
|
+
'Tk::Tile::Frame', # becomes TkExtensions::TkWidgets::Frame
|
34
|
+
'Tk::Tile::Label', # becomes TkExtensions::TkWidgets::Label
|
35
|
+
'Tk::Tile::Button' # becomes TkExtensions::TkWidgets::Button
|
35
36
|
]
|
36
37
|
tk_class_names.each do |tk_class_name|
|
37
38
|
# extract last part of the name (e.g. Tk::Tile::Entry => Entry)
|
data/lib/tkwrapper.rb
CHANGED
@@ -2,10 +2,16 @@
|
|
2
2
|
|
3
3
|
LIB_DIR = __dir__
|
4
4
|
|
5
|
-
module TkWrapper
|
5
|
+
module TkWrapper
|
6
|
+
module Util
|
7
|
+
module Tk
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
6
11
|
|
7
12
|
require_relative 'widgets/widgets'
|
8
13
|
|
9
14
|
module TkWrapper
|
15
|
+
Manager = TkWrapper::Widgets::Base::Manager
|
10
16
|
Widget = TkWrapper::Widgets::Base::Widget
|
11
17
|
end
|
data/lib/util/tk/cell.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'tk'
|
4
|
+
|
5
|
+
class TkWrapper::Util::Tk::Cell
|
6
|
+
def initialize(widget)
|
7
|
+
@widget = widget
|
8
|
+
end
|
9
|
+
|
10
|
+
# returns the bounding box of the tk_widget
|
11
|
+
def bbox
|
12
|
+
return unless (container = container_parent)
|
13
|
+
|
14
|
+
grid_info = TkGrid.info(@widget.tk_widget)
|
15
|
+
start_col = grid_info['column']
|
16
|
+
end_col = start_col + grid_info['columnspan'] - 1
|
17
|
+
start_row = grid_info['row']
|
18
|
+
end_row = start_row + grid_info['rowspan'] - 1
|
19
|
+
|
20
|
+
container.tk_widget.update
|
21
|
+
TkGrid.bbox(container.tk_widget, start_col, start_row, end_col, end_row)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# the first parent, which contains a tk_widget, which is really different
|
27
|
+
# from self.tk_widget
|
28
|
+
def container_parent
|
29
|
+
container = @widget.parent
|
30
|
+
while container.tk_widget == @widget.tk_widget
|
31
|
+
return unless container.parent # not in a grid?
|
32
|
+
|
33
|
+
container = container.parent
|
34
|
+
end
|
35
|
+
container
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "#{LIB_DIR}/widgets/base/manager"
|
4
|
+
require "#{LIB_DIR}/widgets/base/matcher"
|
5
|
+
require "#{LIB_DIR}/widgets/base/matches"
|
6
|
+
|
7
|
+
class TkWrapper::Util::Tk::Finder
|
8
|
+
Match = TkWrapper::Widgets::Base::Match
|
9
|
+
Matcher = TkWrapper::Widgets::Base::Matcher
|
10
|
+
Matches = TkWrapper::Widgets::Base::Matches
|
11
|
+
|
12
|
+
def initialize(widgets: nil, lookup: nil)
|
13
|
+
@lookup = lookup
|
14
|
+
@widgets = widgets
|
15
|
+
end
|
16
|
+
|
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 }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def find(comparators, widgets = @widgets, lookup = @lookup)
|
26
|
+
iter(comparators, widgets, lookup, &:itself).first
|
27
|
+
end
|
28
|
+
|
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) }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def create_value_matchers(comparators)
|
37
|
+
comparators.map { |comparator| Matcher.new(comparator: comparator) }
|
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
|
66
|
+
end
|
data/lib/util/tk/font.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tk'
|
4
|
+
require 'forwardable'
|
5
|
+
|
6
|
+
require_relative 'tk'
|
7
|
+
|
8
|
+
class TkWrapper::Util::Tk::Font
|
9
|
+
def initialize(tk_widget)
|
10
|
+
@tk_widget = tk_widget
|
11
|
+
end
|
12
|
+
|
13
|
+
%i[family size weight slant underline overstrike].each do |option|
|
14
|
+
define_method("#{option}=") do |value, **args|
|
15
|
+
load unless @config
|
16
|
+
args[:update] ||= false
|
17
|
+
@config[option] = value
|
18
|
+
update if args[:update]
|
19
|
+
end
|
20
|
+
|
21
|
+
define_method(option) do
|
22
|
+
load unless @config
|
23
|
+
@config[option]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def with_update(&block)
|
28
|
+
block.call(self)
|
29
|
+
update
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_missing(method, *args)
|
33
|
+
if TkFont.respond_to?(method)
|
34
|
+
TkFont.send(method, @tk_widget.font, *args)
|
35
|
+
else
|
36
|
+
super
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def respond_to_missing?(method, *)
|
41
|
+
TkFont.respond_to?(method) || super
|
42
|
+
end
|
43
|
+
|
44
|
+
def load
|
45
|
+
@config = TkFont.actual(@tk_widget.font).to_h.transform_keys(&:to_sym)
|
46
|
+
end
|
47
|
+
|
48
|
+
def update
|
49
|
+
@tk_widget.font = TkFont.new(@config)
|
50
|
+
end
|
51
|
+
end
|
data/lib/util/tk/tk.rb
ADDED
@@ -4,14 +4,14 @@ class TkWrapper::Widgets::AutoResizeEntry < TkWrapper::Widgets::Entry
|
|
4
4
|
# auto resizes on user input, only works if in the grid geometry manager of tk
|
5
5
|
attr_accessor :min_width, :add_width
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
@min_width = config
|
9
|
-
@add_width = config
|
10
|
-
super(
|
7
|
+
def initialize(**args)
|
8
|
+
@min_width = args.dig(:config, :min_width) || 0
|
9
|
+
@add_width = args.dig(:config, :add_width) || 0
|
10
|
+
super(**args)
|
11
11
|
end
|
12
12
|
|
13
|
-
def build(parent,
|
14
|
-
super(parent,
|
13
|
+
def build(parent, **args)
|
14
|
+
super(parent, **args)
|
15
15
|
parent.tk_widget.bind('Configure') { resize }
|
16
16
|
tk_widget.textvariable = TkVariable.new unless tk_widget.textvariable
|
17
17
|
tk_widget.textvariable.trace('write') { resize }
|
@@ -26,43 +26,9 @@ class TkWrapper::Widgets::AutoResizeEntry < TkWrapper::Widgets::Entry
|
|
26
26
|
tk_widget.textvariable.value
|
27
27
|
end
|
28
28
|
|
29
|
-
def config_for_dummy_label
|
30
|
-
grid_info = TkGrid.info(tk_widget)
|
31
|
-
{ config: { grid: {
|
32
|
-
row: grid_info['row'],
|
33
|
-
column: grid_info['column'],
|
34
|
-
columnspan: grid_info['columnspan'],
|
35
|
-
sticky: 'nw'
|
36
|
-
} } }
|
37
|
-
end
|
38
|
-
|
39
|
-
def create_dummy_label_with_same_size(&block)
|
40
|
-
label = TkWrapper::Widgets::Label.new(**config_for_dummy_label)
|
41
|
-
label.build(@parent)
|
42
|
-
label.tk_widget.text = value
|
43
|
-
label.tk_widget.lower
|
44
|
-
result = block.call(label)
|
45
|
-
label.tk_widget.destroy
|
46
|
-
result
|
47
|
-
end
|
48
|
-
|
49
|
-
def text_width_in_pixel
|
50
|
-
create_dummy_label_with_same_size do |label|
|
51
|
-
@parent.tk_widget.update
|
52
|
-
label.tk_widget.winfo_width
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def textwidth_and_maxwidth_in_pixel
|
57
|
-
create_dummy_frame_with_same_size_label do |frame, label|
|
58
|
-
{ text_width: label.tk_widget.winfo_width,
|
59
|
-
max_width: frame.tk_widget.winfo_width }
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
29
|
def resize
|
64
|
-
max_width =
|
65
|
-
text_width =
|
30
|
+
max_width = [@cell.bbox[2], 0].max
|
31
|
+
text_width = @font.measure(value)
|
66
32
|
new_width = [[@min_width, text_width + @add_width].max, max_width].min
|
67
33
|
tk_widget.width = 0
|
68
34
|
tk_widget.grid(ipadx: new_width / 2.0)
|
data/lib/widgets/base/base.rb
CHANGED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'matcher'
|
4
|
+
|
5
|
+
class TkWrapper::Widgets::Base::ComparatorItemStore
|
6
|
+
Matcher = TkWrapper::Widgets::Base::Matcher
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@key_map = {} # for fast lookup
|
10
|
+
@comparator_map = {} # for lookup using comparisons by Matcher class
|
11
|
+
end
|
12
|
+
|
13
|
+
def map_key?(key)
|
14
|
+
[String, Symbol].include?(key)
|
15
|
+
end
|
16
|
+
|
17
|
+
def push(key, *items)
|
18
|
+
if map_key?(key)
|
19
|
+
(@key_map[key] ||= []).concat(items)
|
20
|
+
else
|
21
|
+
(@comparator_map[key] ||= []).concat(items)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns [{items: [...], match: Match}, {items: [...]}, ...]
|
26
|
+
def items_and_matches_for_widget(widget)
|
27
|
+
widget.ids.reduce([]) do |items, id|
|
28
|
+
items + items_from_key_map(id) + items_from_comparator_map(id, widget)
|
29
|
+
end
|
30
|
+
end
|
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
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def items_from_key_map(id)
|
40
|
+
(items = @key_map[id]) ? [{ items: items }] : []
|
41
|
+
end
|
42
|
+
|
43
|
+
def items_from_comparator_map(id, widget)
|
44
|
+
matcher = Matcher.new(value: id)
|
45
|
+
|
46
|
+
@comparator_map.filter_map do |(comparator, items)|
|
47
|
+
(m = matcher.match(comparator, widget)) && { items: items, match: m }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -21,7 +21,7 @@ class TkWrapper::Widgets::Base::Configuration
|
|
21
21
|
}.freeze
|
22
22
|
|
23
23
|
NON_TK_OPTIONS = %i[
|
24
|
-
|
24
|
+
tk_class tearoff weights menu min_width add_width
|
25
25
|
].freeze
|
26
26
|
|
27
27
|
def initialize(config)
|
@@ -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)
|
@@ -112,6 +118,8 @@ class TkWrapper::Widgets::Base::Configuration
|
|
112
118
|
end
|
113
119
|
|
114
120
|
def merge_global_configurations(manager, widget)
|
121
|
+
return unless manager
|
122
|
+
|
115
123
|
merge(*manager.configurations(widget))
|
116
124
|
end
|
117
125
|
end
|
data/lib/widgets/base/manager.rb
CHANGED
@@ -1,62 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'comparator_item_store'
|
4
|
+
require_relative 'widget_store'
|
5
|
+
|
4
6
|
class TkWrapper::Widgets::Base::Manager
|
7
|
+
ComparatorItemStore = TkWrapper::Widgets::Base::ComparatorItemStore
|
8
|
+
WidgetStore = TkWrapper::Widgets::Base::WidgetStore
|
9
|
+
|
10
|
+
attr_reader :widgets
|
11
|
+
|
5
12
|
def initialize
|
6
|
-
@
|
7
|
-
@
|
13
|
+
@configurations = ComparatorItemStore.new
|
14
|
+
@modifications = ComparatorItemStore.new
|
15
|
+
@widgets = WidgetStore.new
|
8
16
|
end
|
9
17
|
|
10
|
-
def add_configurations(matcher = nil,
|
11
|
-
|
18
|
+
def add_configurations(matcher = nil, configuration = nil, **configurations)
|
19
|
+
add_configuration(matcher, configuration) if configuration
|
12
20
|
|
13
|
-
|
21
|
+
configurations.each { |mat, cfg| add_configuration(mat, cfg) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_configuration(comparator, configuration)
|
25
|
+
@configurations.push(comparator, configuration)
|
14
26
|
end
|
15
27
|
|
16
28
|
def add_modification(matcher, &callback)
|
17
|
-
|
29
|
+
@modifications.push(matcher, callback)
|
18
30
|
end
|
19
31
|
|
20
32
|
def configurations(widget)
|
21
|
-
|
22
|
-
|
33
|
+
config_list = @configurations.items_and_matches_for_widget(widget)
|
34
|
+
config_list.map { |configs| configs[:items] }.flatten(1)
|
23
35
|
end
|
24
36
|
|
25
37
|
def execute_modifications(widget)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def find_matching_items(keys, container)
|
36
|
-
keys.each_with_object([]) do |key, items|
|
37
|
-
items.concat(
|
38
|
-
items_from_map(key, container),
|
39
|
-
items_by_regex(key, container)
|
40
|
-
)
|
38
|
+
item_list = @modifications.items_and_matches_for_widget(widget)
|
39
|
+
item_list.each do |items|
|
40
|
+
items[:items].each do |callback|
|
41
|
+
callback.call(widget, items[:match])
|
42
|
+
end
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
def
|
45
|
-
(
|
46
|
+
def configure(widget)
|
47
|
+
widget.config.merge(*configurations(widget))
|
46
48
|
end
|
47
49
|
|
48
|
-
def
|
49
|
-
|
50
|
-
match = matcher.match(key)
|
51
|
-
merged_items.concat(items.map { |item| [item, match] }) if match
|
52
|
-
end
|
50
|
+
def tk_widget(id)
|
51
|
+
@widgets[id].tk_widget
|
53
52
|
end
|
54
53
|
|
55
|
-
|
56
|
-
|
57
|
-
(container[:regex][matcher] ||= []).push(item)
|
58
|
-
else
|
59
|
-
(container[:map][matcher] ||= []).push(item)
|
60
|
-
end
|
61
|
-
end
|
54
|
+
alias modify add_modification
|
55
|
+
alias config add_configurations
|
62
56
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# single 'match' as part of a Matches object
|
4
|
+
class TkWrapper::Widgets::Base::Match
|
5
|
+
attr_reader :key, :widget, :match
|
6
|
+
|
7
|
+
def initialize(value, cls: nil, match: nil, widget: nil)
|
8
|
+
@key = match&.[](0) || value
|
9
|
+
@widget = widget
|
10
|
+
@match = match
|
11
|
+
@cls = cls
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def tk_widget
|
16
|
+
@widget&.tk_widget
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "#{LIB_DIR}/widgets/base/match"
|
4
|
+
|
5
|
+
class TkWrapper::Widgets::Base::Matcher
|
6
|
+
Match = TkWrapper::Widgets::Base::Match
|
7
|
+
|
8
|
+
def initialize(value: nil, comparator: nil)
|
9
|
+
@match_function = curry_match_function(value, comparator)
|
10
|
+
end
|
11
|
+
|
12
|
+
# args:
|
13
|
+
# [] if widget and matcher were provided on initialization
|
14
|
+
# [widget] if matcher was provided on initialization
|
15
|
+
# [matcher] if widget was provided on initialization
|
16
|
+
# [widget, matcher] if neither widget nor matcher were provided on initial.
|
17
|
+
def match(*args)
|
18
|
+
@match_function.call(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def match_regex(value, comparator, widget)
|
24
|
+
(match = comparator.match(value)) &&
|
25
|
+
Match.new(value, match: match, widget: widget)
|
26
|
+
end
|
27
|
+
|
28
|
+
def match_string(value, comparator, widget)
|
29
|
+
value == comparator && Match.new(value, widget: widget)
|
30
|
+
end
|
31
|
+
|
32
|
+
def match_class(value, comparator, widget)
|
33
|
+
widget.is_a?(comparator) &&
|
34
|
+
Match.new(value, cls: comparator, widget: widget)
|
35
|
+
end
|
36
|
+
|
37
|
+
def match_f(value, comparator, widget)
|
38
|
+
case comparator
|
39
|
+
when String, Symbol then match_string(value, comparator, widget)
|
40
|
+
when Regexp then match_regex(value, comparator, widget)
|
41
|
+
when Class then match_class(value, comparator, widget)
|
42
|
+
when nil then Match(value, { widget: widget })
|
43
|
+
else false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def curry_match_function(value, comparator)
|
48
|
+
if value && comparator
|
49
|
+
->(widget) { match_f(value, comparator, widget) }
|
50
|
+
elsif value
|
51
|
+
->(x_comparator, widget) { match_f(value, x_comparator, widget) }
|
52
|
+
elsif comparator
|
53
|
+
->(x_value, widget) { match_f(x_value, comparator, widget) }
|
54
|
+
else
|
55
|
+
->(x_value, x_comparator, widget) { match_f(x_value, x_comparator, widget) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require_relative 'match'
|
2
|
+
|
3
|
+
# matches widgets against conditions and stores matching widgets and matches
|
4
|
+
class TkWrapper::Widgets::Base::Matches
|
5
|
+
include Enumerable
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@matches = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def push(match)
|
12
|
+
(@matches[match.key] ||= []).push(match)
|
13
|
+
end
|
14
|
+
|
15
|
+
def concat(matches)
|
16
|
+
matches.each { |match| push(match) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def each(&block)
|
20
|
+
@matches.each do |(key, matches_for_key)|
|
21
|
+
matches_for_key.each do |match|
|
22
|
+
block.call([match.widget, key, match.match, match])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def [](key)
|
28
|
+
case @matches[key].size
|
29
|
+
when 0 then nil
|
30
|
+
when 1 then @matches[key][0]
|
31
|
+
else @matches[key]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def first
|
36
|
+
@matches.first&.[](1)
|
37
|
+
end
|
38
|
+
end
|
data/lib/widgets/base/widget.rb
CHANGED
@@ -1,47 +1,30 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
require 'tk'
|
4
|
-
|
1
|
+
require "#{LIB_DIR}/util/tk/cell"
|
2
|
+
require "#{LIB_DIR}/util/tk/finder"
|
5
3
|
require "#{LIB_DIR}/tk_extensions"
|
6
4
|
|
7
5
|
require_relative 'base'
|
6
|
+
require_relative 'window_info'
|
8
7
|
|
9
8
|
class TkWrapper::Widgets::Base::Widget
|
9
|
+
extend Forwardable
|
10
10
|
include TkExtensions
|
11
|
+
include Enumerable
|
12
|
+
|
13
|
+
def_delegators :@finder, :find, :find_all
|
11
14
|
|
12
15
|
attr_accessor :config
|
13
|
-
attr_reader :parent, :childs
|
16
|
+
attr_reader :parent, :ids, :cell, :childs, :manager, :winfo
|
14
17
|
|
15
18
|
def tk_class() end
|
16
19
|
|
17
|
-
def
|
18
|
-
@
|
19
|
-
|
20
|
-
|
21
|
-
def self.config(matcher = nil, configuration = nil, **configurations)
|
22
|
-
manager.add_configurations(matcher, configuration, **configurations)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.modify(matcher, &callback)
|
26
|
-
manager.add_modification(matcher, &callback)
|
27
|
-
end
|
28
|
-
|
29
|
-
def ids
|
30
|
-
case @id
|
31
|
-
when Array then @id
|
32
|
-
when nil then []
|
33
|
-
else [@id]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def manager
|
38
|
-
TkWrapper::Widgets::Base::Widget.manager
|
39
|
-
end
|
40
|
-
|
41
|
-
def initialize(config: {}, childs: [])
|
20
|
+
def initialize(config: {}, childs: [], manager: nil, ids: [])
|
21
|
+
@cell = TkWrapper::Util::Tk::Cell.new(self)
|
22
|
+
@winfo = TkWrapper::Widgets::Base::WindowInfo.new(self)
|
23
|
+
@finder = TkWrapper::Util::Tk::Finder.new(widgets: self)
|
42
24
|
@config = TkWrapper::Widgets::Base::Configuration.new(config)
|
43
25
|
@childs = childs.is_a?(Array) ? childs : [childs]
|
44
|
-
@
|
26
|
+
@manager = manager
|
27
|
+
@ids = ids.is_a?(Array) ? ids : [ids]
|
45
28
|
end
|
46
29
|
|
47
30
|
def create_tk_widget(parent)
|
@@ -49,7 +32,7 @@ class TkWrapper::Widgets::Base::Widget
|
|
49
32
|
|
50
33
|
return unless tk_class
|
51
34
|
|
52
|
-
|
35
|
+
tk_class.new(parent&.tk_widget)
|
53
36
|
end
|
54
37
|
|
55
38
|
# if parent is provided and self has no tk_class, the tk_widget of the
|
@@ -60,84 +43,38 @@ class TkWrapper::Widgets::Base::Widget
|
|
60
43
|
(@tk_widget = create_tk_widget(parent)) || parent&.tk_widget
|
61
44
|
end
|
62
45
|
|
63
|
-
def
|
46
|
+
def build_childs
|
47
|
+
@childs.each { |child| child.build(self, manager: @manager) }
|
48
|
+
end
|
49
|
+
|
50
|
+
def build(parent, configure: true, manager: nil)
|
64
51
|
@parent = parent
|
65
52
|
tk_widget # creates the widget if possible and not yet created
|
53
|
+
@font = TkWrapper::Util::Tk::Font.new(tk_widget)
|
54
|
+
@manager ||= manager
|
55
|
+
@config.merge(*@manager.configurations(self)) if @manager
|
66
56
|
self.configure if configure
|
67
|
-
manager
|
68
|
-
@
|
69
|
-
|
70
|
-
|
71
|
-
def push(child)
|
72
|
-
@childs.push(child)
|
73
|
-
child.build(self)
|
57
|
+
@manager&.execute_modifications(self)
|
58
|
+
@manager&.widgets&.push(self)
|
59
|
+
build_childs
|
74
60
|
end
|
75
61
|
|
76
62
|
def configure
|
77
|
-
@config.merge_global_configurations(manager, self)
|
78
63
|
@config.configure_tk_widget(tk_widget)
|
79
64
|
@config.configure_tearoff
|
80
65
|
end
|
81
66
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
when nil
|
89
|
-
true
|
90
|
-
else
|
91
|
-
is_a?(matcher)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
def find(matcher)
|
96
|
-
nodes_to_scan = [self]
|
97
|
-
until nodes_to_scan.empty?
|
98
|
-
node = nodes_to_scan.pop
|
99
|
-
return node if node.check_match(matcher)
|
100
|
-
|
101
|
-
nodes_to_scan = node.childs + nodes_to_scan
|
67
|
+
def each(&block)
|
68
|
+
nodes_to_walk = [self]
|
69
|
+
until nodes_to_walk.empty?
|
70
|
+
node = nodes_to_walk.pop
|
71
|
+
block.call(node)
|
72
|
+
nodes_to_walk = node.childs + nodes_to_walk
|
102
73
|
end
|
103
74
|
end
|
104
75
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
until nodes_to_scan.empty?
|
110
|
-
node = nodes_to_scan.pop
|
111
|
-
found_nodes.push(node) if node.check_match(matcher)
|
112
|
-
|
113
|
-
nodes_to_scan = node.childs + nodes_to_scan
|
114
|
-
end
|
115
|
-
|
116
|
-
found_nodes
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# the first parent, which contains a tk_widget, which is really different
|
121
|
-
# from self.tk_widget
|
122
|
-
def get_container_parent
|
123
|
-
container = @parent
|
124
|
-
while container.tk_widget == tk_widget
|
125
|
-
return unless container.parent # not in a grid?
|
126
|
-
|
127
|
-
container = container.parent
|
76
|
+
def push(child)
|
77
|
+
@childs.push(child)
|
78
|
+
child.build(self, manager: @manager)
|
128
79
|
end
|
129
|
-
container
|
130
|
-
end
|
131
|
-
|
132
|
-
# returns the bounding box of the tk_widget
|
133
|
-
def cell_bbox
|
134
|
-
return unless (container = get_container_parent)
|
135
|
-
|
136
|
-
grid_info = TkGrid.info(tk_widget)
|
137
|
-
start_col = grid_info['column']
|
138
|
-
end_col = start_col + grid_info['columnspan'] - 1
|
139
|
-
start_row = grid_info['row']
|
140
|
-
end_row = start_row + grid_info['rowspan'] - 1
|
141
|
-
|
142
|
-
TkGrid.bbox(container.tk_widget, start_col, start_row, end_col, end_row)
|
143
80
|
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,13 @@
|
|
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
|
+
end
|
data/lib/widgets/grid.rb
CHANGED
@@ -10,8 +10,8 @@ class TkWrapper::Widgets::Grid < TkWrapper::Widgets::Base::Widget
|
|
10
10
|
TkWidgets::Frame
|
11
11
|
end
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
super(
|
13
|
+
def initialize(**arguments)
|
14
|
+
super(**arguments)
|
15
15
|
@childs.map! { |row| row.is_a?(Array) ? row : [row] }
|
16
16
|
configure_cells_for_grid
|
17
17
|
@childs.flatten! && @childs.select! { |cell| cell.is_a?(Widget) }
|
data/lib/widgets/menu.rb
CHANGED
@@ -5,8 +5,8 @@ class TkWrapper::Widgets::Menu < TkWrapper::Widgets::Base::Widget
|
|
5
5
|
TkWidgets::TkMenu
|
6
6
|
end
|
7
7
|
|
8
|
-
def build(parent)
|
9
|
-
super(parent)
|
8
|
+
def build(parent, **args)
|
9
|
+
super(parent, **args)
|
10
10
|
parent.tk_widget['menu'] = tk_widget
|
11
11
|
end
|
12
12
|
|
@@ -15,15 +15,18 @@ class TkWrapper::Widgets::Menu < TkWrapper::Widgets::Base::Widget
|
|
15
15
|
TkWidgets::TkMenu
|
16
16
|
end
|
17
17
|
|
18
|
-
def build(parent)
|
19
|
-
|
18
|
+
def build(parent, **args)
|
19
|
+
args[:configure] = false
|
20
|
+
super(parent, **args)
|
20
21
|
@config[:menu] = tk_widget
|
21
22
|
parent.tk_widget.add :cascade, **@config.config
|
22
23
|
end
|
23
24
|
end
|
24
25
|
|
25
26
|
class Command < TkWrapper::Widgets::Base::Widget
|
26
|
-
def build(parent)
|
27
|
+
def build(parent, **args)
|
28
|
+
args[:configure] = false
|
29
|
+
super(parent, **args)
|
27
30
|
parent.tk_widget.add :command, **@config.config
|
28
31
|
end
|
29
32
|
end
|
@@ -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/widgets.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tkwrapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
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-20 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: []
|
@@ -19,18 +33,29 @@ files:
|
|
19
33
|
- lib/tk_extensions.rb
|
20
34
|
- lib/tkwrapper.rb
|
21
35
|
- lib/util/hash_recursive.rb
|
36
|
+
- lib/util/tk/cell.rb
|
37
|
+
- lib/util/tk/finder.rb
|
38
|
+
- lib/util/tk/font.rb
|
39
|
+
- lib/util/tk/tk.rb
|
22
40
|
- lib/util/virtual_methods.rb
|
23
41
|
- lib/widgets/auto_resize_entry.rb
|
24
42
|
- lib/widgets/base/base.rb
|
43
|
+
- lib/widgets/base/comparator_item_store.rb
|
25
44
|
- lib/widgets/base/configuration.rb
|
26
45
|
- lib/widgets/base/manager.rb
|
46
|
+
- lib/widgets/base/match.rb
|
47
|
+
- lib/widgets/base/matcher.rb
|
48
|
+
- lib/widgets/base/matches.rb
|
27
49
|
- lib/widgets/base/widget.rb
|
28
|
-
- lib/widgets/base/
|
50
|
+
- lib/widgets/base/widget_store.rb
|
51
|
+
- lib/widgets/base/window_info.rb
|
52
|
+
- lib/widgets/button.rb
|
29
53
|
- lib/widgets/entry.rb
|
30
54
|
- lib/widgets/frame.rb
|
31
55
|
- lib/widgets/grid.rb
|
32
56
|
- lib/widgets/label.rb
|
33
57
|
- lib/widgets/menu.rb
|
58
|
+
- lib/widgets/mount_point.rb
|
34
59
|
- lib/widgets/root.rb
|
35
60
|
- lib/widgets/text.rb
|
36
61
|
- lib/widgets/widgets.rb
|
data/lib/widgets/base/widgets.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class TkWrapper::Widgets::Base::Widgets
|
4
|
-
def initialize
|
5
|
-
@configurations = []
|
6
|
-
@modifications = []
|
7
|
-
end
|
8
|
-
|
9
|
-
def add_configuration(matcher, configuration)
|
10
|
-
@configurations.push(matcher, configuration)
|
11
|
-
end
|
12
|
-
|
13
|
-
def add_modification(matcher, &callback)
|
14
|
-
@modifications.push(matcher, callback)
|
15
|
-
end
|
16
|
-
|
17
|
-
def configurations(widget)
|
18
|
-
@configurations.filter_map do |(matcher, config)|
|
19
|
-
config if widget.check_match(matcher)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def execute_modifications(widget)
|
24
|
-
@modifications.each do |(matcher, callback)|
|
25
|
-
next unless (match = widget.check_match(matcher))
|
26
|
-
|
27
|
-
arguments = match.is_a?(MatchData) ? [widget, match] : [widget]
|
28
|
-
callback.call(*arguments)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|