tkwrapper 1.6.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a67fc8eac231f5b0b875cdd2fba4f107a3b596206766a4e57793e4f3d1b71992
4
- data.tar.gz: 9bd2376b17ebf7e866f7858f98d2e9698575dec8a3fa2794c84c7b625048b33c
3
+ metadata.gz: 90b29c12036c765281e148238dd8b97afc06091749eeb5c8a8595ce8a3ddd589
4
+ data.tar.gz: 8c7b8f7f3b5c9b54a239d9d7d034b14d8cde4e700d848e98d2b77329da03aa8b
5
5
  SHA512:
6
- metadata.gz: b467177153264f4a1cf973e4ae321d57c94f421e14eddfac98db6766ed06ca133f7af73931ef3f2ca3b23800363dacc533c666fb883f2bcb01c19a5432250b75
7
- data.tar.gz: 00f36bd8f579688715d25b580a028e577f3820a83749b39bfd353c90ed32a3e0509ebcc5ca0306a3cf48576dd3d52d136e093ad26d87a33212cb84cb9a09b456
6
+ metadata.gz: 402470958a23a858dbe40ab101e31b61fd7ccbf6c240dbaa83a9c6e6727c94ca1a5e81e9d73ab571fc3c85b0ba275fece636793eacb487a98a60ed85bffc1661
7
+ data.tar.gz: 3f74e9a050ec620ea4d77bc0e518dff8fe4037e79c37d5ca111d85f33d52288dc663449ba760a963fa26fb5dd2bcafb6d6edd9ecc6b84ac0831f67e1456bdbf1
data/lib/util/array.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Util
4
+ def self.first_not_nil(array, default = nil)
5
+ index = indexes.find { |i| !array[i].nil? }
6
+ index.nil? ? default : array[index]
7
+ end
8
+ 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
@@ -2,24 +2,97 @@
2
2
 
3
3
  require_relative 'text'
4
4
 
5
- class TkWrapper::Widgets::AutoResizeText < TkWrapper::Widgets::Text
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
+
6
26
  def build(parent, **args)
7
27
  super(parent, **args)
8
- bind('<Modified>', ->(ev) { resize(ev) })
9
- bind('<Modified>', -> { puts 'hihi' })
10
- end
11
-
12
- def resize(event)
13
- return unless tk_widget.modified?
14
-
15
- puts event
16
- puts 'yes!'
17
- tk_widget.modified(false)
18
- #max_width = [@cell.bbox[2], 0].max
19
- #puts @font.metrics
20
- #new_width = [[@min_width, text_width + @add_width].max, max_width].min
21
- #tk_widget.width = 0
22
- #tk_widget.grid(ipadx: new_width / 2.0)
23
- #@parent.tk_widget.update
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)
24
97
  end
25
98
  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
@@ -3,6 +3,7 @@ require "#{LIB_DIR}/util/tk/finder"
3
3
 
4
4
  require_relative 'base'
5
5
  require_relative 'window_info'
6
+ require_relative 'tk_options'
6
7
 
7
8
  class TkWrapper::Widgets::Base::Widget
8
9
  extend Forwardable
@@ -14,14 +15,12 @@ class TkWrapper::Widgets::Base::Widget
14
15
  def_delegator :@manager, :widgets, :managed
15
16
 
16
17
  attr_accessor :config
17
- attr_reader :parent, :ids, :cell, :childs, :manager, :winfo
18
+ attr_reader :parent, :ids, :cell, :childs, :manager, :winfo, :opts, :font
18
19
 
19
20
  def tk_class() end
20
21
 
21
22
  def initialize(parent: nil, config: {}, childs: [], manager: nil, ids: [], id: [])
22
- @cell = TkWrapper::Util::Tk::Cell.new(self)
23
- @winfo = TkWrapper::Widgets::Base::WindowInfo.new(self)
24
- @finder = TkWrapper::Util::Tk::Finder.new(widgets: self)
23
+ initialize_utilities
25
24
  @config = TkWrapper::Widgets::Base::Configuration.new(config)
26
25
  @manager = manager
27
26
  @ids = init_id(id) + init_id(ids)
@@ -31,6 +30,13 @@ class TkWrapper::Widgets::Base::Widget
31
30
  parent&.push(self)
32
31
  end
33
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
+
34
40
  def init_id(id)
35
41
  id.is_a?(Array) ? id : [id]
36
42
  end
@@ -10,4 +10,8 @@ class TkWrapper::Widgets::Base::WindowInfo
10
10
  super
11
11
  end
12
12
  end
13
+
14
+ def respond_to_missing?(name, *)
15
+ @widget.tk_widget.respond_to?("winfo_#{name}") || super
16
+ end
13
17
  end
data/lib/widgets/frame.rb CHANGED
@@ -6,4 +6,12 @@ class TkWrapper::Widgets::Frame < TkWrapper::Widgets::Base::Widget
6
6
  def tk_class
7
7
  Tk::Tile::Frame
8
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
16
+ end
9
17
  end
data/lib/widgets/text.rb CHANGED
@@ -6,4 +6,61 @@ class TkWrapper::Widgets::Text < TkWrapper::Widgets::Base::Widget
6
6
  def tk_class
7
7
  TkText
8
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)
65
+ end
9
66
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tkwrapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.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-21 00:00:00.000000000 Z
11
+ date: 2021-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tk
@@ -31,6 +31,7 @@ extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
33
  - lib/tkwrapper.rb
34
+ - lib/util/array.rb
34
35
  - lib/util/hash_recursive.rb
35
36
  - lib/util/tk/cell.rb
36
37
  - lib/util/tk/finder.rb
@@ -46,6 +47,8 @@ files:
46
47
  - lib/widgets/base/match.rb
47
48
  - lib/widgets/base/matcher.rb
48
49
  - lib/widgets/base/matches.rb
50
+ - lib/widgets/base/padding.rb
51
+ - lib/widgets/base/tk_options.rb
49
52
  - lib/widgets/base/widget.rb
50
53
  - lib/widgets/base/widget_store.rb
51
54
  - lib/widgets/base/window_info.rb