tksheet 7.3.1__py3-none-any.whl → 7.3.2__py3-none-any.whl
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.
- tksheet/__init__.py +2 -2
- tksheet/column_headers.py +22 -36
- tksheet/find_window.py +251 -0
- tksheet/formatters.py +1 -1
- tksheet/functions.py +60 -41
- tksheet/main_table.py +436 -265
- tksheet/other_classes.py +6 -9
- tksheet/row_index.py +23 -35
- tksheet/sheet.py +75 -21
- tksheet/sheet_options.py +16 -1
- tksheet/text_editor.py +1 -1
- tksheet/top_left_rectangle.py +1 -1
- {tksheet-7.3.1.dist-info → tksheet-7.3.2.dist-info}/METADATA +10 -11
- tksheet-7.3.2.dist-info/RECORD +21 -0
- {tksheet-7.3.1.dist-info → tksheet-7.3.2.dist-info}/WHEEL +1 -1
- tksheet-7.3.1.dist-info/RECORD +0 -20
- /tksheet/{vars.py → constants.py} +0 -0
- {tksheet-7.3.1.dist-info → tksheet-7.3.2.dist-info}/LICENSE.txt +0 -0
- {tksheet-7.3.1.dist-info → tksheet-7.3.2.dist-info}/top_level.txt +0 -0
tksheet/main_table.py
CHANGED
@@ -39,6 +39,22 @@ from typing import Literal
|
|
39
39
|
from .colors import (
|
40
40
|
color_map,
|
41
41
|
)
|
42
|
+
from .constants import (
|
43
|
+
USER_OS,
|
44
|
+
bind_add_columns,
|
45
|
+
bind_add_rows,
|
46
|
+
bind_del_columns,
|
47
|
+
bind_del_rows,
|
48
|
+
ctrl_key,
|
49
|
+
rc_binding,
|
50
|
+
text_editor_close_bindings,
|
51
|
+
text_editor_newline_bindings,
|
52
|
+
text_editor_to_unbind,
|
53
|
+
val_modifying_options,
|
54
|
+
)
|
55
|
+
from .find_window import (
|
56
|
+
FindWindow,
|
57
|
+
)
|
42
58
|
from .formatters import (
|
43
59
|
data_to_str,
|
44
60
|
format_data,
|
@@ -50,6 +66,7 @@ from .formatters import (
|
|
50
66
|
from .functions import (
|
51
67
|
add_to_displayed,
|
52
68
|
b_index,
|
69
|
+
bisect_in,
|
53
70
|
box_is_single_cell,
|
54
71
|
cell_right_within_box,
|
55
72
|
color_tup,
|
@@ -58,6 +75,8 @@ from .functions import (
|
|
58
75
|
diff_list,
|
59
76
|
down_cell_within_box,
|
60
77
|
event_dict,
|
78
|
+
event_has_char_key,
|
79
|
+
event_opens_dropdown_or_checkbox,
|
61
80
|
float_to_int,
|
62
81
|
gen_formatted,
|
63
82
|
get_data_from_clipboard,
|
@@ -86,6 +105,7 @@ from .other_classes import (
|
|
86
105
|
Box_t,
|
87
106
|
DotDict,
|
88
107
|
DropdownStorage,
|
108
|
+
EditorStorageBase,
|
89
109
|
EventDataDict,
|
90
110
|
FontTuple,
|
91
111
|
Highlight,
|
@@ -101,20 +121,6 @@ from .text_editor import (
|
|
101
121
|
from .types import (
|
102
122
|
AnyIter,
|
103
123
|
)
|
104
|
-
from .vars import (
|
105
|
-
USER_OS,
|
106
|
-
bind_add_columns,
|
107
|
-
bind_add_rows,
|
108
|
-
bind_del_columns,
|
109
|
-
bind_del_rows,
|
110
|
-
ctrl_key,
|
111
|
-
rc_binding,
|
112
|
-
symbols_set,
|
113
|
-
text_editor_close_bindings,
|
114
|
-
text_editor_newline_bindings,
|
115
|
-
text_editor_to_unbind,
|
116
|
-
val_modifying_options,
|
117
|
-
)
|
118
124
|
|
119
125
|
|
120
126
|
class MainTable(tk.Canvas):
|
@@ -140,6 +146,7 @@ class MainTable(tk.Canvas):
|
|
140
146
|
self.synced_scrolls = set()
|
141
147
|
self.dropdown = DropdownStorage()
|
142
148
|
self.text_editor = TextEditorStorage()
|
149
|
+
self.find_window = EditorStorageBase()
|
143
150
|
self.event_linker = {
|
144
151
|
"<<Copy>>": self.ctrl_c,
|
145
152
|
"<<Cut>>": self.ctrl_x,
|
@@ -248,6 +255,7 @@ class MainTable(tk.Canvas):
|
|
248
255
|
self.drag_selection_enabled = False
|
249
256
|
self.select_all_enabled = False
|
250
257
|
self.undo_enabled = False
|
258
|
+
self.find_enabled = False
|
251
259
|
self.cut_enabled = False
|
252
260
|
self.copy_enabled = False
|
253
261
|
self.paste_enabled = False
|
@@ -476,6 +484,250 @@ class MainTable(tk.Canvas):
|
|
476
484
|
if delete_on_timer:
|
477
485
|
self.after(1500, self.delete_ctrl_outlines)
|
478
486
|
|
487
|
+
def escape(self, event: tk.Misc | None) -> None:
|
488
|
+
if self.find_window.open:
|
489
|
+
self.close_find_window()
|
490
|
+
else:
|
491
|
+
self.deselect()
|
492
|
+
|
493
|
+
def get_find_window_dimensions_coords(self, w_width: int) -> tuple[int, int, int, int]:
|
494
|
+
width = min(self.get_txt_w("X" * 23), w_width - 7)
|
495
|
+
# w, h, x, y
|
496
|
+
return width, self.min_row_height, self.canvasx(max(0, w_width - width - 7)), self.canvasy(7)
|
497
|
+
|
498
|
+
def open_find_window(
|
499
|
+
self,
|
500
|
+
event: tk.Misc | None = None,
|
501
|
+
focus: bool = True,
|
502
|
+
) -> Literal["break"]:
|
503
|
+
if self.find_window.open:
|
504
|
+
self.close_find_window()
|
505
|
+
return "break"
|
506
|
+
width, height, x, y = self.get_find_window_dimensions_coords(w_width=self.winfo_width())
|
507
|
+
if not self.find_window.window:
|
508
|
+
self.find_window.window = FindWindow(
|
509
|
+
self,
|
510
|
+
find_prev_func=self.find_previous,
|
511
|
+
find_next_func=self.find_next,
|
512
|
+
close_func=self.close_find_window,
|
513
|
+
)
|
514
|
+
self.find_window.canvas_id = self.create_window((x, y), window=self.find_window.window, anchor="nw")
|
515
|
+
for b in chain(self.PAR.ops.escape_bindings, self.PAR.ops.find_bindings):
|
516
|
+
self.find_window.tktext.bind(b, self.close_find_window)
|
517
|
+
for b in chain(self.PAR.ops.find_next_bindings, ("<Return>", "<KP_Enter>")):
|
518
|
+
self.find_window.tktext.bind(b, self.find_next)
|
519
|
+
for b in self.PAR.ops.find_previous_bindings:
|
520
|
+
self.find_window.tktext.bind(b, self.find_previous)
|
521
|
+
else:
|
522
|
+
self.coords(self.find_window.canvas_id, x, y)
|
523
|
+
if not self.find_window.open:
|
524
|
+
self.itemconfig(self.find_window.canvas_id, state="normal")
|
525
|
+
self.find_window.open = True
|
526
|
+
self.find_window.window.reset(
|
527
|
+
**{
|
528
|
+
"menu_kwargs": DotDict(
|
529
|
+
{
|
530
|
+
"font": self.PAR.ops.table_font,
|
531
|
+
"foreground": self.PAR.ops.popup_menu_fg,
|
532
|
+
"background": self.PAR.ops.popup_menu_bg,
|
533
|
+
"activebackground": self.PAR.ops.popup_menu_highlight_bg,
|
534
|
+
"activeforeground": self.PAR.ops.popup_menu_highlight_fg,
|
535
|
+
}
|
536
|
+
),
|
537
|
+
"sheet_ops": self.PAR.ops,
|
538
|
+
"border_color": self.PAR.ops.table_selected_box_cells_fg,
|
539
|
+
"bg": self.PAR.ops.table_editor_bg,
|
540
|
+
"fg": self.PAR.ops.table_editor_fg,
|
541
|
+
"select_bg": self.PAR.ops.table_editor_select_bg,
|
542
|
+
"select_fg": self.PAR.ops.table_editor_select_fg,
|
543
|
+
}
|
544
|
+
)
|
545
|
+
self.itemconfig(self.find_window.canvas_id, width=width, height=height)
|
546
|
+
if focus:
|
547
|
+
self.find_window.tktext.focus_set()
|
548
|
+
return "break"
|
549
|
+
|
550
|
+
def find_see_and_set(self, coords: tuple[int, int] | None, just_see: bool = False) -> tuple[int, int]:
|
551
|
+
if coords:
|
552
|
+
if not self.all_rows_displayed:
|
553
|
+
coords = (self.disprn(coords[0]), coords[1])
|
554
|
+
if not self.all_columns_displayed:
|
555
|
+
coords = (coords[0], self.dispcn(coords[1]))
|
556
|
+
if not just_see:
|
557
|
+
if self.find_window.window.find_in_selection:
|
558
|
+
self.set_currently_selected(*coords)
|
559
|
+
else:
|
560
|
+
self.select_cell(*coords, redraw=False)
|
561
|
+
if not self.see(
|
562
|
+
*coords,
|
563
|
+
keep_yscroll=False,
|
564
|
+
keep_xscroll=False,
|
565
|
+
bottom_right_corner=False,
|
566
|
+
check_cell_visibility=True,
|
567
|
+
redraw=True,
|
568
|
+
):
|
569
|
+
self.refresh()
|
570
|
+
return coords
|
571
|
+
|
572
|
+
def find_gen_all_cells(
|
573
|
+
self,
|
574
|
+
start_row: int,
|
575
|
+
start_col: int,
|
576
|
+
total_cols: int | None = None,
|
577
|
+
reverse: bool = False,
|
578
|
+
) -> Generator[tuple[int, int]]:
|
579
|
+
if total_cols is None:
|
580
|
+
total_cols = self.total_data_cols(include_header=False)
|
581
|
+
total_rows = self.total_data_rows(include_index=False)
|
582
|
+
if reverse:
|
583
|
+
# yield start cell
|
584
|
+
yield (start_row, start_col)
|
585
|
+
# yield any remaining cells in the starting row before the start column
|
586
|
+
if start_col:
|
587
|
+
for col in reversed(range(start_col)):
|
588
|
+
yield (start_row, col)
|
589
|
+
# yield any cells above start row
|
590
|
+
for row in reversed(range(start_row)):
|
591
|
+
for col in reversed(range(total_cols)):
|
592
|
+
yield (row, col)
|
593
|
+
# yield cells from bottom of table upward
|
594
|
+
for row in range(total_rows - 1, start_row, -1):
|
595
|
+
for col in reversed(range(total_cols)):
|
596
|
+
yield (row, col)
|
597
|
+
# yield any remaining cells in start row
|
598
|
+
for col in range(total_cols - 1, start_col, -1):
|
599
|
+
yield (start_row, col)
|
600
|
+
else:
|
601
|
+
# Yield cells from the start position to the end of the current row
|
602
|
+
for col in range(start_col, total_cols):
|
603
|
+
yield (start_row, col)
|
604
|
+
# yield from the next row to the last row
|
605
|
+
for row in range(start_row + 1, total_rows):
|
606
|
+
for col in range(total_cols):
|
607
|
+
yield (row, col)
|
608
|
+
# yield from the beginning up to the start
|
609
|
+
for row in range(start_row):
|
610
|
+
for col in range(total_cols):
|
611
|
+
yield (row, col)
|
612
|
+
# yield any remaining cells in the starting row before the start column
|
613
|
+
for col in range(start_col):
|
614
|
+
yield (start_row, col)
|
615
|
+
|
616
|
+
def find_get_start_coords(
|
617
|
+
self,
|
618
|
+
plus_one: bool = True,
|
619
|
+
within: None | list = None,
|
620
|
+
reverse: bool = False,
|
621
|
+
) -> tuple[int, int, int]:
|
622
|
+
selected = self.selected
|
623
|
+
if not selected:
|
624
|
+
return 0, 0, 0
|
625
|
+
max_row = len(self.row_positions) - 2
|
626
|
+
max_col = len(self.col_positions) - 2
|
627
|
+
row, col = selected.row, selected.column
|
628
|
+
if plus_one and within:
|
629
|
+
curridx = bisect_left(within, (row, col)) + (1 if not reverse else -1)
|
630
|
+
return row, col, curridx % len(within)
|
631
|
+
if plus_one:
|
632
|
+
if reverse:
|
633
|
+
if col == 0:
|
634
|
+
col = max_col
|
635
|
+
row = max_row if row == 0 else row - 1
|
636
|
+
else:
|
637
|
+
col -= 1
|
638
|
+
else:
|
639
|
+
col = (col + 1) % (max_col + 1)
|
640
|
+
if col == 0:
|
641
|
+
row = (row + 1) % (max_row + 1)
|
642
|
+
return row, col, 0
|
643
|
+
|
644
|
+
def find_match(self, find: str, r: int, c: int) -> bool:
|
645
|
+
return (
|
646
|
+
not find
|
647
|
+
and (not self.get_valid_cell_data_as_str(r, c, True).lower() or not f"{self.get_cell_data(r, c)}".lower())
|
648
|
+
) or (
|
649
|
+
find
|
650
|
+
and (
|
651
|
+
find in self.get_valid_cell_data_as_str(r, c, True).lower()
|
652
|
+
or find in f"{self.get_cell_data(r, c)}".lower()
|
653
|
+
)
|
654
|
+
)
|
655
|
+
|
656
|
+
def find_within_sels(
|
657
|
+
self,
|
658
|
+
find: str,
|
659
|
+
reverse: bool = False,
|
660
|
+
) -> tuple[int, int] | None:
|
661
|
+
sels = self.PAR.get_selected_cells(
|
662
|
+
get_rows=True,
|
663
|
+
get_columns=True,
|
664
|
+
sort_by_row=True,
|
665
|
+
sort_by_column=True,
|
666
|
+
)
|
667
|
+
_, _, from_idx = self.find_get_start_coords(plus_one=True, within=sels, reverse=reverse)
|
668
|
+
for r, c in chain(islice(sels, from_idx, None), islice(sels, 0, from_idx)):
|
669
|
+
if not self.all_rows_displayed:
|
670
|
+
r = self.datarn(r)
|
671
|
+
if not self.all_columns_displayed:
|
672
|
+
c = self.datacn(c)
|
673
|
+
if self.find_match(find, r, c):
|
674
|
+
return (r, c)
|
675
|
+
return None
|
676
|
+
|
677
|
+
def find_all_cells(
|
678
|
+
self,
|
679
|
+
find: str,
|
680
|
+
reverse: bool = False,
|
681
|
+
) -> tuple[int, int] | None:
|
682
|
+
row, col, _ = self.find_get_start_coords(plus_one=True, reverse=reverse)
|
683
|
+
row, col = self.datarn(row), self.datacn(col)
|
684
|
+
return next(
|
685
|
+
(
|
686
|
+
(r, c)
|
687
|
+
for r, c in self.find_gen_all_cells(
|
688
|
+
start_row=row,
|
689
|
+
start_col=col,
|
690
|
+
total_cols=self.total_data_cols(include_header=False),
|
691
|
+
reverse=reverse,
|
692
|
+
)
|
693
|
+
if (
|
694
|
+
(self.all_rows_displayed or bisect_in(self.displayed_rows, r))
|
695
|
+
and (self.all_columns_displayed or bisect_in(self.displayed_columns, c))
|
696
|
+
and self.find_match(find, r, c)
|
697
|
+
)
|
698
|
+
),
|
699
|
+
None,
|
700
|
+
)
|
701
|
+
|
702
|
+
def find_next(self, event: tk.Misc | None = None) -> Literal["break"]:
|
703
|
+
find = self.find_window.get().lower()
|
704
|
+
if not self.find_window.open:
|
705
|
+
self.open_find_window(focus=False)
|
706
|
+
if self.find_window.window.find_in_selection:
|
707
|
+
self.find_see_and_set(self.find_within_sels(find))
|
708
|
+
else:
|
709
|
+
self.find_see_and_set(self.find_all_cells(find))
|
710
|
+
return "break"
|
711
|
+
|
712
|
+
def find_previous(self, event: tk.Misc | None = None) -> Literal["break"]:
|
713
|
+
find = self.find_window.get().lower()
|
714
|
+
if not self.find_window.open:
|
715
|
+
self.open_find_window(focus=False)
|
716
|
+
if self.find_window.window.find_in_selection:
|
717
|
+
self.find_see_and_set(self.find_within_sels(find, reverse=True))
|
718
|
+
else:
|
719
|
+
self.find_see_and_set(self.find_all_cells(find, reverse=True))
|
720
|
+
return "break"
|
721
|
+
|
722
|
+
def close_find_window(
|
723
|
+
self,
|
724
|
+
event: tk.Misc | None = None,
|
725
|
+
) -> None:
|
726
|
+
if self.find_window.open:
|
727
|
+
self.itemconfig(self.find_window.canvas_id, state="hidden")
|
728
|
+
self.find_window.open = False
|
729
|
+
self.focus_set()
|
730
|
+
|
479
731
|
def create_ctrl_outline(
|
480
732
|
self,
|
481
733
|
x1: int,
|
@@ -527,19 +779,19 @@ class MainTable(tk.Canvas):
|
|
527
779
|
self.hidd_ctrl_outline[t] = False
|
528
780
|
|
529
781
|
def get_ctrl_x_c_boxes(self) -> tuple[dict[tuple[int, int, int, int], str], int]:
|
530
|
-
boxes = {}
|
531
782
|
maxrows = 0
|
532
783
|
if not self.selected:
|
533
|
-
return
|
784
|
+
return {}, maxrows
|
534
785
|
if self.selected.type_ in ("cells", "columns"):
|
535
786
|
curr_box = self.selection_boxes[self.selected.fill_iid].coords
|
536
787
|
maxrows = curr_box[2] - curr_box[0]
|
537
|
-
|
538
|
-
|
539
|
-
|
788
|
+
boxes = {
|
789
|
+
box.coords: box.type_
|
790
|
+
for _, box in self.get_selection_items(rows=False)
|
791
|
+
if maxrows >= box.coords[2] - box.coords[0]
|
792
|
+
}
|
540
793
|
else:
|
541
|
-
for
|
542
|
-
boxes[box.coords] = "rows"
|
794
|
+
boxes = {box.coords: "rows" for _, box in self.get_selection_items(columns=False, cells=False)}
|
543
795
|
return boxes, maxrows
|
544
796
|
|
545
797
|
def io_csv_writer(self) -> tuple[io.StringIO, csv.writer]:
|
@@ -1750,23 +2002,23 @@ class MainTable(tk.Canvas):
|
|
1750
2002
|
y = self.row_positions[r]
|
1751
2003
|
else:
|
1752
2004
|
y = self.row_positions[r + 1] + 1 - winfo_height
|
2005
|
+
y = y / (self.row_positions[-1] + self.PAR.ops.empty_vertical)
|
1753
2006
|
args = [
|
1754
2007
|
"moveto",
|
1755
|
-
y
|
2008
|
+
y - 1 if y > 1 else y,
|
1756
2009
|
]
|
1757
|
-
if args[1] > 1:
|
1758
|
-
args[1] = args[1] - 1
|
1759
2010
|
self.set_yviews(*args, redraw=False)
|
1760
2011
|
need_redraw = True
|
1761
2012
|
else:
|
1762
2013
|
if r is not None and not keep_yscroll:
|
1763
|
-
y = self.row_positions[r] + ((self.row_positions[r + 1] - self.row_positions[r]) * r_pc)
|
2014
|
+
y = int(self.row_positions[r] + ((self.row_positions[r + 1] - self.row_positions[r]) * r_pc)) - 2
|
2015
|
+
if y < 0:
|
2016
|
+
y = 0
|
2017
|
+
y = y / (self.row_positions[-1] + self.PAR.ops.empty_vertical)
|
1764
2018
|
args = [
|
1765
2019
|
"moveto",
|
1766
|
-
y
|
2020
|
+
y - 1 if y > 1 else y,
|
1767
2021
|
]
|
1768
|
-
if args[1] > 1:
|
1769
|
-
args[1] = args[1] - 1
|
1770
2022
|
self.set_yviews(*args, redraw=False)
|
1771
2023
|
need_redraw = True
|
1772
2024
|
if not xvis and len(self.col_positions) > 1:
|
@@ -1777,18 +2029,22 @@ class MainTable(tk.Canvas):
|
|
1777
2029
|
x = self.col_positions[c]
|
1778
2030
|
else:
|
1779
2031
|
x = self.col_positions[c + 1] + 1 - winfo_width
|
2032
|
+
x = x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal)
|
1780
2033
|
args = [
|
1781
2034
|
"moveto",
|
1782
|
-
x
|
2035
|
+
x - 1 if x > 1 else x,
|
1783
2036
|
]
|
1784
2037
|
self.set_xviews(*args, redraw=False)
|
1785
2038
|
need_redraw = True
|
1786
2039
|
else:
|
1787
2040
|
if c is not None and not keep_xscroll:
|
1788
|
-
x = self.col_positions[c] + ((self.col_positions[c + 1] - self.col_positions[c]) * c_pc)
|
2041
|
+
x = int(self.col_positions[c] + ((self.col_positions[c + 1] - self.col_positions[c]) * c_pc)) - 2
|
2042
|
+
if x < 0:
|
2043
|
+
x = 0
|
2044
|
+
x = x / (self.col_positions[-1] + self.PAR.ops.empty_horizontal)
|
1789
2045
|
args = [
|
1790
2046
|
"moveto",
|
1791
|
-
x
|
2047
|
+
x - 1 if x > 1 else x,
|
1792
2048
|
]
|
1793
2049
|
self.set_xviews(*args, redraw=False)
|
1794
2050
|
need_redraw = True
|
@@ -1810,20 +2066,12 @@ class MainTable(tk.Canvas):
|
|
1810
2066
|
r: int | None = 0,
|
1811
2067
|
c: int | None = 0,
|
1812
2068
|
separate_axes: bool = False,
|
1813
|
-
) -> bool:
|
2069
|
+
) -> bool | tuple[bool, bool]:
|
1814
2070
|
cx1, cy1, cx2, cy2 = self.get_canvas_visible_area()
|
1815
2071
|
x1, y1, x2, y2 = self.get_cell_coords(r, c)
|
1816
|
-
x_vis =
|
1817
|
-
y_vis =
|
1818
|
-
|
1819
|
-
x_vis = False
|
1820
|
-
if cy1 > y1 or cy2 < y2:
|
1821
|
-
y_vis = False
|
1822
|
-
if separate_axes:
|
1823
|
-
return y_vis, x_vis
|
1824
|
-
if not y_vis or not x_vis:
|
1825
|
-
return False
|
1826
|
-
return True
|
2072
|
+
x_vis = cx1 <= x1 and cx2 >= x2
|
2073
|
+
y_vis = cy1 <= y1 and cy2 >= y2
|
2074
|
+
return (y_vis, x_vis) if separate_axes else y_vis and x_vis
|
1827
2075
|
|
1828
2076
|
def cell_visible(self, r: int = 0, c: int = 0) -> bool:
|
1829
2077
|
cx1, cy1, cx2, cy2 = self.get_canvas_visible_area()
|
@@ -1877,13 +2125,13 @@ class MainTable(tk.Canvas):
|
|
1877
2125
|
|
1878
2126
|
def select_row_start(self, event: object) -> None:
|
1879
2127
|
if self.selected:
|
1880
|
-
self.select_cell(self.selected.row, 0)
|
1881
2128
|
self.see(self.selected.row, 0)
|
2129
|
+
self.select_cell(self.selected.row, 0, redraw=True)
|
1882
2130
|
|
1883
2131
|
def select_a1(self, event: object) -> None:
|
1884
2132
|
if len(self.row_positions) > 1 and len(self.col_positions) > 1:
|
1885
|
-
self.select_cell(0, 0)
|
1886
2133
|
self.see(0, 0)
|
2134
|
+
self.select_cell(0, 0, redraw=True)
|
1887
2135
|
|
1888
2136
|
def select_cell(
|
1889
2137
|
self,
|
@@ -2213,9 +2461,8 @@ class MainTable(tk.Canvas):
|
|
2213
2461
|
elif self.selected.type_ in ("cells", "columns"):
|
2214
2462
|
r = self.selected.row
|
2215
2463
|
c = self.selected.column
|
2216
|
-
if not r and self.CH.col_selection_enabled:
|
2217
|
-
|
2218
|
-
self.see(r, c, check_cell_visibility=False)
|
2464
|
+
if not r and self.CH.col_selection_enabled and not self.cell_completely_visible(r=r, c=c):
|
2465
|
+
self.see(r, c, check_cell_visibility=False)
|
2219
2466
|
elif r and (self.single_selection_enabled or self.toggle_selection_enabled):
|
2220
2467
|
if self.cell_completely_visible(r=r - 1, c=c):
|
2221
2468
|
self.select_cell(r - 1, c, redraw=True)
|
@@ -2229,32 +2476,18 @@ class MainTable(tk.Canvas):
|
|
2229
2476
|
if self.selected.type_ == "rows":
|
2230
2477
|
r = self.selected.row
|
2231
2478
|
if r < len(self.row_positions) - 2 and self.RI.row_selection_enabled:
|
2232
|
-
if self.cell_completely_visible(r=
|
2479
|
+
if self.cell_completely_visible(r=r + 1, c=0):
|
2233
2480
|
self.RI.select_row(r + 1, redraw=True)
|
2234
2481
|
else:
|
2235
2482
|
self.RI.select_row(r + 1)
|
2236
|
-
|
2237
|
-
r +
|
2238
|
-
|
2239
|
-
|
2240
|
-
|
2241
|
-
|
2242
|
-
)
|
2243
|
-
|
2244
|
-
r + 2,
|
2245
|
-
0,
|
2246
|
-
keep_xscroll=True,
|
2247
|
-
bottom_right_corner=True,
|
2248
|
-
check_cell_visibility=False,
|
2249
|
-
)
|
2250
|
-
elif not self.cell_completely_visible(r=r + 1, c=0):
|
2251
|
-
self.see(
|
2252
|
-
r + 1,
|
2253
|
-
0,
|
2254
|
-
keep_xscroll=True,
|
2255
|
-
bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
|
2256
|
-
check_cell_visibility=False,
|
2257
|
-
)
|
2483
|
+
self.see(
|
2484
|
+
r + 1,
|
2485
|
+
0,
|
2486
|
+
keep_xscroll=True,
|
2487
|
+
bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
|
2488
|
+
check_cell_visibility=False,
|
2489
|
+
)
|
2490
|
+
|
2258
2491
|
elif self.selected.type_ == "columns":
|
2259
2492
|
c = self.selected.column
|
2260
2493
|
if self.single_selection_enabled or self.toggle_selection_enabled:
|
@@ -2275,32 +2508,17 @@ class MainTable(tk.Canvas):
|
|
2275
2508
|
r = self.selected.row
|
2276
2509
|
c = self.selected.column
|
2277
2510
|
if r < len(self.row_positions) - 2 and (self.single_selection_enabled or self.toggle_selection_enabled):
|
2278
|
-
if self.cell_completely_visible(r=
|
2511
|
+
if self.cell_completely_visible(r=r + 1, c=c):
|
2279
2512
|
self.select_cell(r + 1, c, redraw=True)
|
2280
2513
|
else:
|
2281
2514
|
self.select_cell(r + 1, c)
|
2282
|
-
|
2283
|
-
r +
|
2284
|
-
|
2285
|
-
|
2286
|
-
|
2287
|
-
|
2288
|
-
)
|
2289
|
-
self.see(
|
2290
|
-
r + 2,
|
2291
|
-
c,
|
2292
|
-
keep_xscroll=True,
|
2293
|
-
bottom_right_corner=True,
|
2294
|
-
check_cell_visibility=False,
|
2295
|
-
)
|
2296
|
-
elif not self.cell_completely_visible(r=r + 1, c=c):
|
2297
|
-
self.see(
|
2298
|
-
r + 1,
|
2299
|
-
c,
|
2300
|
-
keep_xscroll=True,
|
2301
|
-
bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
|
2302
|
-
check_cell_visibility=False,
|
2303
|
-
)
|
2515
|
+
self.see(
|
2516
|
+
r + 1,
|
2517
|
+
c,
|
2518
|
+
keep_xscroll=True,
|
2519
|
+
bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
|
2520
|
+
check_cell_visibility=False,
|
2521
|
+
)
|
2304
2522
|
|
2305
2523
|
def arrowkey_LEFT(self, event: object = None) -> None:
|
2306
2524
|
if not self.selected:
|
@@ -2325,7 +2543,7 @@ class MainTable(tk.Canvas):
|
|
2325
2543
|
elif self.selected.type_ == "cells":
|
2326
2544
|
r = self.selected.row
|
2327
2545
|
c = self.selected.column
|
2328
|
-
if not c and not self.cell_completely_visible(r=r, c=
|
2546
|
+
if not c and not self.cell_completely_visible(r=r, c=c):
|
2329
2547
|
self.see(r, c, keep_yscroll=True, check_cell_visibility=False)
|
2330
2548
|
elif c and (self.single_selection_enabled or self.toggle_selection_enabled):
|
2331
2549
|
if self.cell_completely_visible(r=r, c=c - 1):
|
@@ -2710,7 +2928,7 @@ class MainTable(tk.Canvas):
|
|
2710
2928
|
**mnkwgs,
|
2711
2929
|
)
|
2712
2930
|
|
2713
|
-
def enable_bindings(self, bindings):
|
2931
|
+
def enable_bindings(self, bindings: object) -> None:
|
2714
2932
|
if not bindings:
|
2715
2933
|
self._enable_binding("all")
|
2716
2934
|
elif isinstance(bindings, (list, tuple)):
|
@@ -2752,6 +2970,7 @@ class MainTable(tk.Canvas):
|
|
2752
2970
|
):
|
2753
2971
|
self._tksheet_bind("row_start_bindings", self.select_row_start)
|
2754
2972
|
self._tksheet_bind("table_start_bindings", self.select_a1)
|
2973
|
+
self._tksheet_bind("escape_bindings", self.escape)
|
2755
2974
|
if binding in ("all", "single", "single_selection_mode", "single_select"):
|
2756
2975
|
self.single_selection_enabled = True
|
2757
2976
|
self.toggle_selection_enabled = False
|
@@ -2829,6 +3048,11 @@ class MainTable(tk.Canvas):
|
|
2829
3048
|
self.undo_enabled = True
|
2830
3049
|
self._tksheet_bind("undo_bindings", self.undo)
|
2831
3050
|
self._tksheet_bind("redo_bindings", self.redo)
|
3051
|
+
if binding in ("find",):
|
3052
|
+
self.find_enabled = True
|
3053
|
+
self._tksheet_bind("find_bindings", self.open_find_window)
|
3054
|
+
self._tksheet_bind("find_next_bindings", self.find_next)
|
3055
|
+
self._tksheet_bind("find_previous_bindings", self.find_previous)
|
2832
3056
|
if binding in bind_del_columns:
|
2833
3057
|
self.rc_delete_column_enabled = True
|
2834
3058
|
self.rc_popup_menus_enabled = True
|
@@ -2881,6 +3105,7 @@ class MainTable(tk.Canvas):
|
|
2881
3105
|
):
|
2882
3106
|
self._tksheet_unbind("row_start_bindings")
|
2883
3107
|
self._tksheet_unbind("table_start_bindings")
|
3108
|
+
self._tksheet_unbind("escape_bindings")
|
2884
3109
|
self.single_selection_enabled = False
|
2885
3110
|
self.toggle_selection_enabled = False
|
2886
3111
|
if binding in ("all", "drag_select"):
|
@@ -2971,6 +3196,12 @@ class MainTable(tk.Canvas):
|
|
2971
3196
|
if binding in ("all", "undo", "redo", "edit_bindings", "edit"):
|
2972
3197
|
self.undo_enabled = False
|
2973
3198
|
self._tksheet_unbind("undo_bindings", "redo_bindings")
|
3199
|
+
if binding in ("all", "find"):
|
3200
|
+
self.find_enabled = False
|
3201
|
+
self._tksheet_unbind("find_bindings")
|
3202
|
+
self._tksheet_unbind("find_next_bindings")
|
3203
|
+
self._tksheet_unbind("find_previous_bindings")
|
3204
|
+
self.close_find_window()
|
2974
3205
|
|
2975
3206
|
def _tksheet_unbind(self, *keys) -> None:
|
2976
3207
|
for widget in (self, self.RI, self.CH, self.TL):
|
@@ -3457,26 +3688,42 @@ class MainTable(tk.Canvas):
|
|
3457
3688
|
if move_synced:
|
3458
3689
|
self.y_move_synced_scrolls(*args, use_scrollbar=True)
|
3459
3690
|
|
3460
|
-
def set_xviews(
|
3691
|
+
def set_xviews(
|
3692
|
+
self,
|
3693
|
+
*args,
|
3694
|
+
move_synced: bool = True,
|
3695
|
+
redraw: bool = True,
|
3696
|
+
) -> None:
|
3461
3697
|
self.main_table_redraw_grid_and_text(setting_views=True)
|
3462
|
-
self.
|
3698
|
+
if not self.PAR._startup_complete:
|
3699
|
+
self.update_idletasks()
|
3463
3700
|
self.xview(*args)
|
3464
3701
|
if self.show_header:
|
3465
|
-
self.
|
3702
|
+
if not self.PAR._startup_complete:
|
3703
|
+
self.CH.update_idletasks()
|
3466
3704
|
self.CH.xview(*args)
|
3467
|
-
|
3705
|
+
if redraw:
|
3706
|
+
self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=False)
|
3468
3707
|
if move_synced:
|
3469
3708
|
self.x_move_synced_scrolls(*args)
|
3470
3709
|
self.fix_views()
|
3471
3710
|
|
3472
|
-
def set_yviews(
|
3711
|
+
def set_yviews(
|
3712
|
+
self,
|
3713
|
+
*args,
|
3714
|
+
move_synced: bool = True,
|
3715
|
+
redraw: bool = True,
|
3716
|
+
) -> None:
|
3473
3717
|
self.main_table_redraw_grid_and_text(setting_views=True)
|
3474
|
-
self.
|
3718
|
+
if not self.PAR._startup_complete:
|
3719
|
+
self.update_idletasks()
|
3475
3720
|
self.yview(*args)
|
3476
3721
|
if self.show_index:
|
3477
|
-
self.
|
3722
|
+
if not self.PAR._startup_complete:
|
3723
|
+
self.RI.update_idletasks()
|
3478
3724
|
self.RI.yview(*args)
|
3479
|
-
|
3725
|
+
if redraw:
|
3726
|
+
self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=True)
|
3480
3727
|
if move_synced:
|
3481
3728
|
self.y_move_synced_scrolls(*args)
|
3482
3729
|
self.fix_views()
|
@@ -3618,7 +3865,7 @@ class MainTable(tk.Canvas):
|
|
3618
3865
|
b = self.txt_measure_canvas.bbox(self.txt_measure_canvas_text)
|
3619
3866
|
return b[3] - b[1]
|
3620
3867
|
|
3621
|
-
def get_txt_dimensions(self, txt: str, font: None | FontTuple = None) -> int:
|
3868
|
+
def get_txt_dimensions(self, txt: str, font: None | FontTuple = None) -> tuple[int, int]:
|
3622
3869
|
self.txt_measure_canvas.itemconfig(
|
3623
3870
|
self.txt_measure_canvas_text,
|
3624
3871
|
text=txt,
|
@@ -3639,7 +3886,6 @@ class MainTable(tk.Canvas):
|
|
3639
3886
|
def set_min_column_width(self, width: int) -> None:
|
3640
3887
|
if width:
|
3641
3888
|
self.PAR.ops.min_column_width = width
|
3642
|
-
|
3643
3889
|
if self.PAR.ops.min_column_width > self.PAR.ops.max_column_width:
|
3644
3890
|
self.PAR.ops.max_column_width = self.PAR.ops.min_column_width + 20
|
3645
3891
|
if (
|
@@ -3669,12 +3915,12 @@ class MainTable(tk.Canvas):
|
|
3669
3915
|
def set_table_font(self, newfont: tuple | None = None, reset_row_positions: bool = False) -> tuple[str, int, str]:
|
3670
3916
|
if newfont:
|
3671
3917
|
if not isinstance(newfont, tuple):
|
3672
|
-
raise ValueError("Argument must be tuple e.g.
|
3918
|
+
raise ValueError("Argument must be tuple e.g. ('Carlito', 12, 'normal')")
|
3673
3919
|
if len(newfont) != 3:
|
3674
3920
|
raise ValueError("Argument must be three-tuple")
|
3675
3921
|
if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
|
3676
3922
|
raise ValueError(
|
3677
|
-
"Argument must be font, size and 'normal', 'bold' or
|
3923
|
+
"Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
|
3678
3924
|
)
|
3679
3925
|
self.PAR.ops.table_font = FontTuple(*newfont)
|
3680
3926
|
self.set_table_font_help()
|
@@ -3706,7 +3952,7 @@ class MainTable(tk.Canvas):
|
|
3706
3952
|
raise ValueError("Argument must be three-tuple")
|
3707
3953
|
if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
|
3708
3954
|
raise ValueError(
|
3709
|
-
"Argument must be font, size and 'normal', 'bold' or
|
3955
|
+
"Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
|
3710
3956
|
)
|
3711
3957
|
self.PAR.ops.header_font = FontTuple(*newfont)
|
3712
3958
|
self.set_header_font_help()
|
@@ -3737,7 +3983,7 @@ class MainTable(tk.Canvas):
|
|
3737
3983
|
raise ValueError("Argument must be three-tuple")
|
3738
3984
|
if not isinstance(newfont[0], str) or not isinstance(newfont[1], int) or not isinstance(newfont[2], str):
|
3739
3985
|
raise ValueError(
|
3740
|
-
"Argument must be font, size and 'normal', 'bold' or
|
3986
|
+
"Argument must be font, size and 'normal', 'bold' or'italic' e.g. ('Carlito',12,'normal')"
|
3741
3987
|
)
|
3742
3988
|
self.PAR.ops.index_font = FontTuple(*newfont)
|
3743
3989
|
self.set_index_font_help()
|
@@ -4752,8 +4998,8 @@ class MainTable(tk.Canvas):
|
|
4752
4998
|
data_ins_col: int,
|
4753
4999
|
displayed_ins_col: int,
|
4754
5000
|
numcols: int,
|
4755
|
-
columns: list | None = None,
|
4756
|
-
widths: list | None = None,
|
5001
|
+
columns: list[list[object]] | None = None,
|
5002
|
+
widths: list[int] | tuple[int] | None = None,
|
4757
5003
|
headers: bool = False,
|
4758
5004
|
) -> tuple[dict, dict, dict]:
|
4759
5005
|
header_data = {}
|
@@ -4802,10 +5048,10 @@ class MainTable(tk.Canvas):
|
|
4802
5048
|
data_ins_row: int,
|
4803
5049
|
displayed_ins_row: int,
|
4804
5050
|
numrows: int,
|
4805
|
-
rows: list | None = None,
|
4806
|
-
heights: list | None = None,
|
5051
|
+
rows: list[list[object]] | None = None,
|
5052
|
+
heights: list[int] | tuple[int] | None = None,
|
4807
5053
|
row_index: bool = False,
|
4808
|
-
total_data_cols=None,
|
5054
|
+
total_data_cols: int | None = None,
|
4809
5055
|
) -> tuple[dict, dict, dict]:
|
4810
5056
|
index_data = {}
|
4811
5057
|
if isinstance(self._row_index, list):
|
@@ -5008,7 +5254,7 @@ class MainTable(tk.Canvas):
|
|
5008
5254
|
|
5009
5255
|
def display_rows(
|
5010
5256
|
self,
|
5011
|
-
rows: int | AnyIter | None = None,
|
5257
|
+
rows: int | AnyIter[int] | None = None,
|
5012
5258
|
all_rows_displayed: bool | None = None,
|
5013
5259
|
reset_row_positions: bool = True,
|
5014
5260
|
deselect_all: bool = True,
|
@@ -5037,7 +5283,7 @@ class MainTable(tk.Canvas):
|
|
5037
5283
|
|
5038
5284
|
def display_columns(
|
5039
5285
|
self,
|
5040
|
-
columns: int | AnyIter | None = None,
|
5286
|
+
columns: int | AnyIter[int] | None = None,
|
5041
5287
|
all_columns_displayed: bool | None = None,
|
5042
5288
|
reset_col_positions: bool = True,
|
5043
5289
|
deselect_all: bool = True,
|
@@ -5642,11 +5888,18 @@ class MainTable(tk.Canvas):
|
|
5642
5888
|
if resized_cols or resized_rows or changed_w:
|
5643
5889
|
self.recreate_all_selection_boxes()
|
5644
5890
|
if changed_w:
|
5645
|
-
self.
|
5646
|
-
|
5647
|
-
self.CH.update_idletasks()
|
5648
|
-
self.TL.update_idletasks()
|
5891
|
+
for widget in (self, self.RI, self.CH, self.TL):
|
5892
|
+
widget.update_idletasks()
|
5649
5893
|
return False
|
5894
|
+
if self.find_window.open:
|
5895
|
+
w, h, x, y = self.get_find_window_dimensions_coords(w_width=self.winfo_width())
|
5896
|
+
self.coords(self.find_window.canvas_id, x, y)
|
5897
|
+
self.itemconfig(
|
5898
|
+
self.find_window.canvas_id,
|
5899
|
+
width=w,
|
5900
|
+
height=h,
|
5901
|
+
state="normal",
|
5902
|
+
)
|
5650
5903
|
self.hidd_text.update(self.disp_text)
|
5651
5904
|
self.disp_text = {}
|
5652
5905
|
self.hidd_high.update(self.disp_high)
|
@@ -5677,13 +5930,13 @@ class MainTable(tk.Canvas):
|
|
5677
5930
|
chain.from_iterable(
|
5678
5931
|
[
|
5679
5932
|
(
|
5680
|
-
|
5933
|
+
scrollpos_left - 1,
|
5681
5934
|
self.row_positions[r],
|
5682
5935
|
x_grid_stop,
|
5683
5936
|
self.row_positions[r],
|
5684
|
-
|
5937
|
+
scrollpos_left - 1,
|
5685
5938
|
self.row_positions[r],
|
5686
|
-
|
5939
|
+
scrollpos_left - 1,
|
5687
5940
|
self.row_positions[r + 1] if len(self.row_positions) - 1 > r else self.row_positions[r],
|
5688
5941
|
)
|
5689
5942
|
for r in range(grid_start_row, grid_end_row)
|
@@ -6045,56 +6298,35 @@ class MainTable(tk.Canvas):
|
|
6045
6298
|
box: tuple[int, int, int, int] | None = None,
|
6046
6299
|
run_binding: bool = True,
|
6047
6300
|
) -> None:
|
6301
|
+
def box_created(r: int, c: int, box: SelectionBox) -> bool:
|
6302
|
+
r1, c1, r2, c2 = box.coords
|
6303
|
+
if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
|
6304
|
+
self.create_currently_selected_box(r, c, box.type_, box.fill_iid)
|
6305
|
+
if run_binding:
|
6306
|
+
self.run_selection_binding(box.type_)
|
6307
|
+
return True
|
6308
|
+
return False
|
6309
|
+
|
6310
|
+
# set current to a particular existing selection box
|
6048
6311
|
if isinstance(item, int) and item in self.selection_boxes:
|
6049
6312
|
selection_box = self.selection_boxes[item]
|
6050
6313
|
r1, c1, r2, c2 = selection_box.coords
|
6051
|
-
if r is None:
|
6052
|
-
r = r1
|
6053
|
-
if c is None:
|
6054
|
-
c = c1
|
6055
|
-
if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
|
6056
|
-
self.create_currently_selected_box(
|
6057
|
-
r,
|
6058
|
-
c,
|
6059
|
-
selection_box.type_,
|
6060
|
-
selection_box.fill_iid,
|
6061
|
-
)
|
6062
|
-
if run_binding:
|
6063
|
-
self.run_selection_binding(selection_box.type_)
|
6314
|
+
if box_created(r1 if r is None else r, c1 if c is None else c, selection_box):
|
6064
6315
|
return
|
6065
|
-
|
6316
|
+
|
6317
|
+
# set current to any existing selection box with coordinates: box
|
6066
6318
|
if isinstance(box, tuple):
|
6067
|
-
if r is None:
|
6068
|
-
r = box[0]
|
6069
|
-
if c is None:
|
6070
|
-
c = box[1]
|
6071
6319
|
for item, selection_box in self.get_selection_items(reverse=True):
|
6072
|
-
|
6073
|
-
|
6074
|
-
|
6075
|
-
|
6076
|
-
|
6077
|
-
|
6078
|
-
selection_box.fill_iid,
|
6079
|
-
)
|
6080
|
-
if run_binding:
|
6081
|
-
self.run_selection_binding(selection_box.type_)
|
6082
|
-
return
|
6083
|
-
# currently selected is just pointed at a coordinate
|
6084
|
-
# find the top most box there, requires r and c
|
6085
|
-
if r is not None and c is not None:
|
6320
|
+
if box == selection_box.coords:
|
6321
|
+
if box_created(box[0] if r is None else r, box[1] if c is None else c, selection_box):
|
6322
|
+
return
|
6323
|
+
|
6324
|
+
# set current to a coordinate, find the top most box there
|
6325
|
+
if isinstance(r, int) and isinstance(c, int):
|
6086
6326
|
for item, selection_box in self.get_selection_items(reverse=True):
|
6087
|
-
|
6088
|
-
if r1 <= r and c1 <= c and r2 >= r and c2 >= c:
|
6089
|
-
self.create_currently_selected_box(
|
6090
|
-
r,
|
6091
|
-
c,
|
6092
|
-
selection_box.type_,
|
6093
|
-
selection_box.fill_iid,
|
6094
|
-
)
|
6095
|
-
if run_binding:
|
6096
|
-
self.run_selection_binding(selection_box.type_)
|
6327
|
+
if box_created(r, c, selection_box):
|
6097
6328
|
return
|
6329
|
+
|
6098
6330
|
# wasn't provided an item and couldn't find a box at coords so select cell
|
6099
6331
|
if r < len(self.row_positions) - 1 and c < len(self.col_positions) - 1:
|
6100
6332
|
self.select_cell(r, c, redraw=True)
|
@@ -6215,7 +6447,7 @@ class MainTable(tk.Canvas):
|
|
6215
6447
|
|
6216
6448
|
def hide_selection_box(self, item: int | None) -> bool:
|
6217
6449
|
if item is None or item is True or item not in self.selection_boxes:
|
6218
|
-
return
|
6450
|
+
return False
|
6219
6451
|
box = self.selection_boxes.pop(item)
|
6220
6452
|
self.hide_box(box.fill_iid)
|
6221
6453
|
self.hide_box(box.bd_iid)
|
@@ -6465,50 +6697,30 @@ class MainTable(tk.Canvas):
|
|
6465
6697
|
def recreate_all_selection_boxes(self) -> None:
|
6466
6698
|
if not self.selected:
|
6467
6699
|
return
|
6700
|
+
|
6468
6701
|
modified = False
|
6702
|
+
row_limit = len(self.row_positions) - 1
|
6703
|
+
col_limit = len(self.col_positions) - 1
|
6704
|
+
|
6469
6705
|
for item, box in self.get_selection_items():
|
6470
6706
|
r1, c1, r2, c2 = box.coords
|
6471
|
-
|
6472
|
-
|
6473
|
-
|
6474
|
-
|
6475
|
-
|
6476
|
-
|
6477
|
-
|
6478
|
-
if r1 >= len(self.row_positions) - 1:
|
6479
|
-
if len(self.row_positions) > 1:
|
6480
|
-
r1 = len(self.row_positions) - 2
|
6481
|
-
else:
|
6482
|
-
r1 = 0
|
6483
|
-
if c1 >= len(self.col_positions) - 1:
|
6484
|
-
if len(self.col_positions) > 1:
|
6485
|
-
c1 = len(self.col_positions) - 2
|
6486
|
-
else:
|
6487
|
-
c1 = 0
|
6488
|
-
if r2 > len(self.row_positions) - 1:
|
6489
|
-
r2 = len(self.row_positions) - 1
|
6490
|
-
if c2 > len(self.col_positions) - 1:
|
6491
|
-
c2 = len(self.col_positions) - 1
|
6707
|
+
# check coordinates
|
6708
|
+
r1 = min(r1, row_limit - (1 if row_limit > 0 else 0))
|
6709
|
+
c1 = min(c1, col_limit - (1 if col_limit > 0 else 0))
|
6710
|
+
r2 = min(r2, row_limit)
|
6711
|
+
c2 = min(c2, col_limit)
|
6712
|
+
|
6713
|
+
modified = modified or (r1 >= row_limit or c1 >= col_limit or r2 > row_limit or c2 > col_limit)
|
6492
6714
|
self.recreate_selection_box(r1, c1, r2, c2, item, run_binding=False)
|
6493
6715
|
|
6494
6716
|
if self.selected:
|
6495
|
-
r = self.selected.row
|
6496
|
-
c
|
6497
|
-
|
6498
|
-
self.set_currently_selected(
|
6499
|
-
r,
|
6500
|
-
c,
|
6501
|
-
item=self.selected.fill_iid,
|
6502
|
-
run_binding=False,
|
6503
|
-
)
|
6717
|
+
r, c = self.selected.row, self.selected.column
|
6718
|
+
if r < row_limit and c < col_limit:
|
6719
|
+
self.set_currently_selected(r, c, item=self.selected.fill_iid, run_binding=False)
|
6504
6720
|
else:
|
6505
6721
|
box = self.selection_boxes[self.selected.fill_iid]
|
6506
|
-
self.set_currently_selected(
|
6507
|
-
|
6508
|
-
box.coords.from_c,
|
6509
|
-
item=box.fill_iid,
|
6510
|
-
run_binding=False,
|
6511
|
-
)
|
6722
|
+
self.set_currently_selected(box.coords[0], box.coords[1], item=box.fill_iid, run_binding=False)
|
6723
|
+
|
6512
6724
|
if modified:
|
6513
6725
|
self.PAR.emit_event(
|
6514
6726
|
"<<SheetSelect>>",
|
@@ -6535,23 +6747,17 @@ class MainTable(tk.Canvas):
|
|
6535
6747
|
return d
|
6536
6748
|
|
6537
6749
|
def get_selected_min_max(self) -> tuple[int, int, int, int] | tuple[None, None, None, None]:
|
6538
|
-
|
6539
|
-
|
6540
|
-
|
6541
|
-
max_y = 0
|
6542
|
-
|
6750
|
+
if not self.get_selection_items():
|
6751
|
+
return None, None, None, None
|
6752
|
+
min_y, min_x = float("inf"), float("inf")
|
6753
|
+
max_y, max_x = 0, 0
|
6754
|
+
|
6755
|
+
for _, box in self.get_selection_items():
|
6543
6756
|
r1, c1, r2, c2 = box.coords
|
6544
|
-
|
6545
|
-
|
6546
|
-
|
6547
|
-
|
6548
|
-
if r2 > max_y:
|
6549
|
-
max_y = r2
|
6550
|
-
if c2 > max_x:
|
6551
|
-
max_x = c2
|
6552
|
-
if min_x != float("inf") and min_y != float("inf") and max_x > 0 and max_y > 0:
|
6553
|
-
return min_y, min_x, max_y, max_x
|
6554
|
-
return None, None, None, None
|
6757
|
+
min_y, min_x = min(min_y, r1), min(min_x, c1)
|
6758
|
+
max_y, max_x = max(max_y, r2), max(max_x, c2)
|
6759
|
+
|
6760
|
+
return (min_y, min_x, max_y, max_x) if min_y != float("inf") else (None, None, None, None)
|
6555
6761
|
|
6556
6762
|
def get_selected_rows(
|
6557
6763
|
self,
|
@@ -6706,7 +6912,7 @@ class MainTable(tk.Canvas):
|
|
6706
6912
|
elif self.get_cell_kwargs(datarn, datacn, key="dropdown") or self.get_cell_kwargs(
|
6707
6913
|
datarn, datacn, key="checkbox"
|
6708
6914
|
):
|
6709
|
-
if
|
6915
|
+
if event_opens_dropdown_or_checkbox(event):
|
6710
6916
|
if self.get_cell_kwargs(datarn, datacn, key="dropdown"):
|
6711
6917
|
self.open_dropdown_window(r, c, event=event)
|
6712
6918
|
elif self.get_cell_kwargs(datarn, datacn, key="checkbox"):
|
@@ -6714,27 +6920,6 @@ class MainTable(tk.Canvas):
|
|
6714
6920
|
else:
|
6715
6921
|
self.open_text_editor(event=event, r=r, c=c, dropdown=False)
|
6716
6922
|
|
6717
|
-
def event_opens_dropdown_or_checkbox(self, event=None) -> bool:
|
6718
|
-
if event is None:
|
6719
|
-
return False
|
6720
|
-
elif event == "rc":
|
6721
|
-
return True
|
6722
|
-
elif (
|
6723
|
-
(hasattr(event, "keysym") and event.keysym == "Return")
|
6724
|
-
or (hasattr(event, "keysym") and event.keysym == "F2")
|
6725
|
-
or (
|
6726
|
-
event is not None
|
6727
|
-
and hasattr(event, "keycode")
|
6728
|
-
and event.keycode == "??"
|
6729
|
-
and hasattr(event, "num")
|
6730
|
-
and event.num == 1
|
6731
|
-
) # mouseclick
|
6732
|
-
or (hasattr(event, "keysym") and event.keysym == "BackSpace")
|
6733
|
-
):
|
6734
|
-
return True
|
6735
|
-
else:
|
6736
|
-
return False
|
6737
|
-
|
6738
6923
|
# displayed indexes
|
6739
6924
|
def get_cell_align(self, r: int, c: int) -> str:
|
6740
6925
|
datarn = self.datarn(r)
|
@@ -6754,27 +6939,16 @@ class MainTable(tk.Canvas):
|
|
6754
6939
|
state: str = "normal",
|
6755
6940
|
dropdown: bool = False,
|
6756
6941
|
) -> bool:
|
6757
|
-
text =
|
6942
|
+
text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str=True)}"
|
6758
6943
|
extra_func_key = "??"
|
6759
|
-
if
|
6760
|
-
if event
|
6761
|
-
|
6762
|
-
|
6763
|
-
|
6764
|
-
|
6765
|
-
|
6766
|
-
|
6767
|
-
text = ""
|
6768
|
-
else:
|
6769
|
-
text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str = True)}"
|
6770
|
-
elif event is not None and (
|
6771
|
-
(hasattr(event, "char") and event.char.isalpha())
|
6772
|
-
or (hasattr(event, "char") and event.char.isdigit())
|
6773
|
-
or (hasattr(event, "char") and event.char in symbols_set)
|
6774
|
-
):
|
6775
|
-
extra_func_key = event.char
|
6776
|
-
text = event.char
|
6777
|
-
else:
|
6944
|
+
if event_opens_dropdown_or_checkbox(event):
|
6945
|
+
if hasattr(event, "keysym") and event.keysym in ("Return", "F2", "BackSpace"):
|
6946
|
+
extra_func_key = event.keysym
|
6947
|
+
if event.keysym == "BackSpace":
|
6948
|
+
text = ""
|
6949
|
+
elif event_has_char_key(event):
|
6950
|
+
extra_func_key = text = event.char
|
6951
|
+
elif event is not None:
|
6778
6952
|
return False
|
6779
6953
|
if self.extra_begin_edit_cell_func:
|
6780
6954
|
try:
|
@@ -6797,12 +6971,11 @@ class MainTable(tk.Canvas):
|
|
6797
6971
|
return False
|
6798
6972
|
else:
|
6799
6973
|
text = text if isinstance(text, str) else f"{text}"
|
6800
|
-
text = "" if text is None else text
|
6801
6974
|
if self.PAR.ops.cell_auto_resize_enabled:
|
6802
6975
|
self.set_cell_size_to_text(r, c, only_if_too_small=True, redraw=True, run_binding=True)
|
6803
6976
|
if self.text_editor.open and (r, c) == self.text_editor.coords:
|
6804
6977
|
self.text_editor.window.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
|
6805
|
-
return
|
6978
|
+
return False
|
6806
6979
|
self.hide_text_editor()
|
6807
6980
|
if not self.see(r=r, c=c, check_cell_visibility=True):
|
6808
6981
|
self.refresh()
|
@@ -6810,8 +6983,6 @@ class MainTable(tk.Canvas):
|
|
6810
6983
|
y = self.row_positions[r]
|
6811
6984
|
w = self.col_positions[c + 1] - x + 1
|
6812
6985
|
h = self.row_positions[r + 1] - y + 1
|
6813
|
-
if text is None:
|
6814
|
-
text = f"{self.get_cell_data(self.datarn(r), self.datacn(c), none_to_empty_str = True)}"
|
6815
6986
|
kwargs = {
|
6816
6987
|
"menu_kwargs": DotDict(
|
6817
6988
|
{
|