tksheet 7.0.6__py3-none-any.whl → 7.1.0__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/main_table.py CHANGED
@@ -50,8 +50,6 @@ from .formatters import (
50
50
  )
51
51
  from .functions import (
52
52
  consecutive_chunks,
53
- coords_tag_to_box_nt,
54
- coords_tag_to_int_tuple,
55
53
  decompress_load,
56
54
  diff_gen,
57
55
  diff_list,
@@ -75,11 +73,15 @@ from .functions import (
75
73
  unpickle_obj,
76
74
  )
77
75
  from .other_classes import (
76
+ Box_nt,
78
77
  Box_t,
79
- CurrentlySelectedClass,
80
78
  DotDict,
79
+ DropdownStorage,
81
80
  EventDataDict,
82
81
  FontTuple,
82
+ Selected,
83
+ SelectionBox,
84
+ TextEditorStorage,
83
85
  )
84
86
  from .text_editor import (
85
87
  TextEditor,
@@ -104,39 +106,40 @@ class MainTable(tk.Canvas):
104
106
  self.PAR = kwargs["parent"]
105
107
  self.PAR_width = 0
106
108
  self.PAR_height = 0
109
+ self.scrollregion = tuple()
107
110
  self.current_cursor = ""
108
111
  self.b1_pressed_loc = None
109
- self.existing_dropdown_canvas_id = None
110
- self.existing_dropdown_window = None
111
112
  self.closed_dropdown = None
112
- self.last_selected = None
113
113
  self.centre_alignment_text_mod_indexes = (slice(1, None), slice(None, -1))
114
114
  self.c_align_cyc = cycle(self.centre_alignment_text_mod_indexes)
115
115
  self.allow_auto_resize_columns = True
116
116
  self.allow_auto_resize_rows = True
117
117
  self.span = self.PAR.span
118
118
  self.synced_scrolls = set()
119
+ self.dropdown = DropdownStorage()
120
+ self.text_editor = TextEditorStorage()
119
121
 
120
122
  self.disp_ctrl_outline = {}
121
123
  self.disp_text = {}
122
124
  self.disp_high = {}
123
125
  self.disp_grid = {}
124
- self.disp_fill_sels = {}
125
- self.disp_bord_sels = {}
126
126
  self.disp_resize_lines = {}
127
127
  self.disp_dropdown = {}
128
128
  self.disp_checkbox = {}
129
+ self.disp_boxes = set()
129
130
  self.hidd_ctrl_outline = {}
130
131
  self.hidd_text = {}
131
132
  self.hidd_high = {}
132
133
  self.hidd_grid = {}
133
- self.hidd_fill_sels = {}
134
- self.hidd_bord_sels = {}
135
134
  self.hidd_resize_lines = {}
136
135
  self.hidd_dropdown = {}
137
136
  self.hidd_checkbox = {}
137
+ self.hidd_boxes = set()
138
138
 
139
+ self.selection_boxes = {}
140
+ self.selected = tuple()
139
141
  self.named_spans = {}
142
+ self.reset_tags()
140
143
  self.cell_options = {}
141
144
  self.col_options = {}
142
145
  self.row_options = {}
@@ -225,7 +228,6 @@ class MainTable(tk.Canvas):
225
228
  self.rc_insert_row_enabled = False
226
229
  self.rc_popup_menus_enabled = False
227
230
  self.edit_cell_enabled = False
228
- self.text_editor_loc = None
229
231
  self.new_row_width = 0
230
232
  self.new_header_height = 0
231
233
  self.CH = kwargs["column_headers_canvas"]
@@ -265,8 +267,6 @@ class MainTable(tk.Canvas):
265
267
 
266
268
  self.txt_measure_canvas = tk.Canvas(self)
267
269
  self.txt_measure_canvas_text = self.txt_measure_canvas.create_text(0, 0, text="", font=self.PAR.ops.table_font)
268
- self.text_editor = None
269
- self.text_editor_id = None
270
270
 
271
271
  self.max_row_height = float(kwargs["max_row_height"])
272
272
  self.max_index_width = float(kwargs["max_index_width"])
@@ -306,6 +306,8 @@ class MainTable(tk.Canvas):
306
306
  self._row_index = _row_index
307
307
  else:
308
308
  self._row_index = []
309
+ self.saved_row_heights = {}
310
+ self.saved_column_widths = {}
309
311
  self.displayed_columns = []
310
312
  self.displayed_rows = []
311
313
  self.set_col_positions(itr=[])
@@ -404,6 +406,11 @@ class MainTable(tk.Canvas):
404
406
  for canvas in (self, self.RI, self.CH):
405
407
  canvas.unbind(b[0])
406
408
 
409
+ def reset_tags(self) -> None:
410
+ self.tagged_cells = {}
411
+ self.tagged_rows = {}
412
+ self.tagged_columns = {}
413
+
407
414
  def show_ctrl_outline(
408
415
  self,
409
416
  canvas: Literal["table"] = "table",
@@ -478,20 +485,17 @@ class MainTable(tk.Canvas):
478
485
  self.hidd_ctrl_outline[t] = False
479
486
 
480
487
  def get_ctrl_x_c_boxes(self) -> tuple[dict[tuple[int, int, int, int], str], int]:
481
- currently_selected = self.currently_selected()
482
488
  boxes = {}
483
489
  maxrows = 0
484
- if currently_selected.type_ in ("cell", "column"):
485
- curr_box = self.get_box_containing_current()
490
+ if self.selected.type_ in ("cells", "columns"):
491
+ curr_box = self.selection_boxes[self.selected.fill_iid].coords
486
492
  maxrows = curr_box[2] - curr_box[0]
487
- for item in self.get_selection_items(rows=False, current=False):
488
- tags = self.gettags(item)
489
- box = coords_tag_to_box_nt(tags[1])
490
- if maxrows >= box[2] - box[0]:
491
- boxes[box] = tags[0]
493
+ for item, box in self.get_selection_items(rows=False):
494
+ if maxrows >= box.coords[2] - box.coords[0]:
495
+ boxes[box.coords] = box.type_
492
496
  else:
493
- for item in self.get_selection_items(columns=False, cells=False, current=False):
494
- boxes[coords_tag_to_box_nt(self.gettags(item)[1])] = "rows"
497
+ for item, box in self.get_selection_items(columns=False, cells=False):
498
+ boxes[box.coords] = "rows"
495
499
  return boxes, maxrows
496
500
 
497
501
  def io_csv_writer(self) -> tuple[io.StringIO, csv.writer]:
@@ -506,12 +510,11 @@ class MainTable(tk.Canvas):
506
510
  return s, writer
507
511
 
508
512
  def ctrl_c(self, event=None) -> None:
509
- if not self.anything_selected():
513
+ if not self.selected:
510
514
  return
511
- currently_selected = self.currently_selected()
512
515
  event_data = event_dict(
513
516
  sheet=self.PAR.name,
514
- selected=currently_selected,
517
+ selected=self.selected,
515
518
  )
516
519
  event_data["eventname"] = "begin_ctrl_c"
517
520
  boxes, maxrows = self.get_ctrl_x_c_boxes()
@@ -519,7 +522,7 @@ class MainTable(tk.Canvas):
519
522
  s, writer = self.io_csv_writer()
520
523
  if not try_binding(self.extra_begin_ctrl_c_func, event_data):
521
524
  return
522
- if currently_selected.type_ in ("cell", "column"):
525
+ if self.selected.type_ in ("cells", "columns"):
523
526
  for rn in range(maxrows):
524
527
  row = []
525
528
  for r1, c1, r2, c2 in boxes:
@@ -549,20 +552,19 @@ class MainTable(tk.Canvas):
549
552
  try_binding(self.extra_end_ctrl_c_func, event_data, "end_ctrl_c")
550
553
 
551
554
  def ctrl_x(self, event=None) -> None:
552
- if not self.anything_selected():
555
+ if not self.selected:
553
556
  return
554
- currently_selected = self.currently_selected()
555
557
  event_data = event_dict(
556
558
  name="edit_table",
557
559
  sheet=self.PAR.name,
558
- selected=currently_selected,
560
+ selected=self.selected,
559
561
  )
560
562
  boxes, maxrows = self.get_ctrl_x_c_boxes()
561
563
  event_data["selection_boxes"] = boxes
562
564
  s, writer = self.io_csv_writer()
563
565
  if not try_binding(self.extra_begin_ctrl_x_func, event_data, "begin_ctrl_x"):
564
566
  return
565
- if currently_selected.type_ in ("cell", "column"):
567
+ if self.selected.type_ in ("cells", "columns"):
566
568
  for rn in range(maxrows):
567
569
  row = []
568
570
  for r1, c1, r2, c2 in boxes:
@@ -618,25 +620,20 @@ class MainTable(tk.Canvas):
618
620
  try_binding(self.extra_end_ctrl_x_func, event_data, "end_ctrl_x")
619
621
  self.sheet_modified(event_data)
620
622
 
621
- def get_box_containing_current(self) -> tuple[int, int, int, int]:
622
- item = self.get_selection_items(cells=False, rows=False, columns=False)[-1]
623
- return coords_tag_to_box_nt(self.gettags(item)[1])
624
-
625
623
  def ctrl_v(self, event: object = None) -> None:
626
624
  if not self.PAR.ops.expand_sheet_if_paste_too_big and (
627
625
  len(self.col_positions) == 1 or len(self.row_positions) == 1
628
626
  ):
629
627
  return
630
- currently_selected = self.currently_selected()
631
628
  event_data = event_dict(
632
629
  name="edit_table",
633
630
  sheet=self.PAR.name,
634
- selected=currently_selected,
631
+ selected=self.selected,
635
632
  )
636
- if currently_selected:
637
- selected_r = currently_selected[0]
638
- selected_c = currently_selected[1]
639
- elif not currently_selected and not self.PAR.ops.expand_sheet_if_paste_too_big:
633
+ if self.selected:
634
+ selected_r = self.selected.row
635
+ selected_c = self.selected.column
636
+ elif not self.selected and not self.PAR.ops.expand_sheet_if_paste_too_big:
640
637
  return
641
638
  else:
642
639
  if not self.data:
@@ -669,7 +666,7 @@ class MainTable(tk.Canvas):
669
666
  lastbox_c1,
670
667
  lastbox_r2,
671
668
  lastbox_c2,
672
- ) = self.get_box_containing_current()
669
+ ) = self.selection_boxes[self.selected.fill_iid].coords
673
670
  lastbox_numrows = lastbox_r2 - lastbox_r1
674
671
  lastbox_numcols = lastbox_c2 - lastbox_c1
675
672
  if lastbox_numrows > new_data_numrows and not lastbox_numrows % new_data_numrows:
@@ -850,13 +847,12 @@ class MainTable(tk.Canvas):
850
847
  self.sheet_modified(event_data)
851
848
 
852
849
  def delete_key(self, event: object = None) -> None:
853
- if not self.anything_selected():
850
+ if not self.selected:
854
851
  return
855
- currently_selected = self.currently_selected()
856
852
  event_data = event_dict(
857
853
  name="edit_table",
858
854
  sheet=self.PAR.name,
859
- selected=currently_selected,
855
+ selected=self.selected,
860
856
  )
861
857
  boxes = self.get_boxes()
862
858
  event_data["selection_boxes"] = boxes
@@ -928,6 +924,7 @@ class MainTable(tk.Canvas):
928
924
  data_indexes: bool = False,
929
925
  event_data: EventDataDict | None = None,
930
926
  ) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
927
+ self.saved_column_widths = {}
931
928
  if not isinstance(totalcols, int):
932
929
  totalcols = max(data_new_idxs.values(), default=0)
933
930
  if totalcols:
@@ -938,7 +935,7 @@ class MainTable(tk.Canvas):
938
935
  name="move_columns",
939
936
  sheet=self.PAR.name,
940
937
  boxes=self.get_boxes(),
941
- selected=self.currently_selected(),
938
+ selected=self.selected,
942
939
  )
943
940
  event_data["moved"]["columns"] = {
944
941
  "data": data_new_idxs,
@@ -990,13 +987,19 @@ class MainTable(tk.Canvas):
990
987
  old_idxs=data_old_idxs,
991
988
  )
992
989
  full_old_idxs = dict(zip(full_new_idxs.values(), full_new_idxs))
990
+ self.tagged_cells = {
991
+ tags: {(k[0], full_new_idxs[k[1]]) for k in tagged} for tags, tagged in self.tagged_cells.items()
992
+ }
993
993
  self.cell_options = {(k[0], full_new_idxs[k[1]]): v for k, v in self.cell_options.items()}
994
994
  self.col_options = {full_new_idxs[k]: v for k, v in self.col_options.items()}
995
+ self.tagged_columns = {
996
+ tags: {full_new_idxs[k] for k in tagged} for tags, tagged in self.tagged_columns.items()
997
+ }
995
998
  self.CH.cell_options = {full_new_idxs[k]: v for k, v in self.CH.cell_options.items()}
996
999
  totalrows = self.total_data_rows()
997
1000
  new_ops = self.PAR.create_options_from_span
998
1001
  qkspan = self.span()
999
- for name, span in self.named_spans.items():
1002
+ for span in self.named_spans.values():
1000
1003
  # span is neither a cell options nor col options span, continue
1001
1004
  if not isinstance(span["from_c"], int):
1002
1005
  continue
@@ -1158,6 +1161,7 @@ class MainTable(tk.Canvas):
1158
1161
  data_indexes: bool = False,
1159
1162
  event_data: EventDataDict | None = None,
1160
1163
  ) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
1164
+ self.saved_row_heights = {}
1161
1165
  if not isinstance(totalrows, int):
1162
1166
  totalrows = self.fix_data_len(max(data_new_idxs.values(), default=0))
1163
1167
  if event_data is None:
@@ -1165,7 +1169,7 @@ class MainTable(tk.Canvas):
1165
1169
  name="move_rows",
1166
1170
  sheet=self.PAR.name,
1167
1171
  boxes=self.get_boxes(),
1168
- selected=self.currently_selected(),
1172
+ selected=self.selected,
1169
1173
  )
1170
1174
  event_data["moved"]["rows"] = {
1171
1175
  "data": data_new_idxs,
@@ -1214,13 +1218,18 @@ class MainTable(tk.Canvas):
1214
1218
  old_idxs=data_old_idxs,
1215
1219
  )
1216
1220
  full_old_idxs = dict(zip(full_new_idxs.values(), full_new_idxs))
1221
+ self.tagged_cells = {
1222
+ tags: {(full_new_idxs[k[0]], k[1]) for k in tagged} for tags, tagged in self.tagged_cells.items()
1223
+ }
1217
1224
  self.cell_options = {(full_new_idxs[k[0]], k[1]): v for k, v in self.cell_options.items()}
1225
+ self.tagged_rows = {tags: {full_new_idxs[k] for k in tagged} for tags, tagged in self.tagged_rows.items()}
1218
1226
  self.row_options = {full_new_idxs[k]: v for k, v in self.row_options.items()}
1219
1227
  self.RI.cell_options = {full_new_idxs[k]: v for k, v in self.RI.cell_options.items()}
1228
+ self.RI.tree_rns = {v: full_new_idxs[k] for v, k in self.RI.tree_rns.items()}
1220
1229
  totalcols = self.total_data_cols()
1221
1230
  new_ops = self.PAR.create_options_from_span
1222
1231
  qkspan = self.span()
1223
- for name, span in self.named_spans.items():
1232
+ for span in self.named_spans.values():
1224
1233
  # span is neither a cell options nor row options span, continue
1225
1234
  if not isinstance(span["from_r"], int):
1226
1235
  continue
@@ -1436,7 +1445,6 @@ class MainTable(tk.Canvas):
1436
1445
  event_data["selection_boxes"] = modification["selection_boxes"]
1437
1446
  event_data["selected"] = modification["selected"]
1438
1447
  saved_cells = False
1439
- curr = tuple()
1440
1448
 
1441
1449
  if modification["added"]["rows"] or modification["added"]["columns"]:
1442
1450
  event_data = self.save_cells_using_modification(modification, event_data)
@@ -1468,7 +1476,6 @@ class MainTable(tk.Canvas):
1468
1476
  "displayed": disp_new_idxs,
1469
1477
  }
1470
1478
  self.restore_options_named_spans(modification)
1471
- curr = self.currently_selected()
1472
1479
 
1473
1480
  if modification["moved"]["rows"]:
1474
1481
  totalrows = self.total_data_rows()
@@ -1496,7 +1503,6 @@ class MainTable(tk.Canvas):
1496
1503
  "displayed": disp_new_idxs,
1497
1504
  }
1498
1505
  self.restore_options_named_spans(modification)
1499
- curr = self.currently_selected()
1500
1506
 
1501
1507
  if modification["added"]["rows"]:
1502
1508
  self.deselect("all", run_binding=False, redraw=False)
@@ -1514,7 +1520,6 @@ class MainTable(tk.Canvas):
1514
1520
  modification["selection_boxes"],
1515
1521
  modification["selected"],
1516
1522
  )
1517
- curr = self.currently_selected()
1518
1523
 
1519
1524
  if modification["added"]["columns"]:
1520
1525
  self.deselect("all", run_binding=False, redraw=False)
@@ -1532,7 +1537,6 @@ class MainTable(tk.Canvas):
1532
1537
  modification["selection_boxes"],
1533
1538
  modification["selected"],
1534
1539
  )
1535
- curr = self.currently_selected()
1536
1540
 
1537
1541
  if modification["deleted"]["rows"]:
1538
1542
  self.add_rows(
@@ -1567,7 +1571,6 @@ class MainTable(tk.Canvas):
1567
1571
  modification["selection_boxes"],
1568
1572
  modification["selected"],
1569
1573
  )
1570
- curr = self.currently_selected()
1571
1574
 
1572
1575
  if modification["eventname"].startswith(("edit", "move")):
1573
1576
  if not saved_cells:
@@ -1582,7 +1585,6 @@ class MainTable(tk.Canvas):
1582
1585
  modification["selection_boxes"],
1583
1586
  modification["selected"],
1584
1587
  )
1585
- curr = self.currently_selected()
1586
1588
 
1587
1589
  elif modification["eventname"].startswith("add"):
1588
1590
  event_data["eventname"] = modification["eventname"].replace("add", "delete")
@@ -1590,10 +1592,10 @@ class MainTable(tk.Canvas):
1590
1592
  elif modification["eventname"].startswith("delete"):
1591
1593
  event_data["eventname"] = modification["eventname"].replace("delete", "add")
1592
1594
 
1593
- if curr:
1595
+ if self.selected:
1594
1596
  self.see(
1595
- r=curr.row,
1596
- c=curr.column,
1597
+ r=self.selected.row,
1598
+ c=self.selected.column,
1597
1599
  keep_yscroll=False,
1598
1600
  keep_xscroll=False,
1599
1601
  bottom_right_corner=False,
@@ -1707,7 +1709,7 @@ class MainTable(tk.Canvas):
1707
1709
  return False
1708
1710
 
1709
1711
  def select_all(self, redraw: bool = True, run_binding_func: bool = True) -> None:
1710
- currently_selected = self.currently_selected()
1712
+ iid, r, c = self.selected.iid, self.selected.row, self.selected.column
1711
1713
  self.deselect("all", redraw=False)
1712
1714
  if len(self.row_positions) > 1 and len(self.col_positions) > 1:
1713
1715
  item = self.create_selection_box(
@@ -1717,16 +1719,18 @@ class MainTable(tk.Canvas):
1717
1719
  len(self.col_positions) - 1,
1718
1720
  set_current=False,
1719
1721
  )
1720
- if currently_selected:
1721
- self.set_currently_selected(currently_selected.row, currently_selected.column, item=item)
1722
+ if iid:
1723
+ self.set_currently_selected(r, c, item=item)
1722
1724
  else:
1723
1725
  self.set_currently_selected(0, 0, item=item)
1724
1726
  if redraw:
1725
1727
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
1726
- if self.select_all_binding_func and run_binding_func:
1727
- self.select_all_binding_func(
1728
- self.get_select_event(being_drawn_item=self.being_drawn_item),
1729
- )
1728
+ if run_binding_func:
1729
+ if self.select_all_binding_func:
1730
+ self.select_all_binding_func(
1731
+ self.get_select_event(being_drawn_item=self.being_drawn_item),
1732
+ )
1733
+ self.PAR.emit_event("<<SheetSelect>>", data=self.get_select_event(self.being_drawn_item))
1730
1734
 
1731
1735
  def select_cell(
1732
1736
  self,
@@ -1766,7 +1770,7 @@ class MainTable(tk.Canvas):
1766
1770
  redraw: bool = True,
1767
1771
  run_binding_func: bool = True,
1768
1772
  set_as_current: bool = True,
1769
- ) -> int:
1773
+ ) -> int | None:
1770
1774
  if add_selection:
1771
1775
  if self.cell_selected(row, column, inc_rows=True, inc_cols=True):
1772
1776
  fill_iid = self.deselect(r=row, c=column, redraw=redraw)
@@ -1785,12 +1789,12 @@ class MainTable(tk.Canvas):
1785
1789
  fill_iid = self.select_cell(row, column, redraw=redraw)
1786
1790
  return fill_iid
1787
1791
 
1788
- def get_select_event(self, being_drawn_item: None | int) -> EventDataDict:
1792
+ def get_select_event(self, being_drawn_item: None | int = None) -> EventDataDict:
1789
1793
  return event_dict(
1790
1794
  name="select",
1791
1795
  sheet=self.PAR.name,
1792
- selected=self.currently_selected(),
1793
- being_selected=self.get_box_from_item(being_drawn_item),
1796
+ selected=self.selected,
1797
+ being_selected=self.coords_and_type(being_drawn_item),
1794
1798
  boxes=self.get_boxes(),
1795
1799
  )
1796
1800
 
@@ -1802,31 +1806,25 @@ class MainTable(tk.Canvas):
1802
1806
  redraw: bool = True,
1803
1807
  run_binding: bool = True,
1804
1808
  ) -> None:
1805
- if not self.anything_selected():
1809
+ if not self.selected:
1806
1810
  return
1807
- # saved_current = self.currently_selected()
1808
- set_curr = False
1809
- current = self.currently_selected().tags
1810
1811
  if r == "all" or (r is None and c is None and cell is None):
1811
- for item in self.get_selection_items(current=False):
1812
- self.delete_item(item)
1812
+ for item, box in self.get_selection_items():
1813
+ self.hide_selection_box(item)
1813
1814
  elif r in ("allrows", "allcols"):
1814
- for item in self.get_selection_items(
1815
- columns=r == "allcols", rows=r == "allrows", cells=False, current=False
1815
+ for item, box in self.get_selection_items(
1816
+ columns=r == "allcols",
1817
+ rows=r == "allrows",
1818
+ cells=False,
1816
1819
  ):
1817
- tags = self.gettags(item)
1818
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
1819
- self.delete_item(item)
1820
- if current[2] == tags[2]:
1821
- set_curr = True
1820
+ self.hide_selection_box(item)
1822
1821
  elif r is not None and c is None and cell is None:
1823
- for item in self.get_selection_items(columns=False, cells=False, current=False):
1824
- tags = self.gettags(item)
1825
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
1822
+ for item, box in self.get_selection_items(columns=False, cells=False):
1823
+ r1, c1, r2, c2 = box.coords
1826
1824
  if r >= r1 and r < r2:
1827
- self.delete_item(item)
1828
- if current[2] == tags[2]:
1829
- set_curr = True
1825
+ resel = self.selected.fill_iid == item
1826
+ to_sel = self.selected.row
1827
+ self.hide_selection_box(item)
1830
1828
  if r2 - r1 != 1:
1831
1829
  if r == r1:
1832
1830
  self.create_selection_box(
@@ -1835,7 +1833,7 @@ class MainTable(tk.Canvas):
1835
1833
  r2,
1836
1834
  len(self.col_positions) - 1,
1837
1835
  "rows",
1838
- set_current=False,
1836
+ set_current=resel,
1839
1837
  )
1840
1838
  elif r == r2 - 1:
1841
1839
  self.create_selection_box(
@@ -1844,7 +1842,7 @@ class MainTable(tk.Canvas):
1844
1842
  r2 - 1,
1845
1843
  len(self.col_positions) - 1,
1846
1844
  "rows",
1847
- set_current=False,
1845
+ set_current=resel,
1848
1846
  )
1849
1847
  else:
1850
1848
  self.create_selection_box(
@@ -1853,7 +1851,7 @@ class MainTable(tk.Canvas):
1853
1851
  r,
1854
1852
  len(self.col_positions) - 1,
1855
1853
  "rows",
1856
- set_current=False,
1854
+ set_current=resel and to_sel >= r1 and to_sel < r,
1857
1855
  )
1858
1856
  self.create_selection_box(
1859
1857
  r + 1,
@@ -1861,17 +1859,16 @@ class MainTable(tk.Canvas):
1861
1859
  r2,
1862
1860
  len(self.col_positions) - 1,
1863
1861
  "rows",
1864
- set_current=False,
1862
+ set_current=resel and to_sel >= r + 1 and to_sel < r2,
1865
1863
  )
1866
1864
  break
1867
1865
  elif c is not None and r is None and cell is None:
1868
- for item in self.get_selection_items(rows=False, cells=False, current=False):
1869
- tags = self.gettags(item)
1870
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
1866
+ for item, box in self.get_selection_items(rows=False, cells=False):
1867
+ r1, c1, r2, c2 = box.coords
1871
1868
  if c >= c1 and c < c2:
1872
- self.delete_item(item)
1873
- if current[2] == tags[2]:
1874
- set_curr = True
1869
+ resel = self.selected.fill_iid == item
1870
+ to_sel = self.selected.column
1871
+ self.hide_selection_box(item)
1875
1872
  if c2 - c1 != 1:
1876
1873
  if c == c1:
1877
1874
  self.create_selection_box(
@@ -1880,7 +1877,7 @@ class MainTable(tk.Canvas):
1880
1877
  len(self.row_positions) - 1,
1881
1878
  c2,
1882
1879
  "columns",
1883
- set_current=False,
1880
+ set_current=resel,
1884
1881
  )
1885
1882
  elif c == c2 - 1:
1886
1883
  self.create_selection_box(
@@ -1889,7 +1886,7 @@ class MainTable(tk.Canvas):
1889
1886
  len(self.row_positions) - 1,
1890
1887
  c2 - 1,
1891
1888
  "columns",
1892
- set_current=False,
1889
+ set_current=resel,
1893
1890
  )
1894
1891
  else:
1895
1892
  self.create_selection_box(
@@ -1898,7 +1895,7 @@ class MainTable(tk.Canvas):
1898
1895
  len(self.row_positions) - 1,
1899
1896
  c,
1900
1897
  "columns",
1901
- set_current=False,
1898
+ set_current=resel and to_sel >= c1 and to_sel < c,
1902
1899
  )
1903
1900
  self.create_selection_box(
1904
1901
  0,
@@ -1906,29 +1903,23 @@ class MainTable(tk.Canvas):
1906
1903
  len(self.row_positions) - 1,
1907
1904
  c2,
1908
1905
  "columns",
1909
- set_current=False,
1906
+ set_current=resel and to_sel >= c + 1 and to_sel < c2,
1910
1907
  )
1911
1908
  break
1912
1909
  elif (r is not None and c is not None and cell is None) or cell is not None:
1913
1910
  if cell is not None:
1914
1911
  r, c = cell[0], cell[1]
1915
- for item in self.get_selection_items(current=False, reverse=True):
1916
- tags = self.gettags(item)
1917
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
1912
+ for item, box in self.get_selection_items(reverse=True):
1913
+ r1, c1, r2, c2 = box.coords
1918
1914
  if r >= r1 and c >= c1 and r < r2 and c < c2:
1919
- self.delete_item(item)
1920
- if current[2] == tags[2]:
1921
- set_curr = True
1915
+ self.hide_selection_box(item)
1922
1916
  break
1923
- if set_curr:
1924
- self.set_current_to_last()
1925
1917
  if redraw:
1926
1918
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
1919
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
1927
1920
  if run_binding:
1928
- try_binding(
1929
- self.deselection_binding_func,
1930
- self.get_select_event(being_drawn_item=self.being_drawn_item),
1931
- )
1921
+ try_binding(self.deselection_binding_func, sel_event)
1922
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
1932
1923
 
1933
1924
  def page_UP(self, event=None):
1934
1925
  height = self.winfo_height()
@@ -1938,8 +1929,7 @@ class MainTable(tk.Canvas):
1938
1929
  scrollto = 0
1939
1930
  if self.PAR.ops.page_up_down_select_row:
1940
1931
  r = bisect_left(self.row_positions, scrollto)
1941
- current = self.currently_selected()
1942
- if current and current[0] == r:
1932
+ if self.selected and self.selected.row == r:
1943
1933
  r -= 1
1944
1934
  if r < 0:
1945
1935
  r = 0
@@ -1966,8 +1956,7 @@ class MainTable(tk.Canvas):
1966
1956
  scrollto = top + height
1967
1957
  if self.PAR.ops.page_up_down_select_row and self.RI.row_selection_enabled:
1968
1958
  r = bisect_left(self.row_positions, scrollto) - 1
1969
- current = self.currently_selected()
1970
- if current and current[0] == r:
1959
+ if self.selected and self.selected.row == r:
1971
1960
  r += 1
1972
1961
  if r > len(self.row_positions) - 2:
1973
1962
  r = len(self.row_positions) - 2
@@ -1992,20 +1981,19 @@ class MainTable(tk.Canvas):
1992
1981
  self.main_table_redraw_grid_and_text(redraw_row_index=True)
1993
1982
 
1994
1983
  def arrowkey_UP(self, event=None):
1995
- currently_selected = self.currently_selected()
1996
- if not currently_selected:
1984
+ if not self.selected:
1997
1985
  return
1998
- if currently_selected.type_ == "row":
1999
- r = currently_selected.row
1986
+ if self.selected.type_ == "rows":
1987
+ r = self.selected.row
2000
1988
  if r != 0 and self.RI.row_selection_enabled:
2001
1989
  if self.cell_completely_visible(r=r - 1, c=0):
2002
1990
  self.RI.select_row(r - 1, redraw=True)
2003
1991
  else:
2004
1992
  self.RI.select_row(r - 1)
2005
1993
  self.see(r - 1, 0, keep_xscroll=True, check_cell_visibility=False)
2006
- elif currently_selected.type_ in ("cell", "column"):
2007
- r = currently_selected[0]
2008
- c = currently_selected[1]
1994
+ elif self.selected.type_ in ("cells", "columns"):
1995
+ r = self.selected.row
1996
+ c = self.selected.column
2009
1997
  if r == 0 and self.CH.col_selection_enabled:
2010
1998
  if not self.cell_completely_visible(r=r, c=0):
2011
1999
  self.see(r, c, keep_xscroll=True, check_cell_visibility=False)
@@ -2017,11 +2005,10 @@ class MainTable(tk.Canvas):
2017
2005
  self.see(r - 1, c, keep_xscroll=True, check_cell_visibility=False)
2018
2006
 
2019
2007
  def arrowkey_RIGHT(self, event=None):
2020
- currently_selected = self.currently_selected()
2021
- if not currently_selected:
2008
+ if not self.selected:
2022
2009
  return
2023
- if currently_selected.type_ == "row":
2024
- r = currently_selected.row
2010
+ if self.selected.type_ == "rows":
2011
+ r = self.selected.row
2025
2012
  if self.single_selection_enabled or self.toggle_selection_enabled:
2026
2013
  if self.cell_completely_visible(r=r, c=0):
2027
2014
  self.select_cell(r, 0, redraw=True)
@@ -2034,8 +2021,8 @@ class MainTable(tk.Canvas):
2034
2021
  bottom_right_corner=True,
2035
2022
  check_cell_visibility=False,
2036
2023
  )
2037
- elif currently_selected.type_ == "column":
2038
- c = currently_selected.column
2024
+ elif self.selected.type_ == "columns":
2025
+ c = self.selected.column
2039
2026
  if c < len(self.col_positions) - 2 and self.CH.col_selection_enabled:
2040
2027
  if self.cell_completely_visible(r=0, c=c + 1):
2041
2028
  self.CH.select_col(c + 1, redraw=True)
@@ -2049,8 +2036,8 @@ class MainTable(tk.Canvas):
2049
2036
  check_cell_visibility=False,
2050
2037
  )
2051
2038
  else:
2052
- r = currently_selected[0]
2053
- c = currently_selected[1]
2039
+ r = self.selected.row
2040
+ c = self.selected.column
2054
2041
  if c < len(self.col_positions) - 2 and (self.single_selection_enabled or self.toggle_selection_enabled):
2055
2042
  if self.cell_completely_visible(r=r, c=c + 1):
2056
2043
  self.select_cell(r, c + 1, redraw=True)
@@ -2065,11 +2052,10 @@ class MainTable(tk.Canvas):
2065
2052
  )
2066
2053
 
2067
2054
  def arrowkey_DOWN(self, event=None):
2068
- currently_selected = self.currently_selected()
2069
- if not currently_selected:
2055
+ if not self.selected:
2070
2056
  return
2071
- if currently_selected.type_ == "row":
2072
- r = currently_selected.row
2057
+ if self.selected.type_ == "rows":
2058
+ r = self.selected.row
2073
2059
  if r < len(self.row_positions) - 2 and self.RI.row_selection_enabled:
2074
2060
  if self.cell_completely_visible(r=min(r + 2, len(self.row_positions) - 2), c=0):
2075
2061
  self.RI.select_row(r + 1, redraw=True)
@@ -2097,8 +2083,8 @@ class MainTable(tk.Canvas):
2097
2083
  bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2098
2084
  check_cell_visibility=False,
2099
2085
  )
2100
- elif currently_selected.type_ == "column":
2101
- c = currently_selected.column
2086
+ elif self.selected.type_ == "columns":
2087
+ c = self.selected.column
2102
2088
  if self.single_selection_enabled or self.toggle_selection_enabled:
2103
2089
  if self.cell_completely_visible(r=0, c=c):
2104
2090
  self.select_cell(0, c, redraw=True)
@@ -2112,8 +2098,8 @@ class MainTable(tk.Canvas):
2112
2098
  check_cell_visibility=False,
2113
2099
  )
2114
2100
  else:
2115
- r = currently_selected[0]
2116
- c = currently_selected[1]
2101
+ r = self.selected.row
2102
+ c = self.selected.column
2117
2103
  if r < len(self.row_positions) - 2 and (self.single_selection_enabled or self.toggle_selection_enabled):
2118
2104
  if self.cell_completely_visible(r=min(r + 2, len(self.row_positions) - 2), c=c):
2119
2105
  self.select_cell(r + 1, c, redraw=True)
@@ -2143,11 +2129,10 @@ class MainTable(tk.Canvas):
2143
2129
  )
2144
2130
 
2145
2131
  def arrowkey_LEFT(self, event=None):
2146
- currently_selected = self.currently_selected()
2147
- if not currently_selected:
2132
+ if not self.selected:
2148
2133
  return
2149
- if currently_selected.type_ == "column":
2150
- c = currently_selected.column
2134
+ if self.selected.type_ == "columns":
2135
+ c = self.selected.column
2151
2136
  if c != 0 and self.CH.col_selection_enabled:
2152
2137
  if self.cell_completely_visible(r=0, c=c - 1):
2153
2138
  self.CH.select_col(c - 1, redraw=True)
@@ -2160,9 +2145,9 @@ class MainTable(tk.Canvas):
2160
2145
  bottom_right_corner=True,
2161
2146
  check_cell_visibility=False,
2162
2147
  )
2163
- elif currently_selected.type_ == "cell":
2164
- r = currently_selected.row
2165
- c = currently_selected.column
2148
+ elif self.selected.type_ == "cells":
2149
+ r = self.selected.row
2150
+ c = self.selected.column
2166
2151
  if c == 0 and self.RI.row_selection_enabled:
2167
2152
  if not self.cell_completely_visible(r=r, c=0):
2168
2153
  self.see(r, c, keep_yscroll=True, check_cell_visibility=False)
@@ -2826,19 +2811,13 @@ class MainTable(tk.Canvas):
2826
2811
  rowsel = int(self.identify_row(y=event.y))
2827
2812
  colsel = int(self.identify_col(x=event.x))
2828
2813
  if rowsel < len(self.row_positions) - 1 and colsel < len(self.col_positions) - 1:
2829
- if self.cell_selected(rowsel, colsel):
2830
- self.deselect(rowsel, colsel)
2831
- else:
2832
- self.being_drawn_item = True
2833
- self.being_drawn_item = self.add_selection(
2834
- rowsel, colsel, set_as_current=True, run_binding_func=False
2835
- )
2836
- if self.ctrl_selection_binding_func:
2837
- self.ctrl_selection_binding_func(
2838
- self.get_select_event(being_drawn_item=self.being_drawn_item),
2839
- )
2814
+ self.being_drawn_item = True
2815
+ self.being_drawn_item = self.add_selection(rowsel, colsel, set_as_current=True, run_binding_func=False)
2816
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
2817
+ if self.ctrl_selection_binding_func:
2818
+ self.ctrl_selection_binding_func(sel_event)
2840
2819
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True, redraw_table=True)
2841
-
2820
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
2842
2821
  elif not self.ctrl_select_enabled:
2843
2822
  self.b1_press(event)
2844
2823
 
@@ -2850,21 +2829,23 @@ class MainTable(tk.Canvas):
2850
2829
  rowsel = int(self.identify_row(y=event.y))
2851
2830
  colsel = int(self.identify_col(x=event.x))
2852
2831
  if rowsel < len(self.row_positions) - 1 and colsel < len(self.col_positions) - 1:
2853
- currently_selected = self.currently_selected()
2854
- if currently_selected:
2855
- self.delete_item(currently_selected.tags[2])
2856
- box = self.get_shift_select_box(currently_selected.row, rowsel, currently_selected.column, colsel)
2857
- if currently_selected and currently_selected.type_ == "cell":
2858
- self.being_drawn_item = self.create_selection_box(*box, set_current=currently_selected)
2832
+ if self.selected and self.selected.type_ == "cells":
2833
+ self.being_drawn_item = self.recreate_selection_box(
2834
+ *self.get_shift_select_box(self.selected.row, rowsel, self.selected.column, colsel),
2835
+ fill_iid=self.selected.fill_iid,
2836
+ )
2859
2837
  else:
2860
2838
  self.being_drawn_item = self.add_selection(
2861
- rowsel, colsel, set_as_current=True, run_binding_func=False
2839
+ rowsel,
2840
+ colsel,
2841
+ set_as_current=True,
2842
+ run_binding_func=False,
2862
2843
  )
2863
2844
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True, redraw_table=True)
2845
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
2864
2846
  if self.shift_selection_binding_func:
2865
- self.shift_selection_binding_func(
2866
- self.get_select_event(being_drawn_item=self.being_drawn_item),
2867
- )
2847
+ self.shift_selection_binding_func(sel_event)
2848
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
2868
2849
  elif not self.ctrl_select_enabled:
2869
2850
  self.shift_b1_press(event)
2870
2851
 
@@ -2876,28 +2857,35 @@ class MainTable(tk.Canvas):
2876
2857
  rowsel = int(self.identify_row(y=event.y))
2877
2858
  colsel = int(self.identify_col(x=event.x))
2878
2859
  if rowsel < len(self.row_positions) - 1 and colsel < len(self.col_positions) - 1:
2879
- currently_selected = self.currently_selected()
2880
- box = self.get_shift_select_box(currently_selected.row, rowsel, currently_selected.column, colsel)
2881
- if currently_selected and currently_selected.type_ == "cell":
2860
+ if self.selected and self.selected.type_ == "cells":
2861
+ r_to_sel, c_to_sel = self.selected.row, self.selected.column
2882
2862
  self.deselect("all", redraw=False)
2883
- self.being_drawn_item = self.create_selection_box(*box, set_current=currently_selected)
2863
+ self.being_drawn_item = self.create_selection_box(
2864
+ *self.get_shift_select_box(r_to_sel, rowsel, c_to_sel, colsel),
2865
+ )
2866
+ self.set_currently_selected(r_to_sel, c_to_sel, self.being_drawn_item)
2884
2867
  else:
2885
- self.being_drawn_item = self.select_cell(rowsel, colsel, redraw=False, run_binding_func=False)
2868
+ self.being_drawn_item = self.select_cell(
2869
+ rowsel,
2870
+ colsel,
2871
+ redraw=False,
2872
+ run_binding_func=False,
2873
+ )
2886
2874
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True, redraw_table=True)
2875
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
2887
2876
  if self.shift_selection_binding_func:
2888
- self.shift_selection_binding_func(
2889
- self.get_select_event(being_drawn_item=self.being_drawn_item),
2890
- )
2877
+ self.shift_selection_binding_func(sel_event)
2878
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
2891
2879
 
2892
2880
  def get_shift_select_box(self, min_r: int, rowsel: int, min_c: int, colsel: int):
2893
2881
  if rowsel >= min_r and colsel >= min_c:
2894
- return min_r, min_c, rowsel + 1, colsel + 1, "cells"
2882
+ return min_r, min_c, rowsel + 1, colsel + 1
2895
2883
  elif rowsel >= min_r and min_c >= colsel:
2896
- return min_r, colsel, rowsel + 1, min_c + 1, "cells"
2884
+ return min_r, colsel, rowsel + 1, min_c + 1
2897
2885
  elif min_r >= rowsel and colsel >= min_c:
2898
- return rowsel, min_c, min_r + 1, colsel + 1, "cells"
2886
+ return rowsel, min_c, min_r + 1, colsel + 1
2899
2887
  elif min_r >= rowsel and min_c >= colsel:
2900
- return rowsel, colsel, min_r + 1, min_c + 1, "cells"
2888
+ return rowsel, colsel, min_r + 1, min_c + 1
2901
2889
 
2902
2890
  def get_b1_motion_box(self, start_row: int, start_col: int, end_row: int, end_col: int):
2903
2891
  if end_row >= start_row and end_col >= start_col and (end_row - start_row or end_col - start_col):
@@ -2924,17 +2912,16 @@ class MainTable(tk.Canvas):
2924
2912
  need_redraw = False
2925
2913
  end_row = self.identify_row(y=event.y)
2926
2914
  end_col = self.identify_col(x=event.x)
2927
- currently_selected = self.currently_selected()
2928
2915
  if (
2929
2916
  end_row < len(self.row_positions) - 1
2930
2917
  and end_col < len(self.col_positions) - 1
2931
- and currently_selected
2932
- and currently_selected.type_ == "cell"
2918
+ and self.selected
2919
+ and self.selected.type_ == "cells"
2933
2920
  ):
2934
2921
  box = self.get_b1_motion_box(
2935
2922
  *(
2936
- currently_selected.row,
2937
- currently_selected.column,
2923
+ self.selected.row,
2924
+ self.selected.column,
2938
2925
  end_row,
2939
2926
  end_col,
2940
2927
  )
@@ -2942,20 +2929,21 @@ class MainTable(tk.Canvas):
2942
2929
  if (
2943
2930
  box is not None
2944
2931
  and self.being_drawn_item is not None
2945
- and self.get_box_from_item(self.being_drawn_item) != box
2932
+ and self.coords_and_type(self.being_drawn_item) != box
2946
2933
  ):
2947
- self.deselect("all", redraw=False)
2948
2934
  if box[2] - box[0] != 1 or box[3] - box[1] != 1:
2949
- self.being_drawn_item = self.create_selection_box(*box, set_current=currently_selected)
2935
+ self.being_drawn_item = self.recreate_selection_box(*box[:-1], fill_iid=self.selected.fill_iid)
2950
2936
  else:
2951
2937
  self.being_drawn_item = self.select_cell(
2952
- currently_selected.row, currently_selected.column, run_binding_func=False
2938
+ box[0],
2939
+ box[1],
2940
+ run_binding_func=False,
2953
2941
  )
2954
2942
  need_redraw = True
2943
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
2955
2944
  if self.drag_selection_binding_func:
2956
- self.drag_selection_binding_func(
2957
- self.get_select_event(being_drawn_item=self.being_drawn_item),
2958
- )
2945
+ self.drag_selection_binding_func(sel_event)
2946
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
2959
2947
  if self.scroll_if_event_offscreen(event):
2960
2948
  need_redraw = True
2961
2949
  if need_redraw:
@@ -2968,17 +2956,16 @@ class MainTable(tk.Canvas):
2968
2956
  need_redraw = False
2969
2957
  end_row = self.identify_row(y=event.y)
2970
2958
  end_col = self.identify_col(x=event.x)
2971
- currently_selected = self.currently_selected()
2972
2959
  if (
2973
2960
  end_row < len(self.row_positions) - 1
2974
2961
  and end_col < len(self.col_positions) - 1
2975
- and currently_selected
2976
- and currently_selected.type_ == "cell"
2962
+ and self.selected
2963
+ and self.selected.type_ == "cells"
2977
2964
  ):
2978
2965
  box = self.get_b1_motion_box(
2979
2966
  *(
2980
- currently_selected.row,
2981
- currently_selected.column,
2967
+ self.selected.row,
2968
+ self.selected.column,
2982
2969
  end_row,
2983
2970
  end_col,
2984
2971
  )
@@ -2986,22 +2973,23 @@ class MainTable(tk.Canvas):
2986
2973
  if (
2987
2974
  box is not None
2988
2975
  and self.being_drawn_item is not None
2989
- and self.get_box_from_item(self.being_drawn_item) != box
2976
+ and self.coords_and_type(self.being_drawn_item) != box
2990
2977
  ):
2991
- self.delete_item(self.being_drawn_item)
2992
2978
  if box[2] - box[0] != 1 or box[3] - box[1] != 1:
2993
- self.being_drawn_item = self.create_selection_box(*box, set_current=currently_selected)
2979
+ self.being_drawn_item = self.recreate_selection_box(*box[:-1], self.selected.fill_iid)
2994
2980
  else:
2981
+ self.hide_selection_box(self.selected.fill_iid)
2995
2982
  self.being_drawn_item = self.add_selection(
2996
- currently_selected.row,
2997
- currently_selected.column,
2983
+ box[0],
2984
+ box[1],
2985
+ run_binding_func=False,
2998
2986
  set_as_current=True,
2999
2987
  )
3000
2988
  need_redraw = True
2989
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
3001
2990
  if self.drag_selection_binding_func:
3002
- self.drag_selection_binding_func(
3003
- self.get_select_event(being_drawn_item=self.being_drawn_item),
3004
- )
2991
+ self.drag_selection_binding_func(sel_event)
2992
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
3005
2993
  if self.scroll_if_event_offscreen(event):
3006
2994
  need_redraw = True
3007
2995
  if need_redraw:
@@ -3011,19 +2999,23 @@ class MainTable(tk.Canvas):
3011
2999
 
3012
3000
  def b1_release(self, event=None):
3013
3001
  if self.being_drawn_item is not None:
3014
- currently_selected = self.currently_selected()
3015
- to_sel = self.get_box_from_item(self.being_drawn_item)
3016
- self.delete_item(self.being_drawn_item)
3002
+ to_sel = self.coords_and_type(self.being_drawn_item)
3003
+ r_to_sel, c_to_sel = self.selected.row, self.selected.column
3004
+ self.hide_selection_box(self.being_drawn_item)
3017
3005
  self.being_drawn_item = None
3018
- self.create_selection_box(
3019
- *to_sel,
3020
- state="hidden" if to_sel[2] - to_sel[0] == 1 and to_sel[3] - to_sel[1] == 1 else "normal",
3021
- set_current=currently_selected,
3006
+ self.set_currently_selected(
3007
+ r_to_sel,
3008
+ c_to_sel,
3009
+ item=self.create_selection_box(
3010
+ *to_sel,
3011
+ state="hidden" if (to_sel[2] - to_sel[0] == 1 and to_sel[3] - to_sel[1] == 1) else "normal",
3012
+ set_current=False,
3013
+ ),
3022
3014
  )
3015
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
3023
3016
  if self.drag_selection_binding_func:
3024
- self.drag_selection_binding_func(
3025
- self.get_select_event(being_drawn_item=self.being_drawn_item),
3026
- )
3017
+ self.drag_selection_binding_func(sel_event)
3018
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
3027
3019
  if self.RI.width_resizing_enabled and self.RI.rsz_w is not None and self.RI.currently_resizing_width:
3028
3020
  self.delete_resize_lines()
3029
3021
  self.RI.delete_resize_lines()
@@ -3278,6 +3270,8 @@ class MainTable(tk.Canvas):
3278
3270
  )
3279
3271
 
3280
3272
  def zoom_font(self, table_font: tuple, header_font: tuple):
3273
+ self.saved_column_widths = {}
3274
+ self.saved_row_heights = {}
3281
3275
  # should record position prior to change and then see after change
3282
3276
  y = self.canvasy(0)
3283
3277
  x = self.canvasx(0)
@@ -3610,10 +3604,9 @@ class MainTable(tk.Canvas):
3610
3604
  h = min_rh
3611
3605
  rhs = defaultdict(lambda: int(min_rh))
3612
3606
  cws = []
3613
- x = self.txt_measure_canvas.create_text(0, 0, text="", font=self.PAR.ops.table_font)
3614
- x2 = self.txt_measure_canvas.create_text(0, 0, text="", font=self.PAR.ops.header_font)
3615
3607
  itmcon = self.txt_measure_canvas.itemconfig
3616
3608
  itmbbx = self.txt_measure_canvas.bbox
3609
+ self.txt_measure_canvas.itemconfig(self.txt_measure_canvas_text, font=self.PAR.ops.table_font)
3617
3610
  numrows = self.total_data_rows()
3618
3611
  if self.all_columns_displayed:
3619
3612
  itercols = range(self.total_data_cols())
@@ -3639,8 +3632,8 @@ class MainTable(tk.Canvas):
3639
3632
  for datarn in iterrows:
3640
3633
  txt = self.get_valid_cell_data_as_str(datarn, datacn, get_displayed=True)
3641
3634
  if txt:
3642
- itmcon(x, text=txt)
3643
- b = itmbbx(x)
3635
+ itmcon(self.txt_measure_canvas_text, text=txt)
3636
+ b = itmbbx(self.txt_measure_canvas_text)
3644
3637
  tw = b[2] - b[0] + 7
3645
3638
  h = b[3] - b[1] + 5
3646
3639
  else:
@@ -3663,8 +3656,6 @@ class MainTable(tk.Canvas):
3663
3656
  elif w > self.max_column_width:
3664
3657
  w = int(self.max_column_width)
3665
3658
  cws.append(w)
3666
- self.txt_measure_canvas.delete(x)
3667
- self.txt_measure_canvas.delete(x2)
3668
3659
  self.set_row_positions(itr=(height for height in rhs.values()))
3669
3660
  self.set_col_positions(itr=(width for width in cws))
3670
3661
  self.recreate_all_selection_boxes()
@@ -3873,10 +3864,17 @@ class MainTable(tk.Canvas):
3873
3864
  cols: list | tuple,
3874
3865
  create_ops: bool = True,
3875
3866
  ) -> None:
3876
- # self.cell_options = dict(to_add["cell_options"]) here
3867
+ self.tagged_cells = {
3868
+ tags: {(r, c if not (num := bisect_right(cols, c)) else c + num) for (r, c) in tagged}
3869
+ for tags, tagged in self.tagged_cells.items()
3870
+ }
3877
3871
  self.cell_options = {
3878
3872
  (r, c if not (num := bisect_right(cols, c)) else c + num): v for (r, c), v in self.cell_options.items()
3879
3873
  }
3874
+ self.tagged_columns = {
3875
+ tags: {c if not (num := bisect_right(cols, c)) else c + num for c in tagged}
3876
+ for tags, tagged in self.tagged_columns.items()
3877
+ }
3880
3878
  self.col_options = {
3881
3879
  c if not (num := bisect_right(cols, c)) else c + num: v for c, v in self.col_options.items()
3882
3880
  }
@@ -3888,7 +3886,7 @@ class MainTable(tk.Canvas):
3888
3886
  totalrows = None
3889
3887
  new_ops = self.PAR.create_options_from_span
3890
3888
  qkspan = self.span()
3891
- for name, span in self.named_spans.items():
3889
+ for span in self.named_spans.values():
3892
3890
  if isinstance(span["from_c"], int):
3893
3891
  for datacn in cols:
3894
3892
  if span["from_c"] > datacn:
@@ -3935,21 +3933,32 @@ class MainTable(tk.Canvas):
3935
3933
  rows: list | tuple,
3936
3934
  create_ops: bool = True,
3937
3935
  ) -> None:
3936
+ self.tagged_cells = {
3937
+ tags: {(r if not (num := bisect_right(rows, r)) else r + num, c) for (r, c) in tagged}
3938
+ for tags, tagged in self.tagged_cells.items()
3939
+ }
3938
3940
  self.cell_options = {
3939
3941
  (r if not (num := bisect_right(rows, r)) else r + num, c): v for (r, c), v in self.cell_options.items()
3940
3942
  }
3943
+ self.tagged_rows = {
3944
+ tags: {r if not (num := bisect_right(rows, r)) else r + num for r in tagged}
3945
+ for tags, tagged in self.tagged_rows.items()
3946
+ }
3941
3947
  self.row_options = {
3942
3948
  r if not (num := bisect_right(rows, r)) else r + num: v for r, v in self.row_options.items()
3943
3949
  }
3944
3950
  self.RI.cell_options = {
3945
3951
  r if not (num := bisect_right(rows, r)) else r + num: v for r, v in self.RI.cell_options.items()
3946
3952
  }
3953
+ self.RI.tree_rns = {
3954
+ v: r if not (num := bisect_right(rows, r)) else r + num for v, r in self.RI.tree_rns.items()
3955
+ }
3947
3956
  # if there are named spans where rows were added
3948
3957
  # add options to gap which was created by adding rows
3949
3958
  totalcols = None
3950
3959
  new_ops = self.PAR.create_options_from_span
3951
3960
  qkspan = self.span()
3952
- for name, span in self.named_spans.items():
3961
+ for span in self.named_spans.values():
3953
3962
  if isinstance(span["from_r"], int):
3954
3963
  for datarn in rows:
3955
3964
  if span["from_r"] > datarn:
@@ -4001,6 +4010,17 @@ class MainTable(tk.Canvas):
4001
4010
  to_del = set()
4002
4011
  if not to_bis:
4003
4012
  to_bis = sorted(to_del)
4013
+ self.tagged_cells = {
4014
+ tags: {
4015
+ (
4016
+ r,
4017
+ c if not (num := bisect_left(to_bis, c)) else c - num,
4018
+ )
4019
+ for (r, c) in tagged
4020
+ if c not in to_del
4021
+ }
4022
+ for tags, tagged in self.tagged_cells.items()
4023
+ }
4004
4024
  self.cell_options = {
4005
4025
  (
4006
4026
  r,
@@ -4009,6 +4029,10 @@ class MainTable(tk.Canvas):
4009
4029
  for (r, c), v in self.cell_options.items()
4010
4030
  if c not in to_del
4011
4031
  }
4032
+ self.tagged_columns = {
4033
+ tags: {c if not (num := bisect_left(to_bis, c)) else c - num for c in tagged if c not in to_del}
4034
+ for tags, tagged in self.tagged_columns.items()
4035
+ }
4012
4036
  self.col_options = {
4013
4037
  c if not (num := bisect_left(to_bis, c)) else c - num: v
4014
4038
  for c, v in self.col_options.items()
@@ -4036,7 +4060,7 @@ class MainTable(tk.Canvas):
4036
4060
  named_spans = self.get_spans_to_del_from_cols(cols=to_del)
4037
4061
  for name in named_spans:
4038
4062
  del self.named_spans[name]
4039
- for name, span in self.named_spans.items():
4063
+ for span in self.named_spans.values():
4040
4064
  if isinstance(span["from_c"], int):
4041
4065
  for c in to_bis:
4042
4066
  if span["from_c"] > c:
@@ -4066,6 +4090,17 @@ class MainTable(tk.Canvas):
4066
4090
  to_del = set()
4067
4091
  if not to_bis:
4068
4092
  to_bis = sorted(to_del)
4093
+ self.tagged_cells = {
4094
+ tags: {
4095
+ (
4096
+ r if not (num := bisect_left(to_bis, r)) else r - num,
4097
+ c,
4098
+ )
4099
+ for (r, c) in tagged
4100
+ if r not in to_del
4101
+ }
4102
+ for tags, tagged in self.tagged_cells.items()
4103
+ }
4069
4104
  self.cell_options = {
4070
4105
  (
4071
4106
  r if not (num := bisect_left(to_bis, r)) else r - num,
@@ -4074,6 +4109,10 @@ class MainTable(tk.Canvas):
4074
4109
  for (r, c), v in self.cell_options.items()
4075
4110
  if r not in to_del
4076
4111
  }
4112
+ self.tagged_rows = {
4113
+ tags: {r if not (num := bisect_left(to_bis, r)) else r - num for r in tagged if r not in to_del}
4114
+ for tags, tagged in self.tagged_rows.items()
4115
+ }
4077
4116
  self.row_options = {
4078
4117
  r if not (num := bisect_left(to_bis, r)) else r - num: v
4079
4118
  for r, v in self.row_options.items()
@@ -4084,6 +4123,11 @@ class MainTable(tk.Canvas):
4084
4123
  for r, v in self.RI.cell_options.items()
4085
4124
  if r not in to_del
4086
4125
  }
4126
+ self.RI.tree_rns = {
4127
+ v: r if not (num := bisect_left(to_bis, r)) else r - num
4128
+ for v, r in self.RI.tree_rns.items()
4129
+ if r not in to_del
4130
+ }
4087
4131
  self.del_rows_from_named_spans(
4088
4132
  to_del=to_del,
4089
4133
  to_bis=to_bis,
@@ -4101,7 +4145,7 @@ class MainTable(tk.Canvas):
4101
4145
  named_spans = self.get_spans_to_del_from_rows(rows=to_del)
4102
4146
  for name in named_spans:
4103
4147
  del self.named_spans[name]
4104
- for name, span in self.named_spans.items():
4148
+ for span in self.named_spans.values():
4105
4149
  if isinstance(span["from_r"], int):
4106
4150
  for r in to_bis:
4107
4151
  if span["from_r"] > r:
@@ -4132,6 +4176,7 @@ class MainTable(tk.Canvas):
4132
4176
  create_selections: bool = True,
4133
4177
  add_row_positions: bool = True,
4134
4178
  ) -> EventDataDict:
4179
+ self.saved_column_widths = {}
4135
4180
  saved_displayed_columns = list(self.displayed_columns)
4136
4181
  if isinstance(displayed_columns, list):
4137
4182
  self.displayed_columns = displayed_columns
@@ -4237,7 +4282,7 @@ class MainTable(tk.Canvas):
4237
4282
  name="add_columns",
4238
4283
  sheet=self.PAR.name,
4239
4284
  boxes=self.get_boxes(),
4240
- selected=self.currently_selected(),
4285
+ selected=self.selected,
4241
4286
  )
4242
4287
  if not try_binding(self.extra_begin_insert_cols_rc_func, event_data, "begin_add_columns"):
4243
4288
  return
@@ -4262,6 +4307,7 @@ class MainTable(tk.Canvas):
4262
4307
  create_selections: bool = True,
4263
4308
  add_col_positions: bool = True,
4264
4309
  ) -> EventDataDict:
4310
+ self.saved_row_heights = {}
4265
4311
  saved_displayed_rows = list(self.displayed_rows)
4266
4312
  if isinstance(displayed_rows, list):
4267
4313
  self.displayed_rows = displayed_rows
@@ -4295,7 +4341,7 @@ class MainTable(tk.Canvas):
4295
4341
  self.data.insert(rn, row)
4296
4342
  if cn > maxcn:
4297
4343
  maxcn = cn
4298
- if isinstance(self.row_index, list):
4344
+ if isinstance(self._row_index, list):
4299
4345
  self._row_index = insert_items(self._row_index, index, self.RI.fix_index)
4300
4346
  # if not hiding columns then we can extend col positions if necessary
4301
4347
  if add_col_positions and self.all_columns_displayed and maxcn + 1 > len(self.col_positions) - 1:
@@ -4365,7 +4411,7 @@ class MainTable(tk.Canvas):
4365
4411
  name="add_rows",
4366
4412
  sheet=self.PAR.name,
4367
4413
  boxes=self.get_boxes(),
4368
- selected=self.currently_selected(),
4414
+ selected=self.selected,
4369
4415
  )
4370
4416
  if not try_binding(self.extra_begin_insert_rows_rc_func, event_data, "begin_add_rows"):
4371
4417
  return
@@ -4419,7 +4465,8 @@ class MainTable(tk.Canvas):
4419
4465
  }
4420
4466
  if widths is None:
4421
4467
  widths = {
4422
- c: self.PAR.ops.default_column_width for c in reversed(range(displayed_ins_col, displayed_ins_col + numcols))
4468
+ c: self.PAR.ops.default_column_width
4469
+ for c in reversed(range(displayed_ins_col, displayed_ins_col + numcols))
4423
4470
  }
4424
4471
  else:
4425
4472
  widths = {
@@ -4468,9 +4515,7 @@ class MainTable(tk.Canvas):
4468
4515
  }
4469
4516
  if heights is None:
4470
4517
  default_row_height = self.get_default_row_height()
4471
- heights = {
4472
- r: default_row_height for r in reversed(range(displayed_ins_row, displayed_ins_row + numrows))
4473
- }
4518
+ heights = {r: default_row_height for r in reversed(range(displayed_ins_row, displayed_ins_row + numrows))}
4474
4519
  else:
4475
4520
  heights = {
4476
4521
  r: height
@@ -4521,6 +4566,7 @@ class MainTable(tk.Canvas):
4521
4566
  return event_data
4522
4567
 
4523
4568
  def delete_columns_displayed(self, cols: list, event_data: dict) -> EventDataDict:
4569
+ self.saved_column_widths = {}
4524
4570
  cols_set = set(cols)
4525
4571
  for c in reversed(cols):
4526
4572
  event_data["deleted"]["column_widths"][c] = self.col_positions[c + 1] - self.col_positions[c]
@@ -4529,14 +4575,13 @@ class MainTable(tk.Canvas):
4529
4575
 
4530
4576
  def rc_delete_columns(self, event: object = None):
4531
4577
  selected = sorted(self.get_selected_cols())
4532
- curr = self.currently_selected()
4533
- if not selected or not curr:
4578
+ if not self.selected:
4534
4579
  return
4535
4580
  event_data = event_dict(
4536
4581
  name="delete_columns",
4537
4582
  sheet=self.PAR.name,
4538
4583
  boxes=self.get_boxes(),
4539
- selected=self.currently_selected(),
4584
+ selected=self.selected,
4540
4585
  )
4541
4586
  if not try_binding(self.extra_begin_del_cols_rc_func, event_data, "begin_delete_columns"):
4542
4587
  return
@@ -4575,6 +4620,7 @@ class MainTable(tk.Canvas):
4575
4620
  return event_data
4576
4621
 
4577
4622
  def delete_rows_displayed(self, rows: list, event_data: dict) -> EventDataDict:
4623
+ self.saved_row_heights = {}
4578
4624
  rows_set = set(rows)
4579
4625
  for r in reversed(rows):
4580
4626
  event_data["deleted"]["row_heights"][r] = self.row_positions[r + 1] - self.row_positions[r]
@@ -4583,14 +4629,13 @@ class MainTable(tk.Canvas):
4583
4629
 
4584
4630
  def rc_delete_rows(self, event: object = None):
4585
4631
  selected = sorted(self.get_selected_rows())
4586
- curr = self.currently_selected()
4587
- if not selected or not curr:
4632
+ if not self.selected:
4588
4633
  return
4589
4634
  event_data = event_dict(
4590
4635
  name="delete_rows",
4591
4636
  sheet=self.PAR.name,
4592
4637
  boxes=self.get_boxes(),
4593
- selected=self.currently_selected(),
4638
+ selected=self.selected,
4594
4639
  )
4595
4640
  if not try_binding(self.extra_begin_del_rows_rc_func, event_data, "begin_delete_rows"):
4596
4641
  return
@@ -5022,27 +5067,28 @@ class MainTable(tk.Canvas):
5022
5067
  if draw_outline and self.PAR.ops.show_dropdown_borders:
5023
5068
  self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.PAR.ops.table_fg, tag=tag)
5024
5069
  if draw_arrow:
5025
- topysub = floor(self.table_half_txt_height / 2)
5026
- mid_y = y1 + floor(self.min_row_height / 2)
5027
- if mid_y + topysub + 1 >= y1 + self.table_txt_height - 1:
5028
- mid_y -= 1
5029
- if mid_y - topysub + 2 <= y1 + 4 + topysub:
5030
- mid_y -= 1
5031
- ty1 = mid_y + topysub + 1 if dd_is_open else mid_y - topysub + 3
5032
- ty2 = mid_y - topysub + 3 if dd_is_open else mid_y + topysub + 1
5033
- ty3 = mid_y + topysub + 1 if dd_is_open else mid_y - topysub + 3
5070
+ mod = (self.table_txt_height - 1) if self.table_txt_height % 2 else self.table_txt_height
5071
+ half_mod = mod / 2
5072
+ qtr_mod = mod / 4
5073
+ mid_y = (self.table_first_ln_ins - 1) if self.table_first_ln_ins % 2 else self.table_first_ln_ins
5074
+ if dd_is_open:
5075
+ points = (
5076
+ x2 - 3 - mod,
5077
+ y1 + mid_y + qtr_mod,
5078
+ x2 - 3 - half_mod,
5079
+ y1 + mid_y - qtr_mod,
5080
+ x2 - 3,
5081
+ y1 + mid_y + qtr_mod,
5082
+ )
5034
5083
  else:
5035
- ty1 = mid_y + topysub + 1 if dd_is_open else mid_y - topysub + 2
5036
- ty2 = mid_y - topysub + 2 if dd_is_open else mid_y + topysub + 1
5037
- ty3 = mid_y + topysub + 1 if dd_is_open else mid_y - topysub + 2
5038
- tx1 = x2 - self.table_txt_height + 1
5039
- tx2 = x2 - self.table_half_txt_height - 1
5040
- tx3 = x2 - 3
5041
- if tx2 - tx1 > tx3 - tx2:
5042
- tx1 += (tx2 - tx1) - (tx3 - tx2)
5043
- elif tx2 - tx1 < tx3 - tx2:
5044
- tx1 -= (tx3 - tx2) - (tx2 - tx1)
5045
- points = (tx1, ty1, tx2, ty2, tx3, ty3)
5084
+ points = (
5085
+ x2 - 3 - mod,
5086
+ y1 + mid_y - qtr_mod,
5087
+ x2 - 3 - half_mod,
5088
+ y1 + mid_y + qtr_mod,
5089
+ x2 - 3,
5090
+ y1 + mid_y - qtr_mod,
5091
+ )
5046
5092
  if self.hidd_dropdown:
5047
5093
  t, sh = self.hidd_dropdown.popitem()
5048
5094
  self.coords(t, points)
@@ -5168,8 +5214,6 @@ class MainTable(tk.Canvas):
5168
5214
  if i not in diffs:
5169
5215
  heights[i] -= change
5170
5216
  self.row_positions = list(accumulate(chain([0], heights)))
5171
- if resized_cols or resized_rows:
5172
- self.recreate_all_selection_boxes()
5173
5217
  last_col_line_pos = self.col_positions[-1] + 1
5174
5218
  last_row_line_pos = self.row_positions[-1] + 1
5175
5219
  if can_width >= last_col_line_pos + self.PAR.ops.empty_horizontal and self.PAR.xscroll_showing:
@@ -5194,27 +5238,35 @@ class MainTable(tk.Canvas):
5194
5238
  ):
5195
5239
  self.PAR.yscroll.grid(row=0, column=2, rowspan=3, sticky="nswe")
5196
5240
  self.PAR.yscroll_showing = True
5197
- self.configure(
5198
- scrollregion=(
5199
- 0,
5200
- 0,
5201
- last_col_line_pos + self.PAR.ops.empty_horizontal + 2,
5202
- last_row_line_pos + self.PAR.ops.empty_vertical + 2,
5203
- )
5241
+ scrollregion = (
5242
+ 0,
5243
+ 0,
5244
+ last_col_line_pos + self.PAR.ops.empty_horizontal + 2,
5245
+ last_row_line_pos + self.PAR.ops.empty_vertical + 2,
5204
5246
  )
5247
+ if scrollregion != self.scrollregion:
5248
+ self.configure(scrollregion=scrollregion)
5249
+ self.scrollregion = scrollregion
5205
5250
  scrollpos_bot = self.canvasy(can_height)
5206
5251
  end_row = bisect_right(self.row_positions, scrollpos_bot)
5207
5252
  if not scrollpos_bot >= self.row_positions[-1]:
5208
5253
  end_row += 1
5209
- if redraw_row_index and self.show_index:
5210
- self.RI.auto_set_index_width(end_row - 1)
5211
- # return
5212
5254
  scrollpos_left = self.canvasx(0)
5213
5255
  scrollpos_top = self.canvasy(0)
5214
5256
  scrollpos_right = self.canvasx(can_width)
5215
5257
  start_row = bisect_left(self.row_positions, scrollpos_top)
5216
5258
  start_col = bisect_left(self.col_positions, scrollpos_left)
5217
5259
  end_col = bisect_right(self.col_positions, scrollpos_right)
5260
+ changed_w = False
5261
+ if redraw_row_index and self.show_index:
5262
+ changed_w = self.RI.auto_set_index_width(
5263
+ end_row=end_row - 1,
5264
+ only_rows=[self.datarn(r) for r in range(start_row if not start_row else start_row - 1, end_row - 1)],
5265
+ )
5266
+ if changed_w:
5267
+ return False
5268
+ if resized_cols or resized_rows:
5269
+ self.recreate_all_selection_boxes()
5218
5270
  self.hidd_text.update(self.disp_text)
5219
5271
  self.disp_text = {}
5220
5272
  self.hidd_high.update(self.disp_high)
@@ -5326,7 +5378,7 @@ class MainTable(tk.Canvas):
5326
5378
  c_4_ = (int(c_4[1:3], 16), int(c_4[3:5], 16), int(c_4[5:], 16))
5327
5379
  rows_ = tuple(range(start_row, end_row))
5328
5380
  font = self.PAR.ops.table_font
5329
- dd_coords = self.get_existing_dropdown_coords()
5381
+ dd_coords = self.dropdown.get_coords()
5330
5382
  for c in range(start_col, end_col - 1):
5331
5383
  for r in rows_:
5332
5384
  rtopgridln = self.row_positions[r]
@@ -5528,10 +5580,11 @@ class MainTable(tk.Canvas):
5528
5580
  self.itemconfig(iid, state="hidden")
5529
5581
  dct[iid] = False
5530
5582
  if self.PAR.ops.show_selected_cells_border:
5531
- self.tag_raise("cellsbd")
5532
- self.tag_raise("selected")
5533
- self.tag_raise("rowsbd")
5534
- self.tag_raise("columnsbd")
5583
+ for iid, box in self.selection_boxes.items():
5584
+ if box.bd_iid:
5585
+ self.tag_raise(box.bd_iid)
5586
+ if self.selected:
5587
+ self.tag_raise(self.selected.iid)
5535
5588
  if redraw_header and self.show_header:
5536
5589
  self.CH.redraw_grid_and_text(
5537
5590
  last_col_line_pos,
@@ -5561,154 +5614,94 @@ class MainTable(tk.Canvas):
5561
5614
  cells: bool = True,
5562
5615
  rows: bool = True,
5563
5616
  columns: bool = True,
5564
- current: bool = True,
5565
5617
  reverse: bool = False,
5566
- ) -> list:
5567
- return sorted(
5568
- (self.find_withtag("cells") if cells else tuple())
5569
- + (self.find_withtag("rows") if rows else tuple())
5570
- + (self.find_withtag("columns") if columns else tuple())
5571
- + (self.find_withtag("selected") if current else tuple()),
5572
- reverse=reverse,
5618
+ ) -> Generator[int]:
5619
+ itr = reversed(self.selection_boxes.items()) if reverse else self.selection_boxes.items()
5620
+ return tuple(
5621
+ (iid, box)
5622
+ for iid, box in itr
5623
+ if cells and box.type_ == "cells" or rows and box.type_ == "rows" or columns and box.type_ == "columns"
5573
5624
  )
5574
5625
 
5575
5626
  def get_boxes(self) -> dict:
5576
- boxes = {}
5577
- for item in self.get_selection_items(current=False):
5578
- tags = self.gettags(item)
5579
- boxes[coords_tag_to_box_nt(tags[1])] = tags[0]
5580
- return boxes
5627
+ return {box.coords: box.type_ for box in self.selection_boxes.values()}
5581
5628
 
5582
5629
  def reselect_from_get_boxes(
5583
5630
  self,
5584
5631
  boxes: dict,
5585
- curr: tuple = tuple(),
5632
+ selected: tuple = tuple(),
5586
5633
  ) -> None:
5587
5634
  for (r1, c1, r2, c2), v in boxes.items():
5588
5635
  if r2 < len(self.row_positions) and c2 < len(self.col_positions):
5589
5636
  self.create_selection_box(r1, c1, r2, c2, v, run_binding=True)
5590
- if curr:
5591
- self.set_currently_selected(tags=curr.tags)
5592
-
5593
- def currently_selected(self, get_item: bool = False) -> int | tuple | CurrentlySelectedClass:
5594
- items = self.get_selection_items(cells=False, rows=False, columns=False)
5595
- if not items:
5596
- return tuple()
5597
- # more than one currently selected box shouldn't be allowed
5598
- # but just to make sure we get the most recent one anyway
5599
- if get_item:
5600
- return items[-1]
5601
- tags = self.gettags(items[-1])
5602
- r, c = coords_tag_to_int_tuple(tags[3])
5603
- # remove "s" from end
5604
- type_ = tags[4].split("_")[1][:-1]
5605
- return CurrentlySelectedClass(r, c, type_, tags)
5606
-
5607
- def move_currently_selected_within_box(self, r: int, c: int) -> None:
5608
- curr = self.currently_selected()
5609
- if curr:
5610
- self.set_currently_selected(r=r, c=c, item=self.to_item_int(curr.tags), tags=curr.tags)
5611
-
5612
- def set_currently_selected(self, r: int | None = None, c: int | None = None, **kwargs) -> None:
5613
- # if r and c are provided it will attempt to
5614
- # put currently box at that coordinate
5615
- # _________
5616
- # "selected" tags have the most information about the box
5617
- if "tags" in kwargs and kwargs["tags"]:
5618
- r_, c_ = coords_tag_to_int_tuple(kwargs["tags"][3])
5637
+ if selected:
5638
+ self.set_currently_selected(selected.row, selected.column, box=selected.coords)
5639
+
5640
+ def set_currently_selected(
5641
+ self,
5642
+ r: int | None = None,
5643
+ c: int | None = None,
5644
+ item: int | None = None,
5645
+ box: tuple[int, int, int, int] | None = None,
5646
+ ) -> None:
5647
+ if isinstance(item, int) and item in self.selection_boxes:
5648
+ selection_box = self.selection_boxes[item]
5649
+ r1, c1, r2, c2 = selection_box.coords
5619
5650
  if r is None:
5620
- r = r_
5651
+ r = r1
5621
5652
  if c is None:
5622
- c = c_
5623
- if "item" in kwargs:
5624
- self.set_currently_selected(
5625
- r=r, c=c, item=kwargs["item"], box=coords_tag_to_int_tuple(kwargs["tags"][1])
5653
+ c = c1
5654
+ if r1 <= r and c1 <= c and r2 > r and c2 > c:
5655
+ self.create_currently_selected_box(
5656
+ r,
5657
+ c,
5658
+ selection_box.type_,
5659
+ selection_box.fill_iid,
5626
5660
  )
5627
- else:
5628
- self.set_currently_selected(r=r, c=c, box=coords_tag_to_int_tuple(kwargs["tags"][1]))
5629
- return
5630
- # place at item if r and c are in bounds
5631
- if "item" in kwargs:
5632
- tags = self.gettags(self.to_item_int(kwargs["item"]))
5633
- if tags:
5634
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
5635
- if r is None:
5636
- r = r1
5637
- if c is None:
5638
- c = c1
5639
- if r1 <= r and c1 <= c and r2 > r and c2 > c:
5640
- self.create_currently_selected_box(
5641
- r,
5642
- c,
5643
- ("selected", tags[1], tags[2], f"{r}_{c}", f"type_{tags[0]}"),
5644
- )
5645
- return
5661
+ return
5646
5662
  # currently selected is pointed at any selection box with "box" coordinates
5647
- if "box" in kwargs:
5663
+ if isinstance(box, tuple):
5648
5664
  if r is None:
5649
- r = kwargs["box"][0]
5665
+ r = box[0]
5650
5666
  if c is None:
5651
- c = kwargs["box"][1]
5652
- for item in self.get_selection_items(current=False):
5653
- tags = self.gettags(item)
5654
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
5655
- if kwargs["box"] == (r1, c1, r2, c2) and r1 <= r and c1 <= c and r2 > r and c2 > c:
5667
+ c = box[1]
5668
+ for item, selection_box in self.get_selection_items(reverse=True):
5669
+ r1, c1, r2, c2 = selection_box.coords
5670
+ if box == (r1, c1, r2, c2) and r1 <= r and c1 <= c and r2 > r and c2 > c:
5656
5671
  self.create_currently_selected_box(
5657
5672
  r,
5658
5673
  c,
5659
- ("selected", tags[1], tags[2], f"{r}_{c}", f"type_{tags[0]}"),
5674
+ selection_box.type_,
5675
+ selection_box.fill_iid,
5660
5676
  )
5661
5677
  return
5662
5678
  # currently selected is just pointed at a coordinate
5663
5679
  # find the top most box there, requires r and c
5664
5680
  if r is not None and c is not None:
5665
- for item in self.get_selection_items(current=False):
5666
- tags = self.gettags(item)
5667
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
5681
+ for item, selection_box in self.get_selection_items(reverse=True):
5682
+ r1, c1, r2, c2 = selection_box.coords
5668
5683
  if r1 <= r and c1 <= c and r2 > r and c2 > c:
5669
5684
  self.create_currently_selected_box(
5670
5685
  r,
5671
5686
  c,
5672
- ("selected", tags[1], tags[2], f"{r}_{c}", f"type_{tags[0]}"),
5687
+ selection_box.type_,
5688
+ selection_box.fill_iid,
5673
5689
  )
5674
5690
  return
5675
5691
  # wasn't provided an item and couldn't find a box at coords so select cell
5676
5692
  self.select_cell(r, c, redraw=True)
5677
5693
 
5678
5694
  def set_current_to_last(self) -> None:
5679
- items = self.get_selection_items(current=False)
5680
- if items:
5681
- item = items[-1]
5682
- r1, c1, r2, c2, type_ = self.get_box_from_item(item)
5695
+ if self.selection_boxes:
5696
+ box = next(iter(reversed(self.selection_boxes.values())))
5697
+ r1, c1, r2, c2 = box.coords
5683
5698
  if r2 - r1 == 1 and c2 - c1 == 1:
5684
- self.itemconfig(item, state="hidden")
5685
- self.set_currently_selected(item=item)
5699
+ self.itemconfig(box.fill_iid, state="hidden")
5700
+ self.set_currently_selected(item=box.fill_iid)
5686
5701
 
5687
- def delete_item(self, item: int, set_current: bool = True) -> None:
5688
- if item is None:
5689
- return
5690
- item = self.to_item_int(item)
5691
- self.delete(f"iid_{item}")
5692
- self.RI.delete(f"iid_{item}")
5693
- self.CH.delete(f"iid_{item}")
5694
-
5695
- def get_box_from_item(self, item: int, get_dict: bool = False) -> dict | tuple:
5696
- if item is None or item is True:
5697
- return tuple()
5698
- # it's in the form of an item tag f"iid_{item}"
5699
- item = self.to_item_int(item)
5700
- tags = self.gettags(item)
5701
- if tags:
5702
- if get_dict:
5703
- if tags[0] == "selected":
5704
- return {coords_tag_to_box_nt(tags[1]): tags[4].split("_")[1]}
5705
- else:
5706
- return {coords_tag_to_box_nt(tags[1]): tags[0]}
5707
- else:
5708
- if tags[0] == "selected":
5709
- return Box_t(*(coords_tag_to_int_tuple(tags[1]) + (tags[4].split("_")[1],)))
5710
- else:
5711
- return Box_t(*(coords_tag_to_int_tuple(tags[1]) + (tags[0],)))
5702
+ def coords_and_type(self, item: int) -> tuple:
5703
+ if item in self.selection_boxes:
5704
+ return Box_t(*(self.selection_boxes[item].coords + (self.selection_boxes[item].type_,)))
5712
5705
  return tuple()
5713
5706
 
5714
5707
  def get_selected_box_bg_fg(self, type_: str) -> tuple:
@@ -5719,65 +5712,103 @@ class MainTable(tk.Canvas):
5719
5712
  elif type_ == "columns":
5720
5713
  return self.PAR.ops.table_selected_columns_bg, self.PAR.ops.table_selected_box_columns_fg
5721
5714
 
5722
- def create_currently_selected_box(self, r: int, c: int, tags: tuple) -> int:
5723
- type_ = tags[4].split("_")[1]
5715
+ def create_currently_selected_box(
5716
+ self,
5717
+ r: int,
5718
+ c: int,
5719
+ type_: Literal["cells", "rows", "columns"],
5720
+ fill_iid: int,
5721
+ ) -> int:
5724
5722
  fill, outline = self.get_selected_box_bg_fg(type_=type_)
5725
- iid = self.currently_selected(get_item=True)
5726
5723
  x1 = self.col_positions[c] + 1
5727
5724
  y1 = self.row_positions[r] + 1
5728
5725
  x2 = self.col_positions[c + 1] if index_exists(self.col_positions, c + 1) else self.col_positions[c]
5729
5726
  y2 = self.row_positions[r + 1] if index_exists(self.row_positions, r + 1) else self.row_positions[r]
5730
- if isinstance(iid, int):
5731
- self.coords(
5732
- iid,
5727
+ self.hide_selected()
5728
+ if self.PAR.ops.show_selected_cells_border:
5729
+ fill = ""
5730
+ else:
5731
+ outline = ""
5732
+ iid = self.display_box(
5733
+ x1,
5734
+ y1,
5735
+ x2,
5736
+ y2,
5737
+ fill=fill,
5738
+ outline=outline,
5739
+ state="normal",
5740
+ tags="selected",
5741
+ width=2,
5742
+ )
5743
+ self.selected = Selected(
5744
+ row=r,
5745
+ column=c,
5746
+ type_=type_,
5747
+ box=self.selection_boxes[fill_iid].coords,
5748
+ iid=iid,
5749
+ fill_iid=fill_iid,
5750
+ )
5751
+ if self.PAR.ops.show_selected_cells_border:
5752
+ self.tag_raise(iid)
5753
+ else:
5754
+ self.tag_lower(iid)
5755
+ self.lower_selection_boxes()
5756
+ return iid
5757
+
5758
+ def display_box(
5759
+ self,
5760
+ x1: int,
5761
+ y1: int,
5762
+ x2: int,
5763
+ y2: int,
5764
+ fill: str,
5765
+ outline: str,
5766
+ state: str,
5767
+ tags: str | tuple[str],
5768
+ width: int,
5769
+ ) -> int:
5770
+ if self.hidd_boxes:
5771
+ iid = self.hidd_boxes.pop()
5772
+ self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags, width=width)
5773
+ self.coords(iid, x1, y1, x2, y2)
5774
+ else:
5775
+ iid = self.create_rectangle(
5733
5776
  x1,
5734
5777
  y1,
5735
5778
  x2,
5736
5779
  y2,
5780
+ fill=fill,
5781
+ outline=outline,
5782
+ state=state,
5783
+ tags=tags,
5784
+ width=width,
5737
5785
  )
5738
- if self.PAR.ops.show_selected_cells_border:
5739
- self.itemconfig(
5740
- iid,
5741
- fill="",
5742
- outline=outline,
5743
- width=2,
5744
- tags=tags,
5745
- )
5746
- self.tag_raise(iid)
5747
- else:
5748
- self.itemconfig(
5749
- iid,
5750
- fill=fill,
5751
- outline="",
5752
- tags=tags,
5753
- )
5754
- else:
5755
- if self.PAR.ops.show_selected_cells_border:
5756
- iid = self.create_rectangle(
5757
- x1,
5758
- y1,
5759
- x2,
5760
- y2,
5761
- fill="",
5762
- outline=outline,
5763
- width=2,
5764
- tags=tags,
5765
- )
5766
- else:
5767
- iid = self.create_rectangle(
5768
- x1,
5769
- y1,
5770
- x2,
5771
- y2,
5772
- fill=fill,
5773
- outline="",
5774
- tags=tags,
5775
- )
5776
- if not self.PAR.ops.show_selected_cells_border:
5777
- self.tag_lower(iid)
5778
- self.lower_selection_boxes()
5786
+ self.disp_boxes.add(iid)
5779
5787
  return iid
5780
5788
 
5789
+ def hide_box(self, item: int | None) -> None:
5790
+ if isinstance(item, int):
5791
+ self.disp_boxes.discard(item)
5792
+ self.hidd_boxes.add(item)
5793
+ self.itemconfig(item, state="hidden")
5794
+
5795
+ def hide_selection_box(self, item: int | None, set_current: bool = True) -> None:
5796
+ if item is None:
5797
+ return
5798
+ box = self.selection_boxes.pop(item)
5799
+ self.hide_box(box.fill_iid)
5800
+ self.hide_box(box.bd_iid)
5801
+ self.RI.hide_box(box.index)
5802
+ self.CH.hide_box(box.header)
5803
+ if self.selected.fill_iid == item:
5804
+ self.hide_selected()
5805
+ self.set_current_to_last()
5806
+
5807
+ def hide_selected(self) -> None:
5808
+ if self.selected:
5809
+ self.hide_box(self.selected.iid)
5810
+ self.selected = tuple()
5811
+
5781
5812
  def create_selection_box(
5782
5813
  self,
5783
5814
  r1: int,
@@ -5795,23 +5826,16 @@ class MainTable(tk.Canvas):
5795
5826
  if self.row_positions == [0]:
5796
5827
  r1 = 0
5797
5828
  r2 = 0
5798
- self.itemconfig("cells", state="normal")
5799
5829
  if type_ == "cells":
5800
- fill_tags = ("cells", f"{r1}_{c1}_{r2}_{c2}")
5801
- border_tags = ("cellsbd", f"{r1}_{c1}_{r2}_{c2}")
5802
5830
  mt_bg = self.PAR.ops.table_selected_cells_bg
5803
5831
  mt_border_col = self.PAR.ops.table_selected_cells_border_fg
5804
5832
  elif type_ == "rows":
5805
- fill_tags = ("rows", f"{r1}_{c1}_{r2}_{c2}")
5806
- border_tags = ("rowsbd", f"{r1}_{c1}_{r2}_{c2}")
5807
5833
  mt_bg = self.PAR.ops.table_selected_rows_bg
5808
5834
  mt_border_col = self.PAR.ops.table_selected_rows_border_fg
5809
5835
  elif type_ == "columns":
5810
- fill_tags = ("columns", f"{r1}_{c1}_{r2}_{c2}")
5811
- border_tags = ("columnsbd", f"{r1}_{c1}_{r2}_{c2}")
5812
5836
  mt_bg = self.PAR.ops.table_selected_columns_bg
5813
5837
  mt_border_col = self.PAR.ops.table_selected_columns_border_fg
5814
- fill_iid = self.create_rectangle(
5838
+ fill_iid = self.display_box(
5815
5839
  self.col_positions[c1],
5816
5840
  self.row_positions[r1],
5817
5841
  self.canvasx(self.winfo_width()) if self.PAR.ops.selected_rows_to_end_of_window else self.col_positions[c2],
@@ -5819,26 +5843,20 @@ class MainTable(tk.Canvas):
5819
5843
  fill=mt_bg,
5820
5844
  outline="",
5821
5845
  state=state,
5822
- tags=fill_tags,
5846
+ tags=type_,
5847
+ width=1,
5823
5848
  )
5824
- tag_addon = f"iid_{fill_iid}"
5825
- self.addtag_withtag(tag_addon, fill_iid)
5826
- self.last_selected = fill_iid
5827
- tag_index_header_type = fill_tags + (tag_addon,)
5828
- tag_index_header = ("cells", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5829
- ch_tags = tag_index_header if type_ == "rows" else tag_index_header_type
5830
- ri_tags = tag_index_header if type_ == "columns" else tag_index_header_type
5831
- border_tags = border_tags + (tag_addon,)
5832
- self.RI.create_rectangle(
5849
+ index_iid = self.RI.display_box(
5833
5850
  0,
5834
5851
  self.row_positions[r1],
5835
5852
  self.RI.current_width - 1,
5836
5853
  self.row_positions[r2],
5837
5854
  fill=self.PAR.ops.index_selected_rows_bg if type_ == "rows" else self.PAR.ops.index_selected_cells_bg,
5838
5855
  outline="",
5839
- tags=ri_tags,
5856
+ state="normal",
5857
+ tags="cells" if type_ == "columns" else type_,
5840
5858
  )
5841
- self.CH.create_rectangle(
5859
+ header_iid = self.CH.display_box(
5842
5860
  self.col_positions[c1],
5843
5861
  0,
5844
5862
  self.col_positions[c2],
@@ -5847,51 +5865,54 @@ class MainTable(tk.Canvas):
5847
5865
  self.PAR.ops.header_selected_columns_bg if type_ == "columns" else self.PAR.ops.header_selected_cells_bg
5848
5866
  ),
5849
5867
  outline="",
5850
- tags=ch_tags,
5868
+ state="normal",
5869
+ tags="cells" if type_ == "rows" else type_,
5851
5870
  )
5852
- if set_current:
5853
- if set_current is True:
5854
- curr_r = r1
5855
- curr_c = c1
5856
- elif isinstance(set_current, tuple):
5857
- curr_r = set_current[0]
5858
- curr_c = set_current[1]
5859
- currently_selected_tags = (
5860
- "selected", # tags[0] name
5861
- f"{r1}_{c1}_{r2}_{c2}", # tags[1] dimensions of box it's attached to
5862
- tag_addon, # tags[2] iid of box it's attached to
5863
- f"{curr_r}_{curr_c}", # tags[3] position of currently selected box
5864
- f"type_{type_}", # tags[4] type of box it's attached to
5865
- )
5866
- self.create_currently_selected_box(curr_r, curr_c, tags=currently_selected_tags)
5871
+ bd_iid = None
5867
5872
  if self.PAR.ops.show_selected_cells_border and (
5868
5873
  (self.being_drawn_item is None and self.RI.being_drawn_item is None and self.CH.being_drawn_item is None)
5869
- or len(self.anything_selected()) > 1
5874
+ or self.selection_boxes
5870
5875
  ):
5871
- self.create_rectangle(
5876
+ bd_iid = self.display_box(
5872
5877
  self.col_positions[c1],
5873
5878
  self.row_positions[r1],
5874
5879
  self.col_positions[c2],
5875
5880
  self.row_positions[r2],
5876
5881
  fill="",
5877
5882
  outline=mt_border_col,
5878
- tags=border_tags,
5883
+ state="normal",
5884
+ tags=f"{type_}bd",
5885
+ width=1,
5879
5886
  )
5887
+ self.tag_raise(bd_iid)
5888
+ self.selection_boxes[fill_iid] = SelectionBox(
5889
+ fill_iid=fill_iid,
5890
+ bd_iid=bd_iid,
5891
+ index=index_iid,
5892
+ header=header_iid,
5893
+ coords=Box_nt(r1, c1, r2, c2),
5894
+ type_=type_,
5895
+ )
5896
+ if set_current:
5897
+ if set_current is True:
5898
+ curr_r = r1
5899
+ curr_c = c1
5900
+ elif isinstance(set_current, tuple):
5901
+ curr_r = set_current[0]
5902
+ curr_c = set_current[1]
5903
+ self.create_currently_selected_box(curr_r, curr_c, type_, fill_iid)
5880
5904
  self.lower_selection_boxes()
5881
5905
  if run_binding:
5882
5906
  self.run_selection_binding(type_)
5883
5907
  return fill_iid
5884
5908
 
5885
5909
  def lower_selection_boxes(self) -> None:
5886
- self.tag_lower("rows")
5887
- self.RI.tag_lower("rows")
5888
- self.tag_lower("columns")
5889
- self.CH.tag_lower("columns")
5890
- self.tag_lower("cells")
5891
- self.RI.tag_lower("cells")
5892
- self.CH.tag_lower("cells")
5893
- if self.PAR.ops.show_selected_cells_border:
5894
- self.tag_raise("selected")
5910
+ for iid, box in reversed(self.selection_boxes.items()):
5911
+ self.tag_lower(iid)
5912
+ self.RI.tag_lower(box.index)
5913
+ self.CH.tag_lower(box.header)
5914
+ if self.PAR.ops.show_selected_cells_border and self.selected:
5915
+ self.tag_raise(self.selected.iid)
5895
5916
 
5896
5917
  def recreate_selection_box(
5897
5918
  self,
@@ -5900,26 +5921,24 @@ class MainTable(tk.Canvas):
5900
5921
  r2: int,
5901
5922
  c2: int,
5902
5923
  fill_iid: int,
5924
+ state: str = "",
5903
5925
  run_binding: bool = False,
5904
- ) -> None:
5905
- alltags = self.gettags(fill_iid)
5906
- type_ = alltags[0]
5907
- tag_addon = f"iid_{fill_iid}"
5926
+ ) -> int:
5927
+ type_ = self.selection_boxes[fill_iid].type_
5928
+ self.selection_boxes[fill_iid].coords = Box_nt(r1, c1, r2, c2)
5908
5929
  if type_ == "cells":
5909
- fill_tags = ("cells", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5910
- border_tags = ("cellsbd", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5911
5930
  mt_bg = self.PAR.ops.table_selected_cells_bg
5912
5931
  mt_border_col = self.PAR.ops.table_selected_cells_border_fg
5913
5932
  elif type_ == "rows":
5914
- fill_tags = ("rows", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5915
- border_tags = ("rowsbd", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5916
5933
  mt_bg = self.PAR.ops.table_selected_rows_bg
5917
5934
  mt_border_col = self.PAR.ops.table_selected_rows_border_fg
5918
5935
  elif type_ == "columns":
5919
- fill_tags = ("columns", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5920
- border_tags = ("columnsbd", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5921
5936
  mt_bg = self.PAR.ops.table_selected_columns_bg
5922
5937
  mt_border_col = self.PAR.ops.table_selected_columns_border_fg
5938
+ if not state:
5939
+ state = "normal" if (r2 - r1 > 1 or c2 - c1 > 1) else "hidden"
5940
+ if self.selected.fill_iid == fill_iid:
5941
+ self.selected = self.selected._replace(box=Box_nt(r1, c1, r2, c2))
5923
5942
  self.coords(
5924
5943
  fill_iid,
5925
5944
  self.col_positions[c1],
@@ -5931,114 +5950,101 @@ class MainTable(tk.Canvas):
5931
5950
  fill_iid,
5932
5951
  fill=mt_bg,
5933
5952
  outline="",
5934
- tags=fill_tags,
5953
+ tags=type_,
5954
+ state=state,
5935
5955
  )
5936
- tag_index_header_type = fill_tags
5937
- tag_index_header = ("cells", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5938
- ch_tags = tag_index_header if type_ == "rows" else tag_index_header_type
5939
- ri_tags = tag_index_header if type_ == "columns" else tag_index_header_type
5940
5956
  self.RI.coords(
5941
- tag_addon,
5957
+ self.selection_boxes[fill_iid].index,
5942
5958
  0,
5943
5959
  self.row_positions[r1],
5944
5960
  self.RI.current_width - 1,
5945
5961
  self.row_positions[r2],
5946
5962
  )
5947
5963
  self.RI.itemconfig(
5948
- tag_addon,
5964
+ self.selection_boxes[fill_iid].index,
5949
5965
  fill=self.PAR.ops.index_selected_rows_bg if type_ == "rows" else self.PAR.ops.index_selected_cells_bg,
5950
5966
  outline="",
5951
- tags=ri_tags,
5967
+ tags="cells" if type_ == "columns" else type_,
5952
5968
  )
5953
5969
  self.CH.coords(
5954
- tag_addon,
5970
+ self.selection_boxes[fill_iid].header,
5955
5971
  self.col_positions[c1],
5956
5972
  0,
5957
5973
  self.col_positions[c2],
5958
5974
  self.CH.current_height - 1,
5959
5975
  )
5960
5976
  self.CH.itemconfig(
5961
- tag_addon,
5977
+ self.selection_boxes[fill_iid].header,
5962
5978
  fill=(
5963
5979
  self.PAR.ops.header_selected_columns_bg if type_ == "columns" else self.PAR.ops.header_selected_cells_bg
5964
5980
  ),
5965
5981
  outline="",
5966
- tags=ch_tags,
5982
+ tags="cells" if type_ == "rows" else type_,
5967
5983
  )
5968
- # check for border of selection box which is a separate item
5969
- border_item = [item for item in self.find_withtag(tag_addon) if self.gettags(item)[0].endswith("bd")]
5970
- if border_item:
5971
- border_item = border_item[0]
5984
+ if bd_iid := self.selection_boxes[fill_iid].bd_iid:
5972
5985
  if self.PAR.ops.show_selected_cells_border:
5973
5986
  self.coords(
5974
- border_item,
5987
+ bd_iid,
5975
5988
  self.col_positions[c1],
5976
5989
  self.row_positions[r1],
5977
5990
  self.col_positions[c2],
5978
5991
  self.row_positions[r2],
5979
5992
  )
5980
5993
  self.itemconfig(
5981
- border_item,
5994
+ bd_iid,
5982
5995
  fill="",
5983
5996
  outline=mt_border_col,
5984
- tags=border_tags,
5997
+ tags=f"{type_}bd",
5998
+ state="normal",
5985
5999
  )
6000
+ self.tag_raise(bd_iid)
5986
6001
  else:
5987
- self.delete(border_item)
6002
+ self.hide_box(bd_iid)
5988
6003
  if run_binding:
5989
6004
  self.run_selection_binding(type_)
6005
+ return fill_iid
5990
6006
 
5991
6007
  def run_selection_binding(self, type_: str) -> None:
5992
6008
  if type_ == "cells":
6009
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
5993
6010
  if self.selection_binding_func:
5994
- self.selection_binding_func(
5995
- self.get_select_event(being_drawn_item=self.being_drawn_item),
5996
- )
6011
+ self.selection_binding_func(sel_event)
5997
6012
  elif type_ == "rows":
6013
+ sel_event = self.get_select_event(being_drawn_item=self.RI.being_drawn_item)
5998
6014
  if self.RI.selection_binding_func:
5999
- self.RI.selection_binding_func(
6000
- self.get_select_event(being_drawn_item=self.RI.being_drawn_item),
6001
- )
6015
+ self.RI.selection_binding_func(sel_event)
6002
6016
  elif type_ == "columns":
6017
+ sel_event = self.get_select_event(being_drawn_item=self.CH.being_drawn_item)
6003
6018
  if self.CH.selection_binding_func:
6004
- self.CH.selection_binding_func(
6005
- self.get_select_event(being_drawn_item=self.CH.being_drawn_item),
6006
- )
6019
+ self.CH.selection_binding_func(sel_event)
6020
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
6007
6021
 
6008
6022
  def recreate_all_selection_boxes(self) -> None:
6009
- curr = self.currently_selected()
6010
- if not curr:
6023
+ if not self.selected:
6011
6024
  return
6012
- for item in self.get_selection_items(current=False):
6013
- tags = self.gettags(item)
6014
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
6025
+ for item, box in self.get_selection_items():
6026
+ r1, c1, r2, c2 = box.coords
6015
6027
  if r1 >= len(self.row_positions) - 1 or c1 >= len(self.col_positions) - 1:
6016
- self.delete_item(item)
6028
+ self.hide_selection_box(item)
6017
6029
  continue
6018
6030
  if r2 > len(self.row_positions) - 1:
6019
6031
  r2 = len(self.row_positions) - 1
6020
6032
  if c2 > len(self.col_positions) - 1:
6021
6033
  c2 = len(self.col_positions) - 1
6022
6034
  self.recreate_selection_box(r1, c1, r2, c2, item)
6023
- self.set_currently_selected(tags=curr.tags)
6024
-
6025
- def to_item_int(self, item: int | str | tuple) -> int:
6026
- # item arg is a tuple of tags
6027
- if isinstance(item, tuple):
6028
- if isinstance(item, CurrentlySelectedClass):
6029
- return int(item[3][2].split("_")[1])
6030
- return int(item[2].split("_")[1])
6031
- # item arg is one of those tags
6032
- if isinstance(item, str):
6033
- return int(item.split("_")[1])
6034
- # item is probably an int
6035
- return item
6035
+ if self.selected:
6036
+ r = self.selected.row
6037
+ c = self.selected.column
6038
+ if r < len(self.row_positions) - 1 and c < len(self.col_positions) - 1:
6039
+ self.set_currently_selected(r, c, item=self.selected.fill_iid)
6040
+ else:
6041
+ box = self.selection_boxes[self.selected.fill_iid]
6042
+ self.set_currently_selected(box.coords.from_r, box.coords.from_c, item=box.fill_iid)
6036
6043
 
6037
6044
  def get_redraw_selections(self, startr: int, endr: int, startc: int, endc: int) -> dict:
6038
6045
  d = defaultdict(list)
6039
- for item in self.get_selection_items(current=False):
6040
- tags = self.gettags(item)
6041
- d[tags[0]].append(coords_tag_to_int_tuple(tags[1]))
6046
+ for item, box in self.get_selection_items():
6047
+ d[box.type_].append(box.coords)
6042
6048
  d2 = {}
6043
6049
  if "cells" in d:
6044
6050
  d2["cells"] = {
@@ -6059,8 +6065,8 @@ class MainTable(tk.Canvas):
6059
6065
  min_y = float("inf")
6060
6066
  max_x = 0
6061
6067
  max_y = 0
6062
- for item in self.get_selection_items():
6063
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6068
+ for item, box in self.get_selection_items():
6069
+ r1, c1, r2, c2 = box.coords
6064
6070
  if r1 < min_y:
6065
6071
  min_y = r1
6066
6072
  if c1 < min_x:
@@ -6085,14 +6091,14 @@ class MainTable(tk.Canvas):
6085
6091
  within_r2 = within_range[1]
6086
6092
  if get_cells:
6087
6093
  if within_range is None:
6088
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6089
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6094
+ for item, box in self.get_selection_items(cells=False, columns=False):
6095
+ r1, c1, r2, c2 = box.coords
6090
6096
  s.update(set(product(range(r1, r2), range(0, len(self.col_positions) - 1))))
6091
6097
  if get_cells_as_rows:
6092
6098
  s.update(self.get_selected_cells())
6093
6099
  else:
6094
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6095
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6100
+ for item, box in self.get_selection_items(cells=False, columns=False):
6101
+ r1, c1, r2, c2 = box.coords
6096
6102
  if r1 >= within_r1 or r2 <= within_r2:
6097
6103
  s.update(
6098
6104
  set(
@@ -6115,14 +6121,14 @@ class MainTable(tk.Canvas):
6115
6121
  )
6116
6122
  else:
6117
6123
  if within_range is None:
6118
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6119
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6124
+ for item, box in self.get_selection_items(cells=False, columns=False):
6125
+ r1, c1, r2, c2 = box.coords
6120
6126
  s.update(set(range(r1, r2)))
6121
6127
  if get_cells_as_rows:
6122
6128
  s.update(set(tup[0] for tup in self.get_selected_cells()))
6123
6129
  else:
6124
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6125
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6130
+ for item, box in self.get_selection_items(cells=False, columns=False):
6131
+ r1, c1, r2, c2 = box.coords
6126
6132
  if r1 >= within_r1 or r2 <= within_r2:
6127
6133
  s.update(set(range(r1 if r1 > within_r1 else within_r1, r2 if r2 < within_r2 else within_r2)))
6128
6134
  if get_cells_as_rows:
@@ -6153,14 +6159,14 @@ class MainTable(tk.Canvas):
6153
6159
  within_c2 = within_range[1]
6154
6160
  if get_cells:
6155
6161
  if within_range is None:
6156
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6157
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6162
+ for item, box in self.get_selection_items(cells=False, rows=False):
6163
+ r1, c1, r2, c2 = box.coords
6158
6164
  s.update(set(product(range(c1, c2), range(0, len(self.row_positions) - 1))))
6159
6165
  if get_cells_as_cols:
6160
6166
  s.update(self.get_selected_cells())
6161
6167
  else:
6162
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6163
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6168
+ for item, box in self.get_selection_items(cells=False, rows=False):
6169
+ r1, c1, r2, c2 = box.coords
6164
6170
  if c1 >= within_c1 or c2 <= within_c2:
6165
6171
  s.update(
6166
6172
  set(
@@ -6183,14 +6189,14 @@ class MainTable(tk.Canvas):
6183
6189
  )
6184
6190
  else:
6185
6191
  if within_range is None:
6186
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6187
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6192
+ for item, box in self.get_selection_items(cells=False, rows=False):
6193
+ r1, c1, r2, c2 = box.coords
6188
6194
  s.update(set(range(c1, c2)))
6189
6195
  if get_cells_as_cols:
6190
6196
  s.update(set(tup[1] for tup in self.get_selected_cells()))
6191
6197
  else:
6192
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6193
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6198
+ for item in self.get_selection_items(cells=False, rows=False):
6199
+ r1, c1, r2, c2 = box.coords
6194
6200
  if c1 >= within_c1 or c2 <= within_c2:
6195
6201
  s.update(set(range(c1 if c1 > within_c1 else within_c1, c2 if c2 < within_c2 else within_c2)))
6196
6202
  if get_cells_as_cols:
@@ -6222,12 +6228,12 @@ class MainTable(tk.Canvas):
6222
6228
  within_r2 = within_range[2]
6223
6229
  within_c2 = within_range[3]
6224
6230
  if within_range is None:
6225
- for item in self.get_selection_items(rows=get_rows, columns=get_cols, current=False):
6226
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6231
+ for item, box in self.get_selection_items(rows=get_rows, columns=get_cols):
6232
+ r1, c1, r2, c2 = box.coords
6227
6233
  s.update(set(product(range(r1, r2), range(c1, c2))))
6228
6234
  else:
6229
- for item in self.get_selection_items(rows=get_rows, columns=get_cols, current=False):
6230
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6235
+ for item in self.get_selection_items(rows=get_rows, columns=get_cols):
6236
+ r1, c1, r2, c2 = box.coords
6231
6237
  if r1 >= within_r1 or c1 >= within_c1 or r2 <= within_r2 or c2 <= within_c2:
6232
6238
  s.update(
6233
6239
  set(
@@ -6240,14 +6246,10 @@ class MainTable(tk.Canvas):
6240
6246
  return s
6241
6247
 
6242
6248
  def get_all_selection_boxes(self) -> tuple[tuple[int, int, int, int]]:
6243
- return tuple(coords_tag_to_int_tuple(self.gettags(item)[1]) for item in self.get_selection_items(current=False))
6249
+ return tuple(box.coords for item, box in self.get_selection_items())
6244
6250
 
6245
6251
  def get_all_selection_boxes_with_types(self) -> list[tuple[tuple[int, int, int, int], str]]:
6246
- boxes = []
6247
- for item in self.get_selection_items(current=False):
6248
- tags = self.gettags(item)
6249
- boxes.append((coords_tag_to_int_tuple(tags[1]), tags[0]))
6250
- return boxes
6252
+ return [(box.coords, box.type) for item, box in self.get_selection_items()]
6251
6253
 
6252
6254
  def all_selected(self) -> bool:
6253
6255
  for r1, c1, r2, c2 in self.get_all_selection_boxes():
@@ -6255,8 +6257,6 @@ class MainTable(tk.Canvas):
6255
6257
  return True
6256
6258
  return False
6257
6259
 
6258
- # don't have to use "selected" because you can't
6259
- # have a current without a selection box
6260
6260
  def cell_selected(
6261
6261
  self,
6262
6262
  r: int,
@@ -6266,8 +6266,8 @@ class MainTable(tk.Canvas):
6266
6266
  ) -> bool:
6267
6267
  if not isinstance(r, int) or not isinstance(c, int):
6268
6268
  return False
6269
- for item in self.get_selection_items(rows=inc_rows, columns=inc_cols, current=False):
6270
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6269
+ for item, box in self.get_selection_items(rows=inc_rows, columns=inc_cols):
6270
+ r1, c1, r2, c2 = box.coords
6271
6271
  if r1 <= r and c1 <= c and r2 > r and c2 > c:
6272
6272
  return True
6273
6273
  return False
@@ -6275,8 +6275,8 @@ class MainTable(tk.Canvas):
6275
6275
  def col_selected(self, c: int) -> bool:
6276
6276
  if not isinstance(c, int):
6277
6277
  return False
6278
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6279
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6278
+ for item, box in self.get_selection_items(cells=False, rows=False):
6279
+ r1, c1, r2, c2 = box.coords
6280
6280
  if c1 <= c and c2 > c:
6281
6281
  return True
6282
6282
  return False
@@ -6284,8 +6284,8 @@ class MainTable(tk.Canvas):
6284
6284
  def row_selected(self, r: int) -> bool:
6285
6285
  if not isinstance(r, int):
6286
6286
  return False
6287
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6288
- r1, c1, r2, c2 = coords_tag_to_int_tuple(self.gettags(item)[1])
6287
+ for item, box in self.get_selection_items(cells=False, columns=False):
6288
+ r1, c1, r2, c2 = box.coords
6289
6289
  if r1 <= r and r2 > r:
6290
6290
  return True
6291
6291
  return False
@@ -6296,24 +6296,25 @@ class MainTable(tk.Canvas):
6296
6296
  exclude_rows: bool = False,
6297
6297
  exclude_cells: bool = False,
6298
6298
  ) -> list[int]:
6299
- return self.get_selection_items(
6300
- columns=not exclude_columns,
6301
- rows=not exclude_rows,
6302
- cells=not exclude_cells,
6303
- current=False,
6304
- )
6299
+ return [
6300
+ item
6301
+ for item, box in self.get_selection_items(
6302
+ columns=not exclude_columns,
6303
+ rows=not exclude_rows,
6304
+ cells=not exclude_cells,
6305
+ )
6306
+ ]
6305
6307
 
6306
6308
  def open_cell(
6307
6309
  self,
6308
6310
  event: object = None,
6309
6311
  ignore_existing_editor: bool = False,
6310
6312
  ) -> None:
6311
- if not self.anything_selected() or (not ignore_existing_editor and self.text_editor_id is not None):
6313
+ if not self.anything_selected() or (not ignore_existing_editor and self.text_editor.open):
6312
6314
  return
6313
- currently_selected = self.currently_selected()
6314
- if not currently_selected:
6315
+ if not self.selected:
6315
6316
  return
6316
- r, c = int(currently_selected[0]), int(currently_selected[1])
6317
+ r, c = self.selected.row, self.selected.column
6317
6318
  datacn = self.datacn(c)
6318
6319
  datarn = self.datarn(r)
6319
6320
  if self.get_cell_kwargs(datarn, datacn, key="readonly"):
@@ -6393,7 +6394,6 @@ class MainTable(tk.Canvas):
6393
6394
  text = event.char
6394
6395
  else:
6395
6396
  return False
6396
- self.text_editor_loc = (r, c)
6397
6397
  if self.extra_begin_edit_cell_func:
6398
6398
  try:
6399
6399
  text = self.extra_begin_edit_cell_func(
@@ -6402,9 +6402,9 @@ class MainTable(tk.Canvas):
6402
6402
  sheet=self.PAR.name,
6403
6403
  key=extra_func_key,
6404
6404
  value=text,
6405
- loc=tuple(self.text_editor_loc),
6405
+ loc=(r, c),
6406
6406
  boxes=self.get_boxes(),
6407
- selected=self.currently_selected(),
6407
+ selected=self.selected,
6408
6408
  )
6409
6409
  )
6410
6410
  except Exception:
@@ -6416,15 +6416,13 @@ class MainTable(tk.Canvas):
6416
6416
  text = "" if text is None else text
6417
6417
  if self.PAR.ops.cell_auto_resize_enabled:
6418
6418
  self.set_cell_size_to_text(r, c, only_set_if_too_small=True, redraw=True, run_binding=True)
6419
-
6420
- if (r, c) == self.text_editor_loc and self.text_editor is not None:
6421
- self.text_editor.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
6419
+ if self.text_editor.open and (r, c) == self.text_editor.coords:
6420
+ self.text_editor.window.set_text(self.text_editor.get() + "" if not isinstance(text, str) else text)
6422
6421
  return
6423
- if self.text_editor is not None:
6424
- self.destroy_text_editor()
6422
+ if self.text_editor.open:
6423
+ self.hide_text_editor()
6425
6424
  if not self.see(r=r, c=c, check_cell_visibility=True):
6426
6425
  self.refresh()
6427
- self.text_editor_loc = (r, c)
6428
6426
  x = self.col_positions[c]
6429
6427
  y = self.row_positions[r]
6430
6428
  w = self.col_positions[c + 1] - x + 1
@@ -6434,9 +6432,8 @@ class MainTable(tk.Canvas):
6434
6432
  c if self.all_columns_displayed else self.displayed_columns[c],
6435
6433
  none_to_empty_str = True)}"""
6436
6434
  bg, fg = self.PAR.ops.table_bg, self.PAR.ops.table_fg
6437
- self.text_editor = TextEditor(
6438
- self,
6439
- menu_kwargs=DotDict(
6435
+ kwargs = {
6436
+ "menu_kwargs": DotDict(
6440
6437
  {
6441
6438
  "font": self.PAR.ops.table_font,
6442
6439
  "foreground": self.PAR.ops.popup_menu_fg,
@@ -6445,35 +6442,40 @@ class MainTable(tk.Canvas):
6445
6442
  "activeforeground": self.PAR.ops.popup_menu_highlight_fg,
6446
6443
  }
6447
6444
  ),
6448
- sheet_ops=self.PAR.ops,
6449
- border_color=self.PAR.ops.table_selected_cells_border_fg,
6450
- text=text,
6451
- state=state,
6452
- width=w,
6453
- height=h,
6454
- show_border=self.PAR.ops.show_selected_cells_border,
6455
- bg=bg,
6456
- fg=fg,
6457
- align=self.get_cell_align(r, c),
6458
- r=r,
6459
- c=c,
6460
- newline_binding=self.text_editor_newline_binding,
6461
- )
6462
- self.text_editor.update_idletasks()
6463
- self.text_editor_id = self.create_window((x, y), window=self.text_editor, anchor="nw")
6445
+ "sheet_ops": self.PAR.ops,
6446
+ "border_color": self.PAR.ops.table_selected_cells_border_fg,
6447
+ "text": text,
6448
+ "state": state,
6449
+ "width": w,
6450
+ "height": h,
6451
+ "show_border": self.PAR.ops.show_selected_cells_border,
6452
+ "bg": bg,
6453
+ "fg": fg,
6454
+ "align": self.get_cell_align(r, c),
6455
+ "r": r,
6456
+ "c": c,
6457
+ }
6458
+ if not self.text_editor.window:
6459
+ self.text_editor.window = TextEditor(self, newline_binding=self.text_editor_newline_binding)
6460
+ self.text_editor.canvas_id = self.create_window((x, y), window=self.text_editor.window, anchor="nw")
6461
+ self.text_editor.window.reset(**kwargs)
6462
+ if not self.text_editor.open:
6463
+ self.itemconfig(self.text_editor.canvas_id, state="normal")
6464
+ self.text_editor.open = True
6465
+ self.coords(self.text_editor.canvas_id, x, y)
6464
6466
  if not dropdown:
6465
- self.text_editor.textedit.focus_set()
6466
- self.text_editor.scroll_to_bottom()
6467
- self.text_editor.textedit.bind("<Alt-Return>", lambda _x: self.text_editor_newline_binding(r, c))
6467
+ self.text_editor.tktext.focus_set()
6468
+ self.text_editor.window.scroll_to_bottom()
6469
+ self.text_editor.tktext.bind("<Alt-Return>", lambda _x: self.text_editor_newline_binding(r, c))
6468
6470
  if USER_OS == "darwin":
6469
- self.text_editor.textedit.bind("<Option-Return>", lambda _x: self.text_editor_newline_binding(r, c))
6471
+ self.text_editor.tktext.bind("<Option-Return>", lambda _x: self.text_editor_newline_binding(r, c))
6470
6472
  for key, func in self.text_editor_user_bound_keys.items():
6471
- self.text_editor.textedit.bind(key, func)
6472
- self.text_editor.textedit.bind("<Tab>", lambda _x: self.close_text_editor((r, c, "Tab")))
6473
- self.text_editor.textedit.bind("<Return>", lambda _x: self.close_text_editor((r, c, "Return")))
6473
+ self.text_editor.tktext.bind(key, func)
6474
+ self.text_editor.tktext.bind("<Tab>", lambda _x: self.close_text_editor((r, c, "Tab")))
6475
+ self.text_editor.tktext.bind("<Return>", lambda _x: self.close_text_editor((r, c, "Return")))
6474
6476
  if not dropdown:
6475
- self.text_editor.textedit.bind("<FocusOut>", lambda _x: self.close_text_editor((r, c, "FocusOut")))
6476
- self.text_editor.textedit.bind("<Escape>", lambda _x: self.close_text_editor((r, c, "Escape")))
6477
+ self.text_editor.tktext.bind("<FocusOut>", lambda _x: self.close_text_editor((r, c, "FocusOut")))
6478
+ self.text_editor.tktext.bind("<Escape>", lambda _x: self.close_text_editor((r, c, "Escape")))
6477
6479
  return True
6478
6480
 
6479
6481
  # displayed indexes
@@ -6484,80 +6486,69 @@ class MainTable(tk.Canvas):
6484
6486
  event: object = None,
6485
6487
  check_lines: bool = True,
6486
6488
  ) -> None:
6487
- datarn = self.datarn(r)
6488
- datacn = self.datacn(c)
6489
- curr_height = self.text_editor.winfo_height()
6490
- if not check_lines or self.get_lines_cell_height(self.text_editor.get_num_lines() + 1) > curr_height:
6489
+ curr_height = self.text_editor.window.winfo_height()
6490
+ if not check_lines or self.get_lines_cell_height(self.text_editor.window.get_num_lines() + 1) > curr_height:
6491
6491
  new_height = curr_height + self.table_xtra_lines_increment
6492
6492
  space_bot = self.get_space_bot(r)
6493
6493
  if new_height > space_bot:
6494
6494
  new_height = space_bot
6495
6495
  if new_height != curr_height:
6496
- self.text_editor.config(height=new_height)
6497
- kwargs = self.get_cell_kwargs(datarn, datacn, key="dropdown")
6498
- if kwargs:
6499
- text_editor_h = self.text_editor.winfo_height()
6496
+ self.text_editor.window.config(height=new_height)
6497
+ if self.dropdown.open and self.dropdown.get_coords() == (r, c):
6498
+ text_editor_h = self.text_editor.window.winfo_height()
6500
6499
  win_h, anchor = self.get_dropdown_height_anchor(r, c, text_editor_h)
6501
6500
  if anchor == "nw":
6502
6501
  self.coords(
6503
- kwargs["canvas_id"],
6502
+ self.dropdown.canvas_id,
6504
6503
  self.col_positions[c],
6505
6504
  self.row_positions[r] + text_editor_h - 1,
6506
6505
  )
6507
- self.itemconfig(kwargs["canvas_id"], anchor=anchor, height=win_h)
6506
+ self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
6508
6507
  elif anchor == "sw":
6509
6508
  self.coords(
6510
- kwargs["canvas_id"],
6509
+ self.dropdown.canvas_id,
6511
6510
  self.col_positions[c],
6512
6511
  self.row_positions[r],
6513
6512
  )
6514
- self.itemconfig(kwargs["canvas_id"], anchor=anchor, height=win_h)
6513
+ self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
6515
6514
 
6516
6515
  def refresh_open_window_positions(self):
6517
- if self.text_editor is not None:
6518
- r, c = self.text_editor_loc
6519
- self.text_editor.config(height=self.row_positions[r + 1] - self.row_positions[r])
6516
+ if self.text_editor.open:
6517
+ r, c = self.text_editor.coords
6518
+ self.text_editor.window.config(height=self.row_positions[r + 1] - self.row_positions[r])
6520
6519
  self.coords(
6521
- self.text_editor_id,
6520
+ self.text_editor.canvas_id,
6522
6521
  self.col_positions[c],
6523
6522
  self.row_positions[r],
6524
6523
  )
6525
- if self.existing_dropdown_window is not None:
6526
- r, c = self.get_existing_dropdown_coords()
6527
- if self.text_editor is None:
6528
- text_editor_h = self.row_positions[r + 1] - self.row_positions[r]
6529
- anchor = self.itemcget(self.existing_dropdown_canvas_id, "anchor")
6530
- win_h = 0
6531
- else:
6532
- text_editor_h = self.text_editor.winfo_height()
6524
+ if self.dropdown.open:
6525
+ r, c = self.dropdown.get_coords()
6526
+ if self.text_editor.open:
6527
+ text_editor_h = self.text_editor.window.winfo_height()
6533
6528
  win_h, anchor = self.get_dropdown_height_anchor(r, c, text_editor_h)
6529
+ else:
6530
+ text_editor_h = self.row_positions[r + 1] - self.row_positions[r]
6531
+ anchor = self.itemcget(self.dropdown.canvas_id, "anchor")
6532
+ # win_h = 0
6534
6533
  if anchor == "nw":
6535
6534
  self.coords(
6536
- self.existing_dropdown_canvas_id,
6535
+ self.dropdown.canvas_id,
6537
6536
  self.col_positions[c],
6538
6537
  self.row_positions[r] + text_editor_h - 1,
6539
6538
  )
6540
- # self.itemconfig(self.existing_dropdown_canvas_id, anchor=anchor, height=win_h)
6539
+ # self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
6541
6540
  elif anchor == "sw":
6542
6541
  self.coords(
6543
- self.existing_dropdown_canvas_id,
6542
+ self.dropdown.canvas_id,
6544
6543
  self.col_positions[c],
6545
6544
  self.row_positions[r],
6546
6545
  )
6547
- # self.itemconfig(self.existing_dropdown_canvas_id, anchor=anchor, height=win_h)
6546
+ # self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
6548
6547
 
6549
- def destroy_text_editor(self, reason: None | str = None) -> None:
6550
- self.text_editor_loc = None
6551
- try:
6552
- self.delete(self.text_editor_id)
6553
- except Exception:
6554
- pass
6555
- try:
6556
- self.text_editor.destroy()
6557
- except Exception:
6558
- pass
6559
- self.text_editor = None
6560
- self.text_editor_id = None
6548
+ def hide_text_editor(self, reason: None | str = None) -> None:
6549
+ if self.text_editor.open:
6550
+ self.itemconfig(self.text_editor.canvas_id, state="hidden")
6551
+ self.text_editor.open = False
6561
6552
  if reason == "Escape":
6562
6553
  self.focus_set()
6563
6554
 
@@ -6569,20 +6560,17 @@ class MainTable(tk.Canvas):
6569
6560
  # checking if text editor should be closed or not
6570
6561
  focused = self.focus_get()
6571
6562
  try:
6572
- if focused == self.text_editor.textedit.rc_popup_menu:
6563
+ if focused == self.text_editor.tktext.rc_popup_menu:
6573
6564
  return "break"
6574
6565
  except Exception:
6575
6566
  pass
6576
6567
  if focused is None and editor_info:
6577
6568
  return "break"
6578
6569
  if editor_info[2] == "Escape":
6579
- self.destroy_text_editor("Escape")
6580
- self.close_dropdown_window()
6570
+ self.hide_text_editor_and_dropdown()
6581
6571
  return
6582
6572
  # setting cell data with text editor value
6583
6573
  self.text_editor_value = self.text_editor.get()
6584
- self.destroy_text_editor()
6585
- currently_selected = self.currently_selected()
6586
6574
  r, c = editor_info[0], editor_info[1]
6587
6575
  datarn, datacn = self.datarn(r), self.datacn(c)
6588
6576
  event_data = event_dict(
@@ -6593,7 +6581,7 @@ class MainTable(tk.Canvas):
6593
6581
  value=self.text_editor_value,
6594
6582
  loc=(r, c),
6595
6583
  boxes=self.get_boxes(),
6596
- selected=currently_selected,
6584
+ selected=self.selected,
6597
6585
  )
6598
6586
  edited = False
6599
6587
  set_data = partial(
@@ -6616,12 +6604,13 @@ class MainTable(tk.Canvas):
6616
6604
  if (
6617
6605
  r is not None
6618
6606
  and c is not None
6619
- and currently_selected
6620
- and r == currently_selected[0]
6621
- and c == currently_selected[1]
6607
+ and self.selected
6608
+ and r == self.selected.row
6609
+ and c == self.selected.column
6622
6610
  and (self.single_selection_enabled or self.toggle_selection_enabled)
6611
+ and (edited or self.cell_equal_to(datarn, datacn, self.text_editor_value))
6623
6612
  ):
6624
- r1, c1, r2, c2 = self.get_box_containing_current()
6613
+ r1, c1, r2, c2 = self.selection_boxes[self.selected.fill_iid].coords
6625
6614
  numcols = c2 - c1
6626
6615
  numrows = r2 - r1
6627
6616
  if numcols == 1 and numrows == 1:
@@ -6669,7 +6658,7 @@ class MainTable(tk.Canvas):
6669
6658
  new_r = r1
6670
6659
  elif numrows > 1:
6671
6660
  new_r = r + 1
6672
- self.move_currently_selected_within_box(new_r, new_c)
6661
+ self.set_currently_selected(new_r, new_c, item=self.selected.fill_iid)
6673
6662
  self.see(
6674
6663
  new_r,
6675
6664
  new_c,
@@ -6677,20 +6666,18 @@ class MainTable(tk.Canvas):
6677
6666
  bottom_right_corner=True,
6678
6667
  check_cell_visibility=True,
6679
6668
  )
6680
- self.close_dropdown_window(r, c)
6681
6669
  self.recreate_all_selection_boxes()
6682
- self.refresh()
6670
+ self.hide_text_editor_and_dropdown()
6683
6671
  if editor_info[2] != "FocusOut":
6684
6672
  self.focus_set()
6685
6673
  return "break"
6686
6674
 
6687
6675
  def tab_key(self, event: object = None) -> str:
6688
- currently_selected = self.currently_selected()
6689
- if not currently_selected:
6676
+ if not self.selected:
6690
6677
  return
6691
- r = currently_selected.row
6692
- c = currently_selected.column
6693
- r1, c1, r2, c2 = self.get_box_containing_current()
6678
+ r = self.selected.row
6679
+ c = self.selected.column
6680
+ r1, c1, r2, c2 = self.selection_boxes[self.selected.fill_iid].coords
6694
6681
  numcols = c2 - c1
6695
6682
  numrows = r2 - r1
6696
6683
  if numcols == 1 and numrows == 1:
@@ -6711,7 +6698,7 @@ class MainTable(tk.Canvas):
6711
6698
  new_r = r1
6712
6699
  elif numrows > 1:
6713
6700
  new_r = r + 1
6714
- self.move_currently_selected_within_box(new_r, new_c)
6701
+ self.set_currently_selected(new_r, new_c, item=self.selected.fill_iid)
6715
6702
  self.see(
6716
6703
  new_r,
6717
6704
  new_c,
@@ -6791,8 +6778,7 @@ class MainTable(tk.Canvas):
6791
6778
  c: int,
6792
6779
  event: object = None,
6793
6780
  ) -> None:
6794
- self.destroy_text_editor("Escape")
6795
- self.destroy_opened_dropdown_window()
6781
+ self.hide_text_editor("Escape")
6796
6782
  datarn = self.datarn(r)
6797
6783
  datacn = self.datacn(c)
6798
6784
  kwargs = self.get_cell_kwargs(datarn, datacn, key="dropdown")
@@ -6800,69 +6786,75 @@ class MainTable(tk.Canvas):
6800
6786
  if not self.open_text_editor(event=event, r=r, c=c, dropdown=True):
6801
6787
  return
6802
6788
  win_h, anchor = self.get_dropdown_height_anchor(r, c)
6803
- window = self.PAR.dropdown_class(
6804
- self.winfo_toplevel(),
6805
- r,
6806
- c,
6807
- width=self.col_positions[c + 1] - self.col_positions[c] + 1,
6808
- height=win_h,
6809
- font=self.PAR.ops.table_font,
6810
- colors={
6811
- "bg": self.PAR.ops.popup_menu_bg,
6812
- "fg": self.PAR.ops.popup_menu_fg,
6813
- "highlight_bg": self.PAR.ops.popup_menu_highlight_bg,
6814
- "highlight_fg": self.PAR.ops.popup_menu_highlight_fg,
6815
- },
6816
- outline_color=self.get_selected_box_bg_fg(type_="cells")[1],
6817
- outline_thickness=2,
6818
- values=kwargs["values"],
6819
- close_dropdown_window=self.close_dropdown_window,
6820
- search_function=kwargs["search_function"],
6821
- arrowkey_RIGHT=self.arrowkey_RIGHT,
6822
- arrowkey_LEFT=self.arrowkey_LEFT,
6823
- align="w",
6824
- ) # self.get_cell_align(r, c)
6825
- if kwargs["state"] == "normal":
6826
- if anchor == "nw":
6827
- ypos = self.row_positions[r] + self.text_editor.h_ - 1
6789
+ if anchor == "nw":
6790
+ if kwargs["state"] == "normal":
6791
+ ypos = self.row_positions[r] + self.text_editor.window.winfo_height() - 1
6828
6792
  else:
6829
- ypos = self.row_positions[r]
6830
- kwargs["canvas_id"] = self.create_window((self.col_positions[c], ypos), window=window, anchor=anchor)
6831
- self.text_editor.textedit.bind(
6793
+ ypos = self.row_positions[r + 1]
6794
+ else:
6795
+ ypos = self.row_positions[r]
6796
+ if self.dropdown.window is not None:
6797
+ self.dropdown.window.search_function = kwargs["search_function"]
6798
+ self.dropdown.window.r = r
6799
+ self.dropdown.window.c = c
6800
+ self.dropdown.window.row = -1
6801
+ self.dropdown.window.set_options()
6802
+ self.dropdown.window.values(kwargs["values"])
6803
+ if not self.dropdown.open:
6804
+ self.itemconfig(self.dropdown.canvas_id, state="normal")
6805
+ self.coords(self.dropdown.canvas_id, self.col_positions[c], ypos)
6806
+ else:
6807
+ self.dropdown.window = self.PAR.dropdown_class(
6808
+ self.winfo_toplevel(),
6809
+ r,
6810
+ c,
6811
+ width=self.col_positions[c + 1] - self.col_positions[c] + 1,
6812
+ height=win_h,
6813
+ font=self.PAR.ops.table_font,
6814
+ ops=self.PAR.ops,
6815
+ outline_color=self.get_selected_box_bg_fg(type_="cells")[1],
6816
+ outline_thickness=2,
6817
+ values=kwargs["values"],
6818
+ close_dropdown_window=self.close_dropdown_window,
6819
+ search_function=kwargs["search_function"],
6820
+ arrowkey_RIGHT=self.arrowkey_RIGHT,
6821
+ arrowkey_LEFT=self.arrowkey_LEFT,
6822
+ align="w", # self.get_cell_align(r, c)
6823
+ )
6824
+ self.dropdown.canvas_id = self.create_window(
6825
+ (self.col_positions[c], ypos),
6826
+ window=self.dropdown.window,
6827
+ anchor=anchor,
6828
+ )
6829
+ if kwargs["state"] == "normal":
6830
+ self.text_editor.tktext.bind(
6832
6831
  "<<TextModified>>",
6833
- lambda x: window.search_and_see(
6832
+ lambda x: self.dropdown.window.search_and_see(
6834
6833
  event_dict(
6835
6834
  name="table_dropdown_modified",
6836
6835
  sheet=self.PAR.name,
6837
6836
  value=self.text_editor.get(),
6838
6837
  loc=(r, c),
6839
6838
  boxes=self.get_boxes(),
6840
- selected=self.currently_selected(),
6839
+ selected=self.selected,
6841
6840
  )
6842
6841
  ),
6843
6842
  )
6844
6843
  if kwargs["modified_function"] is not None:
6845
- window.modified_function = kwargs["modified_function"]
6844
+ self.dropdown.window.modified_function = kwargs["modified_function"]
6846
6845
  self.update_idletasks()
6847
6846
  try:
6848
- self.after(1, lambda: self.text_editor.textedit.focus())
6849
- self.after(2, self.text_editor.scroll_to_bottom())
6847
+ self.after(1, lambda: self.text_editor.tktext.focus())
6848
+ self.after(2, self.text_editor.window.scroll_to_bottom())
6850
6849
  except Exception:
6851
6850
  return
6852
6851
  redraw = False
6853
6852
  else:
6854
- if anchor == "nw":
6855
- ypos = self.row_positions[r + 1]
6856
- else:
6857
- ypos = self.row_positions[r]
6858
- kwargs["canvas_id"] = self.create_window((self.col_positions[c], ypos), window=window, anchor=anchor)
6859
6853
  self.update_idletasks()
6860
- window.bind("<FocusOut>", lambda x: self.close_dropdown_window(r, c))
6861
- window.focus()
6854
+ self.dropdown.window.bind("<FocusOut>", lambda x: self.close_dropdown_window(r, c))
6855
+ self.dropdown.window.focus()
6862
6856
  redraw = True
6863
- self.existing_dropdown_window = window
6864
- kwargs["window"] = window
6865
- self.existing_dropdown_canvas_id = kwargs["canvas_id"]
6857
+ self.dropdown.open = True
6866
6858
  if redraw:
6867
6859
  self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=False)
6868
6860
 
@@ -6887,7 +6879,7 @@ class MainTable(tk.Canvas):
6887
6879
  value=selection,
6888
6880
  loc=(r, c),
6889
6881
  boxes=self.get_boxes(),
6890
- selected=self.currently_selected(),
6882
+ selected=self.selected,
6891
6883
  )
6892
6884
  if kwargs["select_function"] is not None:
6893
6885
  kwargs["select_function"](event_data)
@@ -6915,26 +6907,20 @@ class MainTable(tk.Canvas):
6915
6907
  try_binding(self.extra_end_edit_cell_func, event_data)
6916
6908
  self.focus_set()
6917
6909
  self.recreate_all_selection_boxes()
6918
- self.destroy_text_editor("Escape")
6919
- self.destroy_opened_dropdown_window(r, c)
6910
+ self.hide_text_editor_and_dropdown(redraw=redraw)
6911
+
6912
+ def hide_text_editor_and_dropdown(self, redraw: bool = True) -> None:
6913
+ self.hide_text_editor("Escape")
6914
+ self.hide_dropdown_window()
6920
6915
  if redraw:
6921
6916
  self.refresh()
6922
6917
 
6923
- def get_existing_dropdown_coords(self) -> tuple[int, int] | None:
6924
- if self.existing_dropdown_window is not None:
6925
- return int(self.existing_dropdown_window.r), int(self.existing_dropdown_window.c)
6926
- return None
6927
-
6928
- def mouseclick_outside_editor_or_dropdown(self) -> tuple:
6929
- closed_dd_coords = self.get_existing_dropdown_coords()
6930
- if self.text_editor_loc is not None and self.text_editor is not None:
6931
- self.close_text_editor(editor_info=self.text_editor_loc + ("ButtonPress-1",))
6932
- else:
6933
- self.destroy_text_editor("Escape")
6934
- if closed_dd_coords is not None:
6935
- self.destroy_opened_dropdown_window(
6936
- closed_dd_coords[0], closed_dd_coords[1]
6937
- ) # displayed coords not data, necessary for b1 function
6918
+ def mouseclick_outside_editor_or_dropdown(self) -> tuple[int, int] | None:
6919
+ closed_dd_coords = self.dropdown.get_coords()
6920
+ if self.text_editor.open:
6921
+ self.close_text_editor(editor_info=self.text_editor.coords + ("ButtonPress-1",))
6922
+ self.hide_dropdown_window()
6923
+ self.focus_set()
6938
6924
  return closed_dd_coords
6939
6925
 
6940
6926
  def mouseclick_outside_editor_or_dropdown_all_canvases(self):
@@ -6942,48 +6928,10 @@ class MainTable(tk.Canvas):
6942
6928
  self.RI.mouseclick_outside_editor_or_dropdown()
6943
6929
  return self.mouseclick_outside_editor_or_dropdown()
6944
6930
 
6945
- # function can receive 4 None args
6946
- def destroy_opened_dropdown_window(
6947
- self,
6948
- r: int | None = None,
6949
- c: int | None = None,
6950
- datarn: int | None = None,
6951
- datacn: int | None = None,
6952
- ):
6953
- if r is None and datarn is None and c is None and datacn is None and self.existing_dropdown_window is not None:
6954
- r, c = self.get_existing_dropdown_coords()
6955
- if c is not None or datacn is not None:
6956
- if datacn is None:
6957
- datacn_ = c if self.all_columns_displayed else self.displayed_columns[c]
6958
- else:
6959
- datacn_ = datacn
6960
- else:
6961
- datacn_ = None
6962
- if r is not None or datarn is not None:
6963
- if datarn is None:
6964
- datarn_ = r if self.all_rows_displayed else self.displayed_rows[r]
6965
- else:
6966
- datarn_ = datarn
6967
- else:
6968
- datarn_ = None
6969
- try:
6970
- self.delete(self.existing_dropdown_canvas_id)
6971
- except Exception:
6972
- pass
6973
- self.existing_dropdown_canvas_id = None
6974
- try:
6975
- self.existing_dropdown_window.destroy()
6976
- except Exception:
6977
- pass
6978
- kwargs = self.get_cell_kwargs(datarn_, datacn_, key="dropdown")
6979
- if kwargs:
6980
- kwargs["canvas_id"] = "no dropdown open"
6981
- kwargs["window"] = "no dropdown open"
6982
- try:
6983
- self.delete(kwargs["canvas_id"])
6984
- except Exception:
6985
- pass
6986
- self.existing_dropdown_window = None
6931
+ def hide_dropdown_window(self) -> None:
6932
+ if self.dropdown.open:
6933
+ self.itemconfig(self.dropdown.canvas_id, state="hidden")
6934
+ self.dropdown.open = False
6987
6935
 
6988
6936
  def click_checkbox(
6989
6937
  self,
@@ -7018,7 +6966,7 @@ class MainTable(tk.Canvas):
7018
6966
  value=value,
7019
6967
  loc=(r, c),
7020
6968
  boxes=self.get_boxes(),
7021
- selected=self.currently_selected(),
6969
+ selected=self.selected,
7022
6970
  )
7023
6971
  if kwargs["check_function"] is not None:
7024
6972
  kwargs["check_function"](event_data)
@@ -7048,7 +6996,7 @@ class MainTable(tk.Canvas):
7048
6996
  sheet=self.PAR.name,
7049
6997
  cells_table={(datarn, datacn): self.get_cell_data(datarn, datacn)},
7050
6998
  boxes=self.get_boxes(),
7051
- selected=self.currently_selected(),
6999
+ selected=self.selected,
7052
7000
  )
7053
7001
  if not check_input_valid or self.input_valid_for_cell(datarn, datacn, value):
7054
7002
  if self.undo_enabled and undo:
@@ -7267,11 +7215,11 @@ class MainTable(tk.Canvas):
7267
7215
  return True
7268
7216
  if self.cell_equal_to(datarn, datacn, value, ignore_empty=ignore_empty):
7269
7217
  return False
7270
- if self.get_cell_kwargs(datarn, datacn, key="checkbox"):
7271
- return is_bool_like(value)
7272
7218
  kwargs = self.get_cell_kwargs(datarn, datacn, key="dropdown")
7273
7219
  if kwargs and kwargs["validate_input"] and value not in kwargs["values"]:
7274
7220
  return False
7221
+ if self.get_cell_kwargs(datarn, datacn, key="checkbox"):
7222
+ return is_bool_like(value)
7275
7223
  return True
7276
7224
 
7277
7225
  def cell_equal_to(self, datarn: int, datacn: int, value: object, ignore_empty: bool = False, **kwargs) -> bool: