tksheet 7.0.5__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,10 +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,
81
+ FontTuple,
82
+ Selected,
83
+ SelectionBox,
84
+ TextEditorStorage,
82
85
  )
83
86
  from .text_editor import (
84
87
  TextEditor,
@@ -103,39 +106,40 @@ class MainTable(tk.Canvas):
103
106
  self.PAR = kwargs["parent"]
104
107
  self.PAR_width = 0
105
108
  self.PAR_height = 0
109
+ self.scrollregion = tuple()
106
110
  self.current_cursor = ""
107
111
  self.b1_pressed_loc = None
108
- self.existing_dropdown_canvas_id = None
109
- self.existing_dropdown_window = None
110
112
  self.closed_dropdown = None
111
- self.last_selected = None
112
113
  self.centre_alignment_text_mod_indexes = (slice(1, None), slice(None, -1))
113
114
  self.c_align_cyc = cycle(self.centre_alignment_text_mod_indexes)
114
115
  self.allow_auto_resize_columns = True
115
116
  self.allow_auto_resize_rows = True
116
117
  self.span = self.PAR.span
117
118
  self.synced_scrolls = set()
119
+ self.dropdown = DropdownStorage()
120
+ self.text_editor = TextEditorStorage()
118
121
 
119
122
  self.disp_ctrl_outline = {}
120
123
  self.disp_text = {}
121
124
  self.disp_high = {}
122
125
  self.disp_grid = {}
123
- self.disp_fill_sels = {}
124
- self.disp_bord_sels = {}
125
126
  self.disp_resize_lines = {}
126
127
  self.disp_dropdown = {}
127
128
  self.disp_checkbox = {}
129
+ self.disp_boxes = set()
128
130
  self.hidd_ctrl_outline = {}
129
131
  self.hidd_text = {}
130
132
  self.hidd_high = {}
131
133
  self.hidd_grid = {}
132
- self.hidd_fill_sels = {}
133
- self.hidd_bord_sels = {}
134
134
  self.hidd_resize_lines = {}
135
135
  self.hidd_dropdown = {}
136
136
  self.hidd_checkbox = {}
137
+ self.hidd_boxes = set()
137
138
 
139
+ self.selection_boxes = {}
140
+ self.selected = tuple()
138
141
  self.named_spans = {}
142
+ self.reset_tags()
139
143
  self.cell_options = {}
140
144
  self.col_options = {}
141
145
  self.row_options = {}
@@ -224,7 +228,6 @@ class MainTable(tk.Canvas):
224
228
  self.rc_insert_row_enabled = False
225
229
  self.rc_popup_menus_enabled = False
226
230
  self.edit_cell_enabled = False
227
- self.text_editor_loc = None
228
231
  self.new_row_width = 0
229
232
  self.new_header_height = 0
230
233
  self.CH = kwargs["column_headers_canvas"]
@@ -258,42 +261,19 @@ class MainTable(tk.Canvas):
258
261
  for fnt in (self.PAR.ops.table_font, self.PAR.ops.index_font, self.PAR.ops.header_font):
259
262
  if fnt[1] < 1:
260
263
  fnt[1] = 1
261
- self.PAR.ops.table_font = tuple(self.PAR.ops.table_font)
262
- self.PAR.ops.index_font = tuple(self.PAR.ops.index_font)
263
- self.PAR.ops.header_font = tuple(self.PAR.ops.header_font)
264
+ self.PAR.ops.table_font = FontTuple(*self.PAR.ops.table_font)
265
+ self.PAR.ops.index_font = FontTuple(*self.PAR.ops.index_font)
266
+ self.PAR.ops.header_font = FontTuple(*self.PAR.ops.header_font)
264
267
 
265
268
  self.txt_measure_canvas = tk.Canvas(self)
266
269
  self.txt_measure_canvas_text = self.txt_measure_canvas.create_text(0, 0, text="", font=self.PAR.ops.table_font)
267
- self.text_editor = None
268
- self.text_editor_id = None
269
270
 
270
271
  self.max_row_height = float(kwargs["max_row_height"])
271
272
  self.max_index_width = float(kwargs["max_index_width"])
272
273
  self.max_column_width = float(kwargs["max_column_width"])
273
274
  self.max_header_height = float(kwargs["max_header_height"])
274
- if kwargs["default_row_index_width"] is None:
275
- self.RI.set_width(70)
276
- self.default_row_index_width = 70
277
- else:
278
- self.RI.set_width(kwargs["default_row_index_width"])
279
- self.default_row_index_width = kwargs["default_row_index_width"]
280
- self.default_header_height = (
281
- kwargs["default_header_height"] if isinstance(kwargs["default_header_height"], str) else "pixels",
282
- (
283
- kwargs["default_header_height"]
284
- if isinstance(kwargs["default_header_height"], int)
285
- else self.get_lines_cell_height(int(kwargs["default_header_height"]), font=self.PAR.ops.header_font)
286
- ),
287
- )
288
- self.default_column_width = kwargs["default_column_width"]
289
- self.default_row_height = (
290
- kwargs["default_row_height"] if isinstance(kwargs["default_row_height"], str) else "pixels",
291
- (
292
- kwargs["default_row_height"]
293
- if isinstance(kwargs["default_row_height"], int)
294
- else self.get_lines_cell_height(int(kwargs["default_row_height"]))
295
- ),
296
- )
275
+
276
+ self.RI.set_width(self.PAR.ops.default_row_index_width)
297
277
  self.set_table_font_help()
298
278
  self.set_header_font_help()
299
279
  self.set_index_font_help()
@@ -326,6 +306,8 @@ class MainTable(tk.Canvas):
326
306
  self._row_index = _row_index
327
307
  else:
328
308
  self._row_index = []
309
+ self.saved_row_heights = {}
310
+ self.saved_column_widths = {}
329
311
  self.displayed_columns = []
330
312
  self.displayed_rows = []
331
313
  self.set_col_positions(itr=[])
@@ -424,6 +406,11 @@ class MainTable(tk.Canvas):
424
406
  for canvas in (self, self.RI, self.CH):
425
407
  canvas.unbind(b[0])
426
408
 
409
+ def reset_tags(self) -> None:
410
+ self.tagged_cells = {}
411
+ self.tagged_rows = {}
412
+ self.tagged_columns = {}
413
+
427
414
  def show_ctrl_outline(
428
415
  self,
429
416
  canvas: Literal["table"] = "table",
@@ -498,20 +485,17 @@ class MainTable(tk.Canvas):
498
485
  self.hidd_ctrl_outline[t] = False
499
486
 
500
487
  def get_ctrl_x_c_boxes(self) -> tuple[dict[tuple[int, int, int, int], str], int]:
501
- currently_selected = self.currently_selected()
502
488
  boxes = {}
503
489
  maxrows = 0
504
- if currently_selected.type_ in ("cell", "column"):
505
- 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
506
492
  maxrows = curr_box[2] - curr_box[0]
507
- for item in self.get_selection_items(rows=False, current=False):
508
- tags = self.gettags(item)
509
- box = coords_tag_to_box_nt(tags[1])
510
- if maxrows >= box[2] - box[0]:
511
- 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_
512
496
  else:
513
- for item in self.get_selection_items(columns=False, cells=False, current=False):
514
- 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"
515
499
  return boxes, maxrows
516
500
 
517
501
  def io_csv_writer(self) -> tuple[io.StringIO, csv.writer]:
@@ -526,12 +510,11 @@ class MainTable(tk.Canvas):
526
510
  return s, writer
527
511
 
528
512
  def ctrl_c(self, event=None) -> None:
529
- if not self.anything_selected():
513
+ if not self.selected:
530
514
  return
531
- currently_selected = self.currently_selected()
532
515
  event_data = event_dict(
533
516
  sheet=self.PAR.name,
534
- selected=currently_selected,
517
+ selected=self.selected,
535
518
  )
536
519
  event_data["eventname"] = "begin_ctrl_c"
537
520
  boxes, maxrows = self.get_ctrl_x_c_boxes()
@@ -539,7 +522,7 @@ class MainTable(tk.Canvas):
539
522
  s, writer = self.io_csv_writer()
540
523
  if not try_binding(self.extra_begin_ctrl_c_func, event_data):
541
524
  return
542
- if currently_selected.type_ in ("cell", "column"):
525
+ if self.selected.type_ in ("cells", "columns"):
543
526
  for rn in range(maxrows):
544
527
  row = []
545
528
  for r1, c1, r2, c2 in boxes:
@@ -569,20 +552,19 @@ class MainTable(tk.Canvas):
569
552
  try_binding(self.extra_end_ctrl_c_func, event_data, "end_ctrl_c")
570
553
 
571
554
  def ctrl_x(self, event=None) -> None:
572
- if not self.anything_selected():
555
+ if not self.selected:
573
556
  return
574
- currently_selected = self.currently_selected()
575
557
  event_data = event_dict(
576
558
  name="edit_table",
577
559
  sheet=self.PAR.name,
578
- selected=currently_selected,
560
+ selected=self.selected,
579
561
  )
580
562
  boxes, maxrows = self.get_ctrl_x_c_boxes()
581
563
  event_data["selection_boxes"] = boxes
582
564
  s, writer = self.io_csv_writer()
583
565
  if not try_binding(self.extra_begin_ctrl_x_func, event_data, "begin_ctrl_x"):
584
566
  return
585
- if currently_selected.type_ in ("cell", "column"):
567
+ if self.selected.type_ in ("cells", "columns"):
586
568
  for rn in range(maxrows):
587
569
  row = []
588
570
  for r1, c1, r2, c2 in boxes:
@@ -638,25 +620,20 @@ class MainTable(tk.Canvas):
638
620
  try_binding(self.extra_end_ctrl_x_func, event_data, "end_ctrl_x")
639
621
  self.sheet_modified(event_data)
640
622
 
641
- def get_box_containing_current(self) -> tuple[int, int, int, int]:
642
- item = self.get_selection_items(cells=False, rows=False, columns=False)[-1]
643
- return coords_tag_to_box_nt(self.gettags(item)[1])
644
-
645
623
  def ctrl_v(self, event: object = None) -> None:
646
624
  if not self.PAR.ops.expand_sheet_if_paste_too_big and (
647
625
  len(self.col_positions) == 1 or len(self.row_positions) == 1
648
626
  ):
649
627
  return
650
- currently_selected = self.currently_selected()
651
628
  event_data = event_dict(
652
629
  name="edit_table",
653
630
  sheet=self.PAR.name,
654
- selected=currently_selected,
631
+ selected=self.selected,
655
632
  )
656
- if currently_selected:
657
- selected_r = currently_selected[0]
658
- selected_c = currently_selected[1]
659
- 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:
660
637
  return
661
638
  else:
662
639
  if not self.data:
@@ -689,7 +666,7 @@ class MainTable(tk.Canvas):
689
666
  lastbox_c1,
690
667
  lastbox_r2,
691
668
  lastbox_c2,
692
- ) = self.get_box_containing_current()
669
+ ) = self.selection_boxes[self.selected.fill_iid].coords
693
670
  lastbox_numrows = lastbox_r2 - lastbox_r1
694
671
  lastbox_numcols = lastbox_c2 - lastbox_c1
695
672
  if lastbox_numrows > new_data_numrows and not lastbox_numrows % new_data_numrows:
@@ -870,13 +847,12 @@ class MainTable(tk.Canvas):
870
847
  self.sheet_modified(event_data)
871
848
 
872
849
  def delete_key(self, event: object = None) -> None:
873
- if not self.anything_selected():
850
+ if not self.selected:
874
851
  return
875
- currently_selected = self.currently_selected()
876
852
  event_data = event_dict(
877
853
  name="edit_table",
878
854
  sheet=self.PAR.name,
879
- selected=currently_selected,
855
+ selected=self.selected,
880
856
  )
881
857
  boxes = self.get_boxes()
882
858
  event_data["selection_boxes"] = boxes
@@ -948,6 +924,7 @@ class MainTable(tk.Canvas):
948
924
  data_indexes: bool = False,
949
925
  event_data: EventDataDict | None = None,
950
926
  ) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
927
+ self.saved_column_widths = {}
951
928
  if not isinstance(totalcols, int):
952
929
  totalcols = max(data_new_idxs.values(), default=0)
953
930
  if totalcols:
@@ -958,7 +935,7 @@ class MainTable(tk.Canvas):
958
935
  name="move_columns",
959
936
  sheet=self.PAR.name,
960
937
  boxes=self.get_boxes(),
961
- selected=self.currently_selected(),
938
+ selected=self.selected,
962
939
  )
963
940
  event_data["moved"]["columns"] = {
964
941
  "data": data_new_idxs,
@@ -1010,13 +987,19 @@ class MainTable(tk.Canvas):
1010
987
  old_idxs=data_old_idxs,
1011
988
  )
1012
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
+ }
1013
993
  self.cell_options = {(k[0], full_new_idxs[k[1]]): v for k, v in self.cell_options.items()}
1014
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
+ }
1015
998
  self.CH.cell_options = {full_new_idxs[k]: v for k, v in self.CH.cell_options.items()}
1016
999
  totalrows = self.total_data_rows()
1017
1000
  new_ops = self.PAR.create_options_from_span
1018
1001
  qkspan = self.span()
1019
- for name, span in self.named_spans.items():
1002
+ for span in self.named_spans.values():
1020
1003
  # span is neither a cell options nor col options span, continue
1021
1004
  if not isinstance(span["from_c"], int):
1022
1005
  continue
@@ -1178,6 +1161,7 @@ class MainTable(tk.Canvas):
1178
1161
  data_indexes: bool = False,
1179
1162
  event_data: EventDataDict | None = None,
1180
1163
  ) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
1164
+ self.saved_row_heights = {}
1181
1165
  if not isinstance(totalrows, int):
1182
1166
  totalrows = self.fix_data_len(max(data_new_idxs.values(), default=0))
1183
1167
  if event_data is None:
@@ -1185,7 +1169,7 @@ class MainTable(tk.Canvas):
1185
1169
  name="move_rows",
1186
1170
  sheet=self.PAR.name,
1187
1171
  boxes=self.get_boxes(),
1188
- selected=self.currently_selected(),
1172
+ selected=self.selected,
1189
1173
  )
1190
1174
  event_data["moved"]["rows"] = {
1191
1175
  "data": data_new_idxs,
@@ -1234,13 +1218,18 @@ class MainTable(tk.Canvas):
1234
1218
  old_idxs=data_old_idxs,
1235
1219
  )
1236
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
+ }
1237
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()}
1238
1226
  self.row_options = {full_new_idxs[k]: v for k, v in self.row_options.items()}
1239
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()}
1240
1229
  totalcols = self.total_data_cols()
1241
1230
  new_ops = self.PAR.create_options_from_span
1242
1231
  qkspan = self.span()
1243
- for name, span in self.named_spans.items():
1232
+ for span in self.named_spans.values():
1244
1233
  # span is neither a cell options nor row options span, continue
1245
1234
  if not isinstance(span["from_r"], int):
1246
1235
  continue
@@ -1456,7 +1445,6 @@ class MainTable(tk.Canvas):
1456
1445
  event_data["selection_boxes"] = modification["selection_boxes"]
1457
1446
  event_data["selected"] = modification["selected"]
1458
1447
  saved_cells = False
1459
- curr = tuple()
1460
1448
 
1461
1449
  if modification["added"]["rows"] or modification["added"]["columns"]:
1462
1450
  event_data = self.save_cells_using_modification(modification, event_data)
@@ -1488,7 +1476,6 @@ class MainTable(tk.Canvas):
1488
1476
  "displayed": disp_new_idxs,
1489
1477
  }
1490
1478
  self.restore_options_named_spans(modification)
1491
- curr = self.currently_selected()
1492
1479
 
1493
1480
  if modification["moved"]["rows"]:
1494
1481
  totalrows = self.total_data_rows()
@@ -1516,7 +1503,6 @@ class MainTable(tk.Canvas):
1516
1503
  "displayed": disp_new_idxs,
1517
1504
  }
1518
1505
  self.restore_options_named_spans(modification)
1519
- curr = self.currently_selected()
1520
1506
 
1521
1507
  if modification["added"]["rows"]:
1522
1508
  self.deselect("all", run_binding=False, redraw=False)
@@ -1534,7 +1520,6 @@ class MainTable(tk.Canvas):
1534
1520
  modification["selection_boxes"],
1535
1521
  modification["selected"],
1536
1522
  )
1537
- curr = self.currently_selected()
1538
1523
 
1539
1524
  if modification["added"]["columns"]:
1540
1525
  self.deselect("all", run_binding=False, redraw=False)
@@ -1552,7 +1537,6 @@ class MainTable(tk.Canvas):
1552
1537
  modification["selection_boxes"],
1553
1538
  modification["selected"],
1554
1539
  )
1555
- curr = self.currently_selected()
1556
1540
 
1557
1541
  if modification["deleted"]["rows"]:
1558
1542
  self.add_rows(
@@ -1587,7 +1571,6 @@ class MainTable(tk.Canvas):
1587
1571
  modification["selection_boxes"],
1588
1572
  modification["selected"],
1589
1573
  )
1590
- curr = self.currently_selected()
1591
1574
 
1592
1575
  if modification["eventname"].startswith(("edit", "move")):
1593
1576
  if not saved_cells:
@@ -1602,7 +1585,6 @@ class MainTable(tk.Canvas):
1602
1585
  modification["selection_boxes"],
1603
1586
  modification["selected"],
1604
1587
  )
1605
- curr = self.currently_selected()
1606
1588
 
1607
1589
  elif modification["eventname"].startswith("add"):
1608
1590
  event_data["eventname"] = modification["eventname"].replace("add", "delete")
@@ -1610,10 +1592,10 @@ class MainTable(tk.Canvas):
1610
1592
  elif modification["eventname"].startswith("delete"):
1611
1593
  event_data["eventname"] = modification["eventname"].replace("delete", "add")
1612
1594
 
1613
- if curr:
1595
+ if self.selected:
1614
1596
  self.see(
1615
- r=curr.row,
1616
- c=curr.column,
1597
+ r=self.selected.row,
1598
+ c=self.selected.column,
1617
1599
  keep_yscroll=False,
1618
1600
  keep_xscroll=False,
1619
1601
  bottom_right_corner=False,
@@ -1727,7 +1709,7 @@ class MainTable(tk.Canvas):
1727
1709
  return False
1728
1710
 
1729
1711
  def select_all(self, redraw: bool = True, run_binding_func: bool = True) -> None:
1730
- currently_selected = self.currently_selected()
1712
+ iid, r, c = self.selected.iid, self.selected.row, self.selected.column
1731
1713
  self.deselect("all", redraw=False)
1732
1714
  if len(self.row_positions) > 1 and len(self.col_positions) > 1:
1733
1715
  item = self.create_selection_box(
@@ -1737,16 +1719,18 @@ class MainTable(tk.Canvas):
1737
1719
  len(self.col_positions) - 1,
1738
1720
  set_current=False,
1739
1721
  )
1740
- if currently_selected:
1741
- self.set_currently_selected(currently_selected.row, currently_selected.column, item=item)
1722
+ if iid:
1723
+ self.set_currently_selected(r, c, item=item)
1742
1724
  else:
1743
1725
  self.set_currently_selected(0, 0, item=item)
1744
1726
  if redraw:
1745
1727
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
1746
- if self.select_all_binding_func and run_binding_func:
1747
- self.select_all_binding_func(
1748
- self.get_select_event(being_drawn_item=self.being_drawn_item),
1749
- )
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))
1750
1734
 
1751
1735
  def select_cell(
1752
1736
  self,
@@ -1786,7 +1770,7 @@ class MainTable(tk.Canvas):
1786
1770
  redraw: bool = True,
1787
1771
  run_binding_func: bool = True,
1788
1772
  set_as_current: bool = True,
1789
- ) -> int:
1773
+ ) -> int | None:
1790
1774
  if add_selection:
1791
1775
  if self.cell_selected(row, column, inc_rows=True, inc_cols=True):
1792
1776
  fill_iid = self.deselect(r=row, c=column, redraw=redraw)
@@ -1805,12 +1789,12 @@ class MainTable(tk.Canvas):
1805
1789
  fill_iid = self.select_cell(row, column, redraw=redraw)
1806
1790
  return fill_iid
1807
1791
 
1808
- def get_select_event(self, being_drawn_item: None | int) -> EventDataDict:
1792
+ def get_select_event(self, being_drawn_item: None | int = None) -> EventDataDict:
1809
1793
  return event_dict(
1810
1794
  name="select",
1811
1795
  sheet=self.PAR.name,
1812
- selected=self.currently_selected(),
1813
- being_selected=self.get_box_from_item(being_drawn_item),
1796
+ selected=self.selected,
1797
+ being_selected=self.coords_and_type(being_drawn_item),
1814
1798
  boxes=self.get_boxes(),
1815
1799
  )
1816
1800
 
@@ -1822,31 +1806,25 @@ class MainTable(tk.Canvas):
1822
1806
  redraw: bool = True,
1823
1807
  run_binding: bool = True,
1824
1808
  ) -> None:
1825
- if not self.anything_selected():
1809
+ if not self.selected:
1826
1810
  return
1827
- # saved_current = self.currently_selected()
1828
- set_curr = False
1829
- current = self.currently_selected().tags
1830
1811
  if r == "all" or (r is None and c is None and cell is None):
1831
- for item in self.get_selection_items(current=False):
1832
- self.delete_item(item)
1812
+ for item, box in self.get_selection_items():
1813
+ self.hide_selection_box(item)
1833
1814
  elif r in ("allrows", "allcols"):
1834
- for item in self.get_selection_items(
1835
- 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,
1836
1819
  ):
1837
- tags = self.gettags(item)
1838
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
1839
- self.delete_item(item)
1840
- if current[2] == tags[2]:
1841
- set_curr = True
1820
+ self.hide_selection_box(item)
1842
1821
  elif r is not None and c is None and cell is None:
1843
- for item in self.get_selection_items(columns=False, cells=False, current=False):
1844
- tags = self.gettags(item)
1845
- 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
1846
1824
  if r >= r1 and r < r2:
1847
- self.delete_item(item)
1848
- if current[2] == tags[2]:
1849
- set_curr = True
1825
+ resel = self.selected.fill_iid == item
1826
+ to_sel = self.selected.row
1827
+ self.hide_selection_box(item)
1850
1828
  if r2 - r1 != 1:
1851
1829
  if r == r1:
1852
1830
  self.create_selection_box(
@@ -1855,7 +1833,7 @@ class MainTable(tk.Canvas):
1855
1833
  r2,
1856
1834
  len(self.col_positions) - 1,
1857
1835
  "rows",
1858
- set_current=False,
1836
+ set_current=resel,
1859
1837
  )
1860
1838
  elif r == r2 - 1:
1861
1839
  self.create_selection_box(
@@ -1864,7 +1842,7 @@ class MainTable(tk.Canvas):
1864
1842
  r2 - 1,
1865
1843
  len(self.col_positions) - 1,
1866
1844
  "rows",
1867
- set_current=False,
1845
+ set_current=resel,
1868
1846
  )
1869
1847
  else:
1870
1848
  self.create_selection_box(
@@ -1873,7 +1851,7 @@ class MainTable(tk.Canvas):
1873
1851
  r,
1874
1852
  len(self.col_positions) - 1,
1875
1853
  "rows",
1876
- set_current=False,
1854
+ set_current=resel and to_sel >= r1 and to_sel < r,
1877
1855
  )
1878
1856
  self.create_selection_box(
1879
1857
  r + 1,
@@ -1881,17 +1859,16 @@ class MainTable(tk.Canvas):
1881
1859
  r2,
1882
1860
  len(self.col_positions) - 1,
1883
1861
  "rows",
1884
- set_current=False,
1862
+ set_current=resel and to_sel >= r + 1 and to_sel < r2,
1885
1863
  )
1886
1864
  break
1887
1865
  elif c is not None and r is None and cell is None:
1888
- for item in self.get_selection_items(rows=False, cells=False, current=False):
1889
- tags = self.gettags(item)
1890
- 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
1891
1868
  if c >= c1 and c < c2:
1892
- self.delete_item(item)
1893
- if current[2] == tags[2]:
1894
- set_curr = True
1869
+ resel = self.selected.fill_iid == item
1870
+ to_sel = self.selected.column
1871
+ self.hide_selection_box(item)
1895
1872
  if c2 - c1 != 1:
1896
1873
  if c == c1:
1897
1874
  self.create_selection_box(
@@ -1900,7 +1877,7 @@ class MainTable(tk.Canvas):
1900
1877
  len(self.row_positions) - 1,
1901
1878
  c2,
1902
1879
  "columns",
1903
- set_current=False,
1880
+ set_current=resel,
1904
1881
  )
1905
1882
  elif c == c2 - 1:
1906
1883
  self.create_selection_box(
@@ -1909,7 +1886,7 @@ class MainTable(tk.Canvas):
1909
1886
  len(self.row_positions) - 1,
1910
1887
  c2 - 1,
1911
1888
  "columns",
1912
- set_current=False,
1889
+ set_current=resel,
1913
1890
  )
1914
1891
  else:
1915
1892
  self.create_selection_box(
@@ -1918,7 +1895,7 @@ class MainTable(tk.Canvas):
1918
1895
  len(self.row_positions) - 1,
1919
1896
  c,
1920
1897
  "columns",
1921
- set_current=False,
1898
+ set_current=resel and to_sel >= c1 and to_sel < c,
1922
1899
  )
1923
1900
  self.create_selection_box(
1924
1901
  0,
@@ -1926,29 +1903,23 @@ class MainTable(tk.Canvas):
1926
1903
  len(self.row_positions) - 1,
1927
1904
  c2,
1928
1905
  "columns",
1929
- set_current=False,
1906
+ set_current=resel and to_sel >= c + 1 and to_sel < c2,
1930
1907
  )
1931
1908
  break
1932
1909
  elif (r is not None and c is not None and cell is None) or cell is not None:
1933
1910
  if cell is not None:
1934
1911
  r, c = cell[0], cell[1]
1935
- for item in self.get_selection_items(current=False, reverse=True):
1936
- tags = self.gettags(item)
1937
- 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
1938
1914
  if r >= r1 and c >= c1 and r < r2 and c < c2:
1939
- self.delete_item(item)
1940
- if current[2] == tags[2]:
1941
- set_curr = True
1915
+ self.hide_selection_box(item)
1942
1916
  break
1943
- if set_curr:
1944
- self.set_current_to_last()
1945
1917
  if redraw:
1946
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)
1947
1920
  if run_binding:
1948
- try_binding(
1949
- self.deselection_binding_func,
1950
- self.get_select_event(being_drawn_item=self.being_drawn_item),
1951
- )
1921
+ try_binding(self.deselection_binding_func, sel_event)
1922
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
1952
1923
 
1953
1924
  def page_UP(self, event=None):
1954
1925
  height = self.winfo_height()
@@ -1958,8 +1929,7 @@ class MainTable(tk.Canvas):
1958
1929
  scrollto = 0
1959
1930
  if self.PAR.ops.page_up_down_select_row:
1960
1931
  r = bisect_left(self.row_positions, scrollto)
1961
- current = self.currently_selected()
1962
- if current and current[0] == r:
1932
+ if self.selected and self.selected.row == r:
1963
1933
  r -= 1
1964
1934
  if r < 0:
1965
1935
  r = 0
@@ -1986,8 +1956,7 @@ class MainTable(tk.Canvas):
1986
1956
  scrollto = top + height
1987
1957
  if self.PAR.ops.page_up_down_select_row and self.RI.row_selection_enabled:
1988
1958
  r = bisect_left(self.row_positions, scrollto) - 1
1989
- current = self.currently_selected()
1990
- if current and current[0] == r:
1959
+ if self.selected and self.selected.row == r:
1991
1960
  r += 1
1992
1961
  if r > len(self.row_positions) - 2:
1993
1962
  r = len(self.row_positions) - 2
@@ -2012,20 +1981,19 @@ class MainTable(tk.Canvas):
2012
1981
  self.main_table_redraw_grid_and_text(redraw_row_index=True)
2013
1982
 
2014
1983
  def arrowkey_UP(self, event=None):
2015
- currently_selected = self.currently_selected()
2016
- if not currently_selected:
1984
+ if not self.selected:
2017
1985
  return
2018
- if currently_selected.type_ == "row":
2019
- r = currently_selected.row
1986
+ if self.selected.type_ == "rows":
1987
+ r = self.selected.row
2020
1988
  if r != 0 and self.RI.row_selection_enabled:
2021
1989
  if self.cell_completely_visible(r=r - 1, c=0):
2022
1990
  self.RI.select_row(r - 1, redraw=True)
2023
1991
  else:
2024
1992
  self.RI.select_row(r - 1)
2025
1993
  self.see(r - 1, 0, keep_xscroll=True, check_cell_visibility=False)
2026
- elif currently_selected.type_ in ("cell", "column"):
2027
- r = currently_selected[0]
2028
- c = currently_selected[1]
1994
+ elif self.selected.type_ in ("cells", "columns"):
1995
+ r = self.selected.row
1996
+ c = self.selected.column
2029
1997
  if r == 0 and self.CH.col_selection_enabled:
2030
1998
  if not self.cell_completely_visible(r=r, c=0):
2031
1999
  self.see(r, c, keep_xscroll=True, check_cell_visibility=False)
@@ -2037,11 +2005,10 @@ class MainTable(tk.Canvas):
2037
2005
  self.see(r - 1, c, keep_xscroll=True, check_cell_visibility=False)
2038
2006
 
2039
2007
  def arrowkey_RIGHT(self, event=None):
2040
- currently_selected = self.currently_selected()
2041
- if not currently_selected:
2008
+ if not self.selected:
2042
2009
  return
2043
- if currently_selected.type_ == "row":
2044
- r = currently_selected.row
2010
+ if self.selected.type_ == "rows":
2011
+ r = self.selected.row
2045
2012
  if self.single_selection_enabled or self.toggle_selection_enabled:
2046
2013
  if self.cell_completely_visible(r=r, c=0):
2047
2014
  self.select_cell(r, 0, redraw=True)
@@ -2054,8 +2021,8 @@ class MainTable(tk.Canvas):
2054
2021
  bottom_right_corner=True,
2055
2022
  check_cell_visibility=False,
2056
2023
  )
2057
- elif currently_selected.type_ == "column":
2058
- c = currently_selected.column
2024
+ elif self.selected.type_ == "columns":
2025
+ c = self.selected.column
2059
2026
  if c < len(self.col_positions) - 2 and self.CH.col_selection_enabled:
2060
2027
  if self.cell_completely_visible(r=0, c=c + 1):
2061
2028
  self.CH.select_col(c + 1, redraw=True)
@@ -2069,8 +2036,8 @@ class MainTable(tk.Canvas):
2069
2036
  check_cell_visibility=False,
2070
2037
  )
2071
2038
  else:
2072
- r = currently_selected[0]
2073
- c = currently_selected[1]
2039
+ r = self.selected.row
2040
+ c = self.selected.column
2074
2041
  if c < len(self.col_positions) - 2 and (self.single_selection_enabled or self.toggle_selection_enabled):
2075
2042
  if self.cell_completely_visible(r=r, c=c + 1):
2076
2043
  self.select_cell(r, c + 1, redraw=True)
@@ -2085,11 +2052,10 @@ class MainTable(tk.Canvas):
2085
2052
  )
2086
2053
 
2087
2054
  def arrowkey_DOWN(self, event=None):
2088
- currently_selected = self.currently_selected()
2089
- if not currently_selected:
2055
+ if not self.selected:
2090
2056
  return
2091
- if currently_selected.type_ == "row":
2092
- r = currently_selected.row
2057
+ if self.selected.type_ == "rows":
2058
+ r = self.selected.row
2093
2059
  if r < len(self.row_positions) - 2 and self.RI.row_selection_enabled:
2094
2060
  if self.cell_completely_visible(r=min(r + 2, len(self.row_positions) - 2), c=0):
2095
2061
  self.RI.select_row(r + 1, redraw=True)
@@ -2117,8 +2083,8 @@ class MainTable(tk.Canvas):
2117
2083
  bottom_right_corner=False if self.PAR.ops.arrow_key_down_right_scroll_page else True,
2118
2084
  check_cell_visibility=False,
2119
2085
  )
2120
- elif currently_selected.type_ == "column":
2121
- c = currently_selected.column
2086
+ elif self.selected.type_ == "columns":
2087
+ c = self.selected.column
2122
2088
  if self.single_selection_enabled or self.toggle_selection_enabled:
2123
2089
  if self.cell_completely_visible(r=0, c=c):
2124
2090
  self.select_cell(0, c, redraw=True)
@@ -2132,8 +2098,8 @@ class MainTable(tk.Canvas):
2132
2098
  check_cell_visibility=False,
2133
2099
  )
2134
2100
  else:
2135
- r = currently_selected[0]
2136
- c = currently_selected[1]
2101
+ r = self.selected.row
2102
+ c = self.selected.column
2137
2103
  if r < len(self.row_positions) - 2 and (self.single_selection_enabled or self.toggle_selection_enabled):
2138
2104
  if self.cell_completely_visible(r=min(r + 2, len(self.row_positions) - 2), c=c):
2139
2105
  self.select_cell(r + 1, c, redraw=True)
@@ -2163,11 +2129,10 @@ class MainTable(tk.Canvas):
2163
2129
  )
2164
2130
 
2165
2131
  def arrowkey_LEFT(self, event=None):
2166
- currently_selected = self.currently_selected()
2167
- if not currently_selected:
2132
+ if not self.selected:
2168
2133
  return
2169
- if currently_selected.type_ == "column":
2170
- c = currently_selected.column
2134
+ if self.selected.type_ == "columns":
2135
+ c = self.selected.column
2171
2136
  if c != 0 and self.CH.col_selection_enabled:
2172
2137
  if self.cell_completely_visible(r=0, c=c - 1):
2173
2138
  self.CH.select_col(c - 1, redraw=True)
@@ -2180,9 +2145,9 @@ class MainTable(tk.Canvas):
2180
2145
  bottom_right_corner=True,
2181
2146
  check_cell_visibility=False,
2182
2147
  )
2183
- elif currently_selected.type_ == "cell":
2184
- r = currently_selected.row
2185
- c = currently_selected.column
2148
+ elif self.selected.type_ == "cells":
2149
+ r = self.selected.row
2150
+ c = self.selected.column
2186
2151
  if c == 0 and self.RI.row_selection_enabled:
2187
2152
  if not self.cell_completely_visible(r=r, c=0):
2188
2153
  self.see(r, c, keep_yscroll=True, check_cell_visibility=False)
@@ -2846,19 +2811,13 @@ class MainTable(tk.Canvas):
2846
2811
  rowsel = int(self.identify_row(y=event.y))
2847
2812
  colsel = int(self.identify_col(x=event.x))
2848
2813
  if rowsel < len(self.row_positions) - 1 and colsel < len(self.col_positions) - 1:
2849
- if self.cell_selected(rowsel, colsel):
2850
- self.deselect(rowsel, colsel)
2851
- else:
2852
- self.being_drawn_item = True
2853
- self.being_drawn_item = self.add_selection(
2854
- rowsel, colsel, set_as_current=True, run_binding_func=False
2855
- )
2856
- if self.ctrl_selection_binding_func:
2857
- self.ctrl_selection_binding_func(
2858
- self.get_select_event(being_drawn_item=self.being_drawn_item),
2859
- )
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)
2860
2819
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True, redraw_table=True)
2861
-
2820
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
2862
2821
  elif not self.ctrl_select_enabled:
2863
2822
  self.b1_press(event)
2864
2823
 
@@ -2870,21 +2829,23 @@ class MainTable(tk.Canvas):
2870
2829
  rowsel = int(self.identify_row(y=event.y))
2871
2830
  colsel = int(self.identify_col(x=event.x))
2872
2831
  if rowsel < len(self.row_positions) - 1 and colsel < len(self.col_positions) - 1:
2873
- currently_selected = self.currently_selected()
2874
- if currently_selected:
2875
- self.delete_item(currently_selected.tags[2])
2876
- box = self.get_shift_select_box(currently_selected.row, rowsel, currently_selected.column, colsel)
2877
- if currently_selected and currently_selected.type_ == "cell":
2878
- 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
+ )
2879
2837
  else:
2880
2838
  self.being_drawn_item = self.add_selection(
2881
- rowsel, colsel, set_as_current=True, run_binding_func=False
2839
+ rowsel,
2840
+ colsel,
2841
+ set_as_current=True,
2842
+ run_binding_func=False,
2882
2843
  )
2883
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)
2884
2846
  if self.shift_selection_binding_func:
2885
- self.shift_selection_binding_func(
2886
- self.get_select_event(being_drawn_item=self.being_drawn_item),
2887
- )
2847
+ self.shift_selection_binding_func(sel_event)
2848
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
2888
2849
  elif not self.ctrl_select_enabled:
2889
2850
  self.shift_b1_press(event)
2890
2851
 
@@ -2896,28 +2857,35 @@ class MainTable(tk.Canvas):
2896
2857
  rowsel = int(self.identify_row(y=event.y))
2897
2858
  colsel = int(self.identify_col(x=event.x))
2898
2859
  if rowsel < len(self.row_positions) - 1 and colsel < len(self.col_positions) - 1:
2899
- currently_selected = self.currently_selected()
2900
- box = self.get_shift_select_box(currently_selected.row, rowsel, currently_selected.column, colsel)
2901
- 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
2902
2862
  self.deselect("all", redraw=False)
2903
- 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)
2904
2867
  else:
2905
- 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
+ )
2906
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)
2907
2876
  if self.shift_selection_binding_func:
2908
- self.shift_selection_binding_func(
2909
- self.get_select_event(being_drawn_item=self.being_drawn_item),
2910
- )
2877
+ self.shift_selection_binding_func(sel_event)
2878
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
2911
2879
 
2912
2880
  def get_shift_select_box(self, min_r: int, rowsel: int, min_c: int, colsel: int):
2913
2881
  if rowsel >= min_r and colsel >= min_c:
2914
- return min_r, min_c, rowsel + 1, colsel + 1, "cells"
2882
+ return min_r, min_c, rowsel + 1, colsel + 1
2915
2883
  elif rowsel >= min_r and min_c >= colsel:
2916
- return min_r, colsel, rowsel + 1, min_c + 1, "cells"
2884
+ return min_r, colsel, rowsel + 1, min_c + 1
2917
2885
  elif min_r >= rowsel and colsel >= min_c:
2918
- return rowsel, min_c, min_r + 1, colsel + 1, "cells"
2886
+ return rowsel, min_c, min_r + 1, colsel + 1
2919
2887
  elif min_r >= rowsel and min_c >= colsel:
2920
- return rowsel, colsel, min_r + 1, min_c + 1, "cells"
2888
+ return rowsel, colsel, min_r + 1, min_c + 1
2921
2889
 
2922
2890
  def get_b1_motion_box(self, start_row: int, start_col: int, end_row: int, end_col: int):
2923
2891
  if end_row >= start_row and end_col >= start_col and (end_row - start_row or end_col - start_col):
@@ -2944,17 +2912,16 @@ class MainTable(tk.Canvas):
2944
2912
  need_redraw = False
2945
2913
  end_row = self.identify_row(y=event.y)
2946
2914
  end_col = self.identify_col(x=event.x)
2947
- currently_selected = self.currently_selected()
2948
2915
  if (
2949
2916
  end_row < len(self.row_positions) - 1
2950
2917
  and end_col < len(self.col_positions) - 1
2951
- and currently_selected
2952
- and currently_selected.type_ == "cell"
2918
+ and self.selected
2919
+ and self.selected.type_ == "cells"
2953
2920
  ):
2954
2921
  box = self.get_b1_motion_box(
2955
2922
  *(
2956
- currently_selected.row,
2957
- currently_selected.column,
2923
+ self.selected.row,
2924
+ self.selected.column,
2958
2925
  end_row,
2959
2926
  end_col,
2960
2927
  )
@@ -2962,20 +2929,21 @@ class MainTable(tk.Canvas):
2962
2929
  if (
2963
2930
  box is not None
2964
2931
  and self.being_drawn_item is not None
2965
- and self.get_box_from_item(self.being_drawn_item) != box
2932
+ and self.coords_and_type(self.being_drawn_item) != box
2966
2933
  ):
2967
- self.deselect("all", redraw=False)
2968
2934
  if box[2] - box[0] != 1 or box[3] - box[1] != 1:
2969
- 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)
2970
2936
  else:
2971
2937
  self.being_drawn_item = self.select_cell(
2972
- currently_selected.row, currently_selected.column, run_binding_func=False
2938
+ box[0],
2939
+ box[1],
2940
+ run_binding_func=False,
2973
2941
  )
2974
2942
  need_redraw = True
2943
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
2975
2944
  if self.drag_selection_binding_func:
2976
- self.drag_selection_binding_func(
2977
- self.get_select_event(being_drawn_item=self.being_drawn_item),
2978
- )
2945
+ self.drag_selection_binding_func(sel_event)
2946
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
2979
2947
  if self.scroll_if_event_offscreen(event):
2980
2948
  need_redraw = True
2981
2949
  if need_redraw:
@@ -2988,17 +2956,16 @@ class MainTable(tk.Canvas):
2988
2956
  need_redraw = False
2989
2957
  end_row = self.identify_row(y=event.y)
2990
2958
  end_col = self.identify_col(x=event.x)
2991
- currently_selected = self.currently_selected()
2992
2959
  if (
2993
2960
  end_row < len(self.row_positions) - 1
2994
2961
  and end_col < len(self.col_positions) - 1
2995
- and currently_selected
2996
- and currently_selected.type_ == "cell"
2962
+ and self.selected
2963
+ and self.selected.type_ == "cells"
2997
2964
  ):
2998
2965
  box = self.get_b1_motion_box(
2999
2966
  *(
3000
- currently_selected.row,
3001
- currently_selected.column,
2967
+ self.selected.row,
2968
+ self.selected.column,
3002
2969
  end_row,
3003
2970
  end_col,
3004
2971
  )
@@ -3006,22 +2973,23 @@ class MainTable(tk.Canvas):
3006
2973
  if (
3007
2974
  box is not None
3008
2975
  and self.being_drawn_item is not None
3009
- and self.get_box_from_item(self.being_drawn_item) != box
2976
+ and self.coords_and_type(self.being_drawn_item) != box
3010
2977
  ):
3011
- self.delete_item(self.being_drawn_item)
3012
2978
  if box[2] - box[0] != 1 or box[3] - box[1] != 1:
3013
- 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)
3014
2980
  else:
2981
+ self.hide_selection_box(self.selected.fill_iid)
3015
2982
  self.being_drawn_item = self.add_selection(
3016
- currently_selected.row,
3017
- currently_selected.column,
2983
+ box[0],
2984
+ box[1],
2985
+ run_binding_func=False,
3018
2986
  set_as_current=True,
3019
2987
  )
3020
2988
  need_redraw = True
2989
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
3021
2990
  if self.drag_selection_binding_func:
3022
- self.drag_selection_binding_func(
3023
- self.get_select_event(being_drawn_item=self.being_drawn_item),
3024
- )
2991
+ self.drag_selection_binding_func(sel_event)
2992
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
3025
2993
  if self.scroll_if_event_offscreen(event):
3026
2994
  need_redraw = True
3027
2995
  if need_redraw:
@@ -3031,19 +2999,23 @@ class MainTable(tk.Canvas):
3031
2999
 
3032
3000
  def b1_release(self, event=None):
3033
3001
  if self.being_drawn_item is not None:
3034
- currently_selected = self.currently_selected()
3035
- to_sel = self.get_box_from_item(self.being_drawn_item)
3036
- 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)
3037
3005
  self.being_drawn_item = None
3038
- self.create_selection_box(
3039
- *to_sel,
3040
- state="hidden" if to_sel[2] - to_sel[0] == 1 and to_sel[3] - to_sel[1] == 1 else "normal",
3041
- 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
+ ),
3042
3014
  )
3015
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
3043
3016
  if self.drag_selection_binding_func:
3044
- self.drag_selection_binding_func(
3045
- self.get_select_event(being_drawn_item=self.being_drawn_item),
3046
- )
3017
+ self.drag_selection_binding_func(sel_event)
3018
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
3047
3019
  if self.RI.width_resizing_enabled and self.RI.rsz_w is not None and self.RI.currently_resizing_width:
3048
3020
  self.delete_resize_lines()
3049
3021
  self.RI.delete_resize_lines()
@@ -3298,6 +3270,8 @@ class MainTable(tk.Canvas):
3298
3270
  )
3299
3271
 
3300
3272
  def zoom_font(self, table_font: tuple, header_font: tuple):
3273
+ self.saved_column_widths = {}
3274
+ self.saved_row_heights = {}
3301
3275
  # should record position prior to change and then see after change
3302
3276
  y = self.canvasy(0)
3303
3277
  x = self.canvasx(0)
@@ -3312,7 +3286,7 @@ class MainTable(tk.Canvas):
3312
3286
  except Exception:
3313
3287
  c_pc = 0.0
3314
3288
  old_min_row_height = int(self.min_row_height)
3315
- old_default_row_height = int(self.default_row_height[1])
3289
+ old_default_row_height = int(self.get_default_row_height())
3316
3290
  self.set_table_font(
3317
3291
  table_font,
3318
3292
  reset_row_positions=False,
@@ -3323,6 +3297,7 @@ class MainTable(tk.Canvas):
3323
3297
  self.set_all_cell_sizes_to_text()
3324
3298
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
3325
3299
  elif not self.PAR.ops.set_cell_sizes_on_zoom:
3300
+ default_row_height = self.get_default_row_height()
3326
3301
  self.row_positions = list(
3327
3302
  accumulate(
3328
3303
  chain(
@@ -3332,7 +3307,7 @@ class MainTable(tk.Canvas):
3332
3307
  self.min_row_height
3333
3308
  if h == old_min_row_height
3334
3309
  else (
3335
- self.default_row_height[1]
3310
+ default_row_height
3336
3311
  if h == old_default_row_height
3337
3312
  else self.min_row_height if h < self.min_row_height else h
3338
3313
  )
@@ -3397,14 +3372,22 @@ class MainTable(tk.Canvas):
3397
3372
  self.min_column_width = 1
3398
3373
  if self.min_column_width > self.max_column_width:
3399
3374
  self.max_column_width = self.min_column_width + 20
3400
- if self.min_column_width > self.default_column_width:
3401
- self.default_column_width = self.min_column_width + 20
3402
3375
  if (
3403
3376
  isinstance(self.PAR.ops.auto_resize_columns, (int, float))
3404
3377
  and self.PAR.ops.auto_resize_columns < self.min_column_width
3405
3378
  ):
3406
3379
  self.PAR.ops.auto_resize_columns = self.min_column_width
3407
3380
 
3381
+ def get_default_row_height(self) -> int:
3382
+ if isinstance(self.PAR.ops.default_row_height, str):
3383
+ return self.get_lines_cell_height(int(self.PAR.ops.default_row_height))
3384
+ return self.PAR.ops.default_row_height
3385
+
3386
+ def get_default_header_height(self) -> int:
3387
+ if isinstance(self.PAR.ops.default_header_height, str):
3388
+ return self.get_lines_cell_height(int(self.PAR.ops.default_header_height), font=self.PAR.ops.header_font)
3389
+ return self.PAR.ops.default_header_height
3390
+
3408
3391
  def set_table_font(self, newfont: tuple | None = None, reset_row_positions: bool = False) -> tuple[str, int, str]:
3409
3392
  if newfont:
3410
3393
  if not isinstance(newfont, tuple):
@@ -3415,7 +3398,7 @@ class MainTable(tk.Canvas):
3415
3398
  raise ValueError(
3416
3399
  "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3417
3400
  )
3418
- self.PAR.ops.table_font = newfont
3401
+ self.PAR.ops.table_font = FontTuple(*newfont)
3419
3402
  self.set_table_font_help()
3420
3403
  if reset_row_positions:
3421
3404
  if isinstance(reset_row_positions, bool):
@@ -3436,15 +3419,6 @@ class MainTable(tk.Canvas):
3436
3419
  self.min_row_height = self.table_txt_height + 5
3437
3420
  if self.min_row_height < 12:
3438
3421
  self.min_row_height = 12
3439
- if self.default_row_height[0] != "pixels":
3440
- self.default_row_height = (
3441
- self.default_row_height[0] if self.default_row_height[0] != "pixels" else "pixels",
3442
- (
3443
- self.get_lines_cell_height(int(self.default_row_height[0]))
3444
- if self.default_row_height[0] != "pixels"
3445
- else self.default_row_height[1]
3446
- ),
3447
- )
3448
3422
  self.set_min_column_width()
3449
3423
 
3450
3424
  def set_header_font(self, newfont: tuple | None = None) -> tuple[str, int, str]:
@@ -3457,7 +3431,7 @@ class MainTable(tk.Canvas):
3457
3431
  raise ValueError(
3458
3432
  "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3459
3433
  )
3460
- self.PAR.ops.header_font = newfont
3434
+ self.PAR.ops.header_font = FontTuple(*newfont)
3461
3435
  self.set_header_font_help()
3462
3436
  self.recreate_all_selection_boxes()
3463
3437
  return self.PAR.ops.header_font
@@ -3471,17 +3445,13 @@ class MainTable(tk.Canvas):
3471
3445
  self.header_first_ln_ins = self.header_half_txt_height + 3
3472
3446
  self.header_xtra_lines_increment = self.header_txt_height
3473
3447
  self.min_header_height = self.header_txt_height + 5
3474
- if self.default_header_height[0] != "pixels":
3475
- self.default_header_height = (
3476
- self.default_header_height[0] if self.default_header_height[0] != "pixels" else "pixels",
3477
- (
3478
- self.get_lines_cell_height(int(self.default_header_height[0]), font=self.PAR.ops.header_font)
3479
- if self.default_header_height[0] != "pixels"
3480
- else self.default_header_height[1]
3481
- ),
3482
- )
3448
+ if (
3449
+ isinstance(self.PAR.ops.default_header_height, int)
3450
+ and self.PAR.ops.default_header_height < self.min_header_height
3451
+ ):
3452
+ self.PAR.ops.default_header_height = int(self.min_header_height)
3483
3453
  self.set_min_column_width()
3484
- self.CH.set_height(self.default_header_height[1], set_TL=True)
3454
+ self.CH.set_height(self.get_default_header_height(), set_TL=True)
3485
3455
 
3486
3456
  def set_index_font(self, newfont: tuple | None = None) -> tuple[str, int, str]:
3487
3457
  if newfont:
@@ -3493,7 +3463,7 @@ class MainTable(tk.Canvas):
3493
3463
  raise ValueError(
3494
3464
  "Argument must be font, size and 'normal', 'bold' or" "'italic' e.g. ('Carlito',12,'normal')"
3495
3465
  )
3496
- self.PAR.ops.index_font = newfont
3466
+ self.PAR.ops.index_font = FontTuple(*newfont)
3497
3467
  self.set_index_font_help()
3498
3468
  return self.PAR.ops.index_font
3499
3469
 
@@ -3634,10 +3604,9 @@ class MainTable(tk.Canvas):
3634
3604
  h = min_rh
3635
3605
  rhs = defaultdict(lambda: int(min_rh))
3636
3606
  cws = []
3637
- x = self.txt_measure_canvas.create_text(0, 0, text="", font=self.PAR.ops.table_font)
3638
- x2 = self.txt_measure_canvas.create_text(0, 0, text="", font=self.PAR.ops.header_font)
3639
3607
  itmcon = self.txt_measure_canvas.itemconfig
3640
3608
  itmbbx = self.txt_measure_canvas.bbox
3609
+ self.txt_measure_canvas.itemconfig(self.txt_measure_canvas_text, font=self.PAR.ops.table_font)
3641
3610
  numrows = self.total_data_rows()
3642
3611
  if self.all_columns_displayed:
3643
3612
  itercols = range(self.total_data_cols())
@@ -3663,8 +3632,8 @@ class MainTable(tk.Canvas):
3663
3632
  for datarn in iterrows:
3664
3633
  txt = self.get_valid_cell_data_as_str(datarn, datacn, get_displayed=True)
3665
3634
  if txt:
3666
- itmcon(x, text=txt)
3667
- b = itmbbx(x)
3635
+ itmcon(self.txt_measure_canvas_text, text=txt)
3636
+ b = itmbbx(self.txt_measure_canvas_text)
3668
3637
  tw = b[2] - b[0] + 7
3669
3638
  h = b[3] - b[1] + 5
3670
3639
  else:
@@ -3687,8 +3656,6 @@ class MainTable(tk.Canvas):
3687
3656
  elif w > self.max_column_width:
3688
3657
  w = int(self.max_column_width)
3689
3658
  cws.append(w)
3690
- self.txt_measure_canvas.delete(x)
3691
- self.txt_measure_canvas.delete(x2)
3692
3659
  self.set_row_positions(itr=(height for height in rhs.values()))
3693
3660
  self.set_col_positions(itr=(width for width in cws))
3694
3661
  self.recreate_all_selection_boxes()
@@ -3698,7 +3665,7 @@ class MainTable(tk.Canvas):
3698
3665
  self.col_positions = list(accumulate(chain([0], itr)))
3699
3666
 
3700
3667
  def reset_col_positions(self, ncols: int | None = None):
3701
- colpos = int(self.default_column_width)
3668
+ colpos = self.PAR.ops.default_column_width
3702
3669
  if self.all_columns_displayed:
3703
3670
  self.set_col_positions(itr=(colpos for c in range(ncols if ncols is not None else self.total_data_cols())))
3704
3671
  else:
@@ -3710,7 +3677,7 @@ class MainTable(tk.Canvas):
3710
3677
  self.row_positions = list(accumulate(chain([0], itr)))
3711
3678
 
3712
3679
  def reset_row_positions(self, nrows: int | None = None):
3713
- rowpos = self.default_row_height[1]
3680
+ rowpos = self.get_default_row_height()
3714
3681
  if self.all_rows_displayed:
3715
3682
  self.set_row_positions(itr=(rowpos for r in range(nrows if nrows is not None else self.total_data_rows())))
3716
3683
  else:
@@ -3781,7 +3748,7 @@ class MainTable(tk.Canvas):
3781
3748
  if deselect_all:
3782
3749
  self.deselect("all", redraw=False)
3783
3750
  if width is None:
3784
- w = self.default_column_width
3751
+ w = self.PAR.ops.default_column_width
3785
3752
  else:
3786
3753
  w = width
3787
3754
  if idx == "end" or len(self.col_positions) == idx + 1:
@@ -3801,7 +3768,7 @@ class MainTable(tk.Canvas):
3801
3768
  if deselect_all:
3802
3769
  self.deselect("all", redraw=False)
3803
3770
  if height is None:
3804
- h = self.default_row_height[1]
3771
+ h = self.get_default_row_height()
3805
3772
  else:
3806
3773
  h = height
3807
3774
  if idx == "end" or len(self.row_positions) == idx + 1:
@@ -3821,9 +3788,9 @@ class MainTable(tk.Canvas):
3821
3788
  if deselect_all:
3822
3789
  self.deselect("all", redraw=False)
3823
3790
  if widths is None:
3824
- w = [self.default_column_width]
3791
+ w = [self.PAR.ops.default_column_width]
3825
3792
  elif isinstance(widths, int):
3826
- w = list(repeat(self.default_column_width, widths))
3793
+ w = list(repeat(self.PAR.ops.default_column_width, widths))
3827
3794
  else:
3828
3795
  w = widths
3829
3796
  if idx == "end" or len(self.col_positions) == idx + 1:
@@ -3855,10 +3822,11 @@ class MainTable(tk.Canvas):
3855
3822
  ) -> None:
3856
3823
  if deselect_all:
3857
3824
  self.deselect("all", redraw=False)
3825
+ default_row_height = self.get_default_row_height()
3858
3826
  if heights is None:
3859
- h = [self.default_row_height[1]]
3827
+ h = [default_row_height]
3860
3828
  elif isinstance(heights, int):
3861
- h = list(repeat(self.default_row_height[1], heights))
3829
+ h = list(repeat(default_row_height, heights))
3862
3830
  else:
3863
3831
  h = heights
3864
3832
  if idx == "end" or len(self.row_positions) == idx + 1:
@@ -3896,10 +3864,17 @@ class MainTable(tk.Canvas):
3896
3864
  cols: list | tuple,
3897
3865
  create_ops: bool = True,
3898
3866
  ) -> None:
3899
- # 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
+ }
3900
3871
  self.cell_options = {
3901
3872
  (r, c if not (num := bisect_right(cols, c)) else c + num): v for (r, c), v in self.cell_options.items()
3902
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
+ }
3903
3878
  self.col_options = {
3904
3879
  c if not (num := bisect_right(cols, c)) else c + num: v for c, v in self.col_options.items()
3905
3880
  }
@@ -3911,7 +3886,7 @@ class MainTable(tk.Canvas):
3911
3886
  totalrows = None
3912
3887
  new_ops = self.PAR.create_options_from_span
3913
3888
  qkspan = self.span()
3914
- for name, span in self.named_spans.items():
3889
+ for span in self.named_spans.values():
3915
3890
  if isinstance(span["from_c"], int):
3916
3891
  for datacn in cols:
3917
3892
  if span["from_c"] > datacn:
@@ -3958,21 +3933,32 @@ class MainTable(tk.Canvas):
3958
3933
  rows: list | tuple,
3959
3934
  create_ops: bool = True,
3960
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
+ }
3961
3940
  self.cell_options = {
3962
3941
  (r if not (num := bisect_right(rows, r)) else r + num, c): v for (r, c), v in self.cell_options.items()
3963
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
+ }
3964
3947
  self.row_options = {
3965
3948
  r if not (num := bisect_right(rows, r)) else r + num: v for r, v in self.row_options.items()
3966
3949
  }
3967
3950
  self.RI.cell_options = {
3968
3951
  r if not (num := bisect_right(rows, r)) else r + num: v for r, v in self.RI.cell_options.items()
3969
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
+ }
3970
3956
  # if there are named spans where rows were added
3971
3957
  # add options to gap which was created by adding rows
3972
3958
  totalcols = None
3973
3959
  new_ops = self.PAR.create_options_from_span
3974
3960
  qkspan = self.span()
3975
- for name, span in self.named_spans.items():
3961
+ for span in self.named_spans.values():
3976
3962
  if isinstance(span["from_r"], int):
3977
3963
  for datarn in rows:
3978
3964
  if span["from_r"] > datarn:
@@ -4024,6 +4010,17 @@ class MainTable(tk.Canvas):
4024
4010
  to_del = set()
4025
4011
  if not to_bis:
4026
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
+ }
4027
4024
  self.cell_options = {
4028
4025
  (
4029
4026
  r,
@@ -4032,6 +4029,10 @@ class MainTable(tk.Canvas):
4032
4029
  for (r, c), v in self.cell_options.items()
4033
4030
  if c not in to_del
4034
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
+ }
4035
4036
  self.col_options = {
4036
4037
  c if not (num := bisect_left(to_bis, c)) else c - num: v
4037
4038
  for c, v in self.col_options.items()
@@ -4059,7 +4060,7 @@ class MainTable(tk.Canvas):
4059
4060
  named_spans = self.get_spans_to_del_from_cols(cols=to_del)
4060
4061
  for name in named_spans:
4061
4062
  del self.named_spans[name]
4062
- for name, span in self.named_spans.items():
4063
+ for span in self.named_spans.values():
4063
4064
  if isinstance(span["from_c"], int):
4064
4065
  for c in to_bis:
4065
4066
  if span["from_c"] > c:
@@ -4089,6 +4090,17 @@ class MainTable(tk.Canvas):
4089
4090
  to_del = set()
4090
4091
  if not to_bis:
4091
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
+ }
4092
4104
  self.cell_options = {
4093
4105
  (
4094
4106
  r if not (num := bisect_left(to_bis, r)) else r - num,
@@ -4097,6 +4109,10 @@ class MainTable(tk.Canvas):
4097
4109
  for (r, c), v in self.cell_options.items()
4098
4110
  if r not in to_del
4099
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
+ }
4100
4116
  self.row_options = {
4101
4117
  r if not (num := bisect_left(to_bis, r)) else r - num: v
4102
4118
  for r, v in self.row_options.items()
@@ -4107,6 +4123,11 @@ class MainTable(tk.Canvas):
4107
4123
  for r, v in self.RI.cell_options.items()
4108
4124
  if r not in to_del
4109
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
+ }
4110
4131
  self.del_rows_from_named_spans(
4111
4132
  to_del=to_del,
4112
4133
  to_bis=to_bis,
@@ -4124,7 +4145,7 @@ class MainTable(tk.Canvas):
4124
4145
  named_spans = self.get_spans_to_del_from_rows(rows=to_del)
4125
4146
  for name in named_spans:
4126
4147
  del self.named_spans[name]
4127
- for name, span in self.named_spans.items():
4148
+ for span in self.named_spans.values():
4128
4149
  if isinstance(span["from_r"], int):
4129
4150
  for r in to_bis:
4130
4151
  if span["from_r"] > r:
@@ -4155,6 +4176,7 @@ class MainTable(tk.Canvas):
4155
4176
  create_selections: bool = True,
4156
4177
  add_row_positions: bool = True,
4157
4178
  ) -> EventDataDict:
4179
+ self.saved_column_widths = {}
4158
4180
  saved_displayed_columns = list(self.displayed_columns)
4159
4181
  if isinstance(displayed_columns, list):
4160
4182
  self.displayed_columns = displayed_columns
@@ -4172,7 +4194,7 @@ class MainTable(tk.Canvas):
4172
4194
  cws = self.get_column_widths()
4173
4195
  if column_widths and next(reversed(column_widths)) > len(cws):
4174
4196
  for i in reversed(range(len(cws), len(cws) + next(reversed(column_widths)) - len(cws))):
4175
- column_widths[i] = self.default_column_width
4197
+ column_widths[i] = self.PAR.ops.default_column_width
4176
4198
  self.set_col_positions(
4177
4199
  itr=insert_items(
4178
4200
  cws,
@@ -4191,10 +4213,11 @@ class MainTable(tk.Canvas):
4191
4213
  self.data[rn].insert(cn, v)
4192
4214
  # if not hiding rows then we can extend row positions if necessary
4193
4215
  if add_row_positions and self.all_rows_displayed and maxrn + 1 > len(self.row_positions) - 1:
4216
+ default_row_height = self.get_default_row_height()
4194
4217
  self.set_row_positions(
4195
4218
  itr=chain(
4196
4219
  self.gen_row_heights(),
4197
- (self.default_row_height[1] for i in range(len(self.row_positions) - 1, maxrn + 1)),
4220
+ (default_row_height for i in range(len(self.row_positions) - 1, maxrn + 1)),
4198
4221
  )
4199
4222
  )
4200
4223
  if isinstance(self._headers, list):
@@ -4259,7 +4282,7 @@ class MainTable(tk.Canvas):
4259
4282
  name="add_columns",
4260
4283
  sheet=self.PAR.name,
4261
4284
  boxes=self.get_boxes(),
4262
- selected=self.currently_selected(),
4285
+ selected=self.selected,
4263
4286
  )
4264
4287
  if not try_binding(self.extra_begin_insert_cols_rc_func, event_data, "begin_add_columns"):
4265
4288
  return
@@ -4284,6 +4307,7 @@ class MainTable(tk.Canvas):
4284
4307
  create_selections: bool = True,
4285
4308
  add_col_positions: bool = True,
4286
4309
  ) -> EventDataDict:
4310
+ self.saved_row_heights = {}
4287
4311
  saved_displayed_rows = list(self.displayed_rows)
4288
4312
  if isinstance(displayed_rows, list):
4289
4313
  self.displayed_rows = displayed_rows
@@ -4300,8 +4324,9 @@ class MainTable(tk.Canvas):
4300
4324
  up_to = last_ins
4301
4325
  rhs = self.get_row_heights()
4302
4326
  if row_heights and next(reversed(row_heights)) > len(rhs):
4327
+ default_row_height = self.get_default_row_height()
4303
4328
  for i in reversed(range(len(rhs), len(rhs) + next(reversed(row_heights)) - len(rhs))):
4304
- row_heights[i] = self.default_row_height[1]
4329
+ row_heights[i] = default_row_height
4305
4330
  self.set_row_positions(
4306
4331
  itr=insert_items(
4307
4332
  rhs,
@@ -4316,14 +4341,14 @@ class MainTable(tk.Canvas):
4316
4341
  self.data.insert(rn, row)
4317
4342
  if cn > maxcn:
4318
4343
  maxcn = cn
4319
- if isinstance(self.row_index, list):
4344
+ if isinstance(self._row_index, list):
4320
4345
  self._row_index = insert_items(self._row_index, index, self.RI.fix_index)
4321
4346
  # if not hiding columns then we can extend col positions if necessary
4322
4347
  if add_col_positions and self.all_columns_displayed and maxcn + 1 > len(self.col_positions) - 1:
4323
4348
  self.set_col_positions(
4324
4349
  itr=chain(
4325
4350
  self.gen_column_widths(),
4326
- (self.default_column_width for i in range(len(self.col_positions) - 1, maxcn + 1)),
4351
+ (self.PAR.ops.default_column_width for i in range(len(self.col_positions) - 1, maxcn + 1)),
4327
4352
  )
4328
4353
  )
4329
4354
  self.adjust_options_post_add_rows(
@@ -4386,7 +4411,7 @@ class MainTable(tk.Canvas):
4386
4411
  name="add_rows",
4387
4412
  sheet=self.PAR.name,
4388
4413
  boxes=self.get_boxes(),
4389
- selected=self.currently_selected(),
4414
+ selected=self.selected,
4390
4415
  )
4391
4416
  if not try_binding(self.extra_begin_insert_rows_rc_func, event_data, "begin_add_rows"):
4392
4417
  return
@@ -4440,7 +4465,8 @@ class MainTable(tk.Canvas):
4440
4465
  }
4441
4466
  if widths is None:
4442
4467
  widths = {
4443
- c: self.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))
4444
4470
  }
4445
4471
  else:
4446
4472
  widths = {
@@ -4488,9 +4514,8 @@ class MainTable(tk.Canvas):
4488
4514
  for datarn, v in zip(reversed(range(data_ins_row, data_ins_row + numrows)), reversed(rows))
4489
4515
  }
4490
4516
  if heights is None:
4491
- heights = {
4492
- r: self.default_row_height[1] for r in reversed(range(displayed_ins_row, displayed_ins_row + numrows))
4493
- }
4517
+ default_row_height = self.get_default_row_height()
4518
+ heights = {r: default_row_height for r in reversed(range(displayed_ins_row, displayed_ins_row + numrows))}
4494
4519
  else:
4495
4520
  heights = {
4496
4521
  r: height
@@ -4541,6 +4566,7 @@ class MainTable(tk.Canvas):
4541
4566
  return event_data
4542
4567
 
4543
4568
  def delete_columns_displayed(self, cols: list, event_data: dict) -> EventDataDict:
4569
+ self.saved_column_widths = {}
4544
4570
  cols_set = set(cols)
4545
4571
  for c in reversed(cols):
4546
4572
  event_data["deleted"]["column_widths"][c] = self.col_positions[c + 1] - self.col_positions[c]
@@ -4549,14 +4575,13 @@ class MainTable(tk.Canvas):
4549
4575
 
4550
4576
  def rc_delete_columns(self, event: object = None):
4551
4577
  selected = sorted(self.get_selected_cols())
4552
- curr = self.currently_selected()
4553
- if not selected or not curr:
4578
+ if not self.selected:
4554
4579
  return
4555
4580
  event_data = event_dict(
4556
4581
  name="delete_columns",
4557
4582
  sheet=self.PAR.name,
4558
4583
  boxes=self.get_boxes(),
4559
- selected=self.currently_selected(),
4584
+ selected=self.selected,
4560
4585
  )
4561
4586
  if not try_binding(self.extra_begin_del_cols_rc_func, event_data, "begin_delete_columns"):
4562
4587
  return
@@ -4595,6 +4620,7 @@ class MainTable(tk.Canvas):
4595
4620
  return event_data
4596
4621
 
4597
4622
  def delete_rows_displayed(self, rows: list, event_data: dict) -> EventDataDict:
4623
+ self.saved_row_heights = {}
4598
4624
  rows_set = set(rows)
4599
4625
  for r in reversed(rows):
4600
4626
  event_data["deleted"]["row_heights"][r] = self.row_positions[r + 1] - self.row_positions[r]
@@ -4603,14 +4629,13 @@ class MainTable(tk.Canvas):
4603
4629
 
4604
4630
  def rc_delete_rows(self, event: object = None):
4605
4631
  selected = sorted(self.get_selected_rows())
4606
- curr = self.currently_selected()
4607
- if not selected or not curr:
4632
+ if not self.selected:
4608
4633
  return
4609
4634
  event_data = event_dict(
4610
4635
  name="delete_rows",
4611
4636
  sheet=self.PAR.name,
4612
4637
  boxes=self.get_boxes(),
4613
- selected=self.currently_selected(),
4638
+ selected=self.selected,
4614
4639
  )
4615
4640
  if not try_binding(self.extra_begin_del_rows_rc_func, event_data, "begin_delete_rows"):
4616
4641
  return
@@ -4741,7 +4766,7 @@ class MainTable(tk.Canvas):
4741
4766
  and isinstance(self._headers, list)
4742
4767
  and (self.col_positions == [0] or not self.col_positions)
4743
4768
  ):
4744
- colpos = int(self.default_column_width)
4769
+ colpos = int(self.PAR.ops.default_column_width)
4745
4770
  if self.all_columns_displayed:
4746
4771
  self.set_col_positions(itr=repeat(colpos, len(self._headers)))
4747
4772
  else:
@@ -4764,7 +4789,7 @@ class MainTable(tk.Canvas):
4764
4789
  ) -> object:
4765
4790
  if newindex is not None:
4766
4791
  if not self._row_index and not isinstance(self._row_index, int):
4767
- self.RI.set_width(self.default_row_index_width, set_TL=True)
4792
+ self.RI.set_width(self.PAR.ops.default_row_index_width, set_TL=True)
4768
4793
  if isinstance(newindex, (list, tuple)):
4769
4794
  self._row_index = list(newindex) if isinstance(newindex, tuple) else newindex
4770
4795
  elif isinstance(newindex, int):
@@ -4790,7 +4815,7 @@ class MainTable(tk.Canvas):
4790
4815
  and isinstance(self._row_index, list)
4791
4816
  and (self.row_positions == [0] or not self.row_positions)
4792
4817
  ):
4793
- rowpos = self.default_row_height[1]
4818
+ rowpos = self.get_default_row_height()
4794
4819
  if self.all_rows_displayed:
4795
4820
  self.set_row_positions(itr=repeat(rowpos, len(self._row_index)))
4796
4821
  else:
@@ -5042,27 +5067,28 @@ class MainTable(tk.Canvas):
5042
5067
  if draw_outline and self.PAR.ops.show_dropdown_borders:
5043
5068
  self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.PAR.ops.table_fg, tag=tag)
5044
5069
  if draw_arrow:
5045
- topysub = floor(self.table_half_txt_height / 2)
5046
- mid_y = y1 + floor(self.min_row_height / 2)
5047
- if mid_y + topysub + 1 >= y1 + self.table_txt_height - 1:
5048
- mid_y -= 1
5049
- if mid_y - topysub + 2 <= y1 + 4 + topysub:
5050
- mid_y -= 1
5051
- ty1 = mid_y + topysub + 1 if dd_is_open else mid_y - topysub + 3
5052
- ty2 = mid_y - topysub + 3 if dd_is_open else mid_y + topysub + 1
5053
- 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
+ )
5054
5083
  else:
5055
- ty1 = mid_y + topysub + 1 if dd_is_open else mid_y - topysub + 2
5056
- ty2 = mid_y - topysub + 2 if dd_is_open else mid_y + topysub + 1
5057
- ty3 = mid_y + topysub + 1 if dd_is_open else mid_y - topysub + 2
5058
- tx1 = x2 - self.table_txt_height + 1
5059
- tx2 = x2 - self.table_half_txt_height - 1
5060
- tx3 = x2 - 3
5061
- if tx2 - tx1 > tx3 - tx2:
5062
- tx1 += (tx2 - tx1) - (tx3 - tx2)
5063
- elif tx2 - tx1 < tx3 - tx2:
5064
- tx1 -= (tx3 - tx2) - (tx2 - tx1)
5065
- 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
+ )
5066
5092
  if self.hidd_dropdown:
5067
5093
  t, sh = self.hidd_dropdown.popitem()
5068
5094
  self.coords(t, points)
@@ -5188,8 +5214,6 @@ class MainTable(tk.Canvas):
5188
5214
  if i not in diffs:
5189
5215
  heights[i] -= change
5190
5216
  self.row_positions = list(accumulate(chain([0], heights)))
5191
- if resized_cols or resized_rows:
5192
- self.recreate_all_selection_boxes()
5193
5217
  last_col_line_pos = self.col_positions[-1] + 1
5194
5218
  last_row_line_pos = self.row_positions[-1] + 1
5195
5219
  if can_width >= last_col_line_pos + self.PAR.ops.empty_horizontal and self.PAR.xscroll_showing:
@@ -5214,27 +5238,35 @@ class MainTable(tk.Canvas):
5214
5238
  ):
5215
5239
  self.PAR.yscroll.grid(row=0, column=2, rowspan=3, sticky="nswe")
5216
5240
  self.PAR.yscroll_showing = True
5217
- self.configure(
5218
- scrollregion=(
5219
- 0,
5220
- 0,
5221
- last_col_line_pos + self.PAR.ops.empty_horizontal + 2,
5222
- last_row_line_pos + self.PAR.ops.empty_vertical + 2,
5223
- )
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,
5224
5246
  )
5247
+ if scrollregion != self.scrollregion:
5248
+ self.configure(scrollregion=scrollregion)
5249
+ self.scrollregion = scrollregion
5225
5250
  scrollpos_bot = self.canvasy(can_height)
5226
5251
  end_row = bisect_right(self.row_positions, scrollpos_bot)
5227
5252
  if not scrollpos_bot >= self.row_positions[-1]:
5228
5253
  end_row += 1
5229
- if redraw_row_index and self.show_index:
5230
- self.RI.auto_set_index_width(end_row - 1)
5231
- # return
5232
5254
  scrollpos_left = self.canvasx(0)
5233
5255
  scrollpos_top = self.canvasy(0)
5234
5256
  scrollpos_right = self.canvasx(can_width)
5235
5257
  start_row = bisect_left(self.row_positions, scrollpos_top)
5236
5258
  start_col = bisect_left(self.col_positions, scrollpos_left)
5237
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()
5238
5270
  self.hidd_text.update(self.disp_text)
5239
5271
  self.disp_text = {}
5240
5272
  self.hidd_high.update(self.disp_high)
@@ -5346,7 +5378,7 @@ class MainTable(tk.Canvas):
5346
5378
  c_4_ = (int(c_4[1:3], 16), int(c_4[3:5], 16), int(c_4[5:], 16))
5347
5379
  rows_ = tuple(range(start_row, end_row))
5348
5380
  font = self.PAR.ops.table_font
5349
- dd_coords = self.get_existing_dropdown_coords()
5381
+ dd_coords = self.dropdown.get_coords()
5350
5382
  for c in range(start_col, end_col - 1):
5351
5383
  for r in rows_:
5352
5384
  rtopgridln = self.row_positions[r]
@@ -5548,10 +5580,11 @@ class MainTable(tk.Canvas):
5548
5580
  self.itemconfig(iid, state="hidden")
5549
5581
  dct[iid] = False
5550
5582
  if self.PAR.ops.show_selected_cells_border:
5551
- self.tag_raise("cellsbd")
5552
- self.tag_raise("selected")
5553
- self.tag_raise("rowsbd")
5554
- 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)
5555
5588
  if redraw_header and self.show_header:
5556
5589
  self.CH.redraw_grid_and_text(
5557
5590
  last_col_line_pos,
@@ -5581,154 +5614,94 @@ class MainTable(tk.Canvas):
5581
5614
  cells: bool = True,
5582
5615
  rows: bool = True,
5583
5616
  columns: bool = True,
5584
- current: bool = True,
5585
5617
  reverse: bool = False,
5586
- ) -> list:
5587
- return sorted(
5588
- (self.find_withtag("cells") if cells else tuple())
5589
- + (self.find_withtag("rows") if rows else tuple())
5590
- + (self.find_withtag("columns") if columns else tuple())
5591
- + (self.find_withtag("selected") if current else tuple()),
5592
- 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"
5593
5624
  )
5594
5625
 
5595
5626
  def get_boxes(self) -> dict:
5596
- boxes = {}
5597
- for item in self.get_selection_items(current=False):
5598
- tags = self.gettags(item)
5599
- boxes[coords_tag_to_box_nt(tags[1])] = tags[0]
5600
- return boxes
5627
+ return {box.coords: box.type_ for box in self.selection_boxes.values()}
5601
5628
 
5602
5629
  def reselect_from_get_boxes(
5603
5630
  self,
5604
5631
  boxes: dict,
5605
- curr: tuple = tuple(),
5632
+ selected: tuple = tuple(),
5606
5633
  ) -> None:
5607
5634
  for (r1, c1, r2, c2), v in boxes.items():
5608
5635
  if r2 < len(self.row_positions) and c2 < len(self.col_positions):
5609
5636
  self.create_selection_box(r1, c1, r2, c2, v, run_binding=True)
5610
- if curr:
5611
- self.set_currently_selected(tags=curr.tags)
5612
-
5613
- def currently_selected(self, get_item: bool = False) -> int | tuple | CurrentlySelectedClass:
5614
- items = self.get_selection_items(cells=False, rows=False, columns=False)
5615
- if not items:
5616
- return tuple()
5617
- # more than one currently selected box shouldn't be allowed
5618
- # but just to make sure we get the most recent one anyway
5619
- if get_item:
5620
- return items[-1]
5621
- tags = self.gettags(items[-1])
5622
- r, c = coords_tag_to_int_tuple(tags[3])
5623
- # remove "s" from end
5624
- type_ = tags[4].split("_")[1][:-1]
5625
- return CurrentlySelectedClass(r, c, type_, tags)
5626
-
5627
- def move_currently_selected_within_box(self, r: int, c: int) -> None:
5628
- curr = self.currently_selected()
5629
- if curr:
5630
- self.set_currently_selected(r=r, c=c, item=self.to_item_int(curr.tags), tags=curr.tags)
5631
-
5632
- def set_currently_selected(self, r: int | None = None, c: int | None = None, **kwargs) -> None:
5633
- # if r and c are provided it will attempt to
5634
- # put currently box at that coordinate
5635
- # _________
5636
- # "selected" tags have the most information about the box
5637
- if "tags" in kwargs and kwargs["tags"]:
5638
- 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
5639
5650
  if r is None:
5640
- r = r_
5651
+ r = r1
5641
5652
  if c is None:
5642
- c = c_
5643
- if "item" in kwargs:
5644
- self.set_currently_selected(
5645
- 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,
5646
5660
  )
5647
- else:
5648
- self.set_currently_selected(r=r, c=c, box=coords_tag_to_int_tuple(kwargs["tags"][1]))
5649
- return
5650
- # place at item if r and c are in bounds
5651
- if "item" in kwargs:
5652
- tags = self.gettags(self.to_item_int(kwargs["item"]))
5653
- if tags:
5654
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
5655
- if r is None:
5656
- r = r1
5657
- if c is None:
5658
- c = c1
5659
- if r1 <= r and c1 <= c and r2 > r and c2 > c:
5660
- self.create_currently_selected_box(
5661
- r,
5662
- c,
5663
- ("selected", tags[1], tags[2], f"{r}_{c}", f"type_{tags[0]}"),
5664
- )
5665
- return
5661
+ return
5666
5662
  # currently selected is pointed at any selection box with "box" coordinates
5667
- if "box" in kwargs:
5663
+ if isinstance(box, tuple):
5668
5664
  if r is None:
5669
- r = kwargs["box"][0]
5665
+ r = box[0]
5670
5666
  if c is None:
5671
- c = kwargs["box"][1]
5672
- for item in self.get_selection_items(current=False):
5673
- tags = self.gettags(item)
5674
- r1, c1, r2, c2 = coords_tag_to_int_tuple(tags[1])
5675
- 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:
5676
5671
  self.create_currently_selected_box(
5677
5672
  r,
5678
5673
  c,
5679
- ("selected", tags[1], tags[2], f"{r}_{c}", f"type_{tags[0]}"),
5674
+ selection_box.type_,
5675
+ selection_box.fill_iid,
5680
5676
  )
5681
5677
  return
5682
5678
  # currently selected is just pointed at a coordinate
5683
5679
  # find the top most box there, requires r and c
5684
5680
  if r is not None and c is not None:
5685
- for item in self.get_selection_items(current=False):
5686
- tags = self.gettags(item)
5687
- 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
5688
5683
  if r1 <= r and c1 <= c and r2 > r and c2 > c:
5689
5684
  self.create_currently_selected_box(
5690
5685
  r,
5691
5686
  c,
5692
- ("selected", tags[1], tags[2], f"{r}_{c}", f"type_{tags[0]}"),
5687
+ selection_box.type_,
5688
+ selection_box.fill_iid,
5693
5689
  )
5694
5690
  return
5695
5691
  # wasn't provided an item and couldn't find a box at coords so select cell
5696
5692
  self.select_cell(r, c, redraw=True)
5697
5693
 
5698
5694
  def set_current_to_last(self) -> None:
5699
- items = self.get_selection_items(current=False)
5700
- if items:
5701
- item = items[-1]
5702
- 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
5703
5698
  if r2 - r1 == 1 and c2 - c1 == 1:
5704
- self.itemconfig(item, state="hidden")
5705
- self.set_currently_selected(item=item)
5699
+ self.itemconfig(box.fill_iid, state="hidden")
5700
+ self.set_currently_selected(item=box.fill_iid)
5706
5701
 
5707
- def delete_item(self, item: int, set_current: bool = True) -> None:
5708
- if item is None:
5709
- return
5710
- item = self.to_item_int(item)
5711
- self.delete(f"iid_{item}")
5712
- self.RI.delete(f"iid_{item}")
5713
- self.CH.delete(f"iid_{item}")
5714
-
5715
- def get_box_from_item(self, item: int, get_dict: bool = False) -> dict | tuple:
5716
- if item is None or item is True:
5717
- return tuple()
5718
- # it's in the form of an item tag f"iid_{item}"
5719
- item = self.to_item_int(item)
5720
- tags = self.gettags(item)
5721
- if tags:
5722
- if get_dict:
5723
- if tags[0] == "selected":
5724
- return {coords_tag_to_box_nt(tags[1]): tags[4].split("_")[1]}
5725
- else:
5726
- return {coords_tag_to_box_nt(tags[1]): tags[0]}
5727
- else:
5728
- if tags[0] == "selected":
5729
- return Box_t(*(coords_tag_to_int_tuple(tags[1]) + (tags[4].split("_")[1],)))
5730
- else:
5731
- 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_,)))
5732
5705
  return tuple()
5733
5706
 
5734
5707
  def get_selected_box_bg_fg(self, type_: str) -> tuple:
@@ -5739,65 +5712,103 @@ class MainTable(tk.Canvas):
5739
5712
  elif type_ == "columns":
5740
5713
  return self.PAR.ops.table_selected_columns_bg, self.PAR.ops.table_selected_box_columns_fg
5741
5714
 
5742
- def create_currently_selected_box(self, r: int, c: int, tags: tuple) -> int:
5743
- 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:
5744
5722
  fill, outline = self.get_selected_box_bg_fg(type_=type_)
5745
- iid = self.currently_selected(get_item=True)
5746
5723
  x1 = self.col_positions[c] + 1
5747
5724
  y1 = self.row_positions[r] + 1
5748
5725
  x2 = self.col_positions[c + 1] if index_exists(self.col_positions, c + 1) else self.col_positions[c]
5749
5726
  y2 = self.row_positions[r + 1] if index_exists(self.row_positions, r + 1) else self.row_positions[r]
5750
- if isinstance(iid, int):
5751
- self.coords(
5752
- 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(
5753
5776
  x1,
5754
5777
  y1,
5755
5778
  x2,
5756
5779
  y2,
5780
+ fill=fill,
5781
+ outline=outline,
5782
+ state=state,
5783
+ tags=tags,
5784
+ width=width,
5757
5785
  )
5758
- if self.PAR.ops.show_selected_cells_border:
5759
- self.itemconfig(
5760
- iid,
5761
- fill="",
5762
- outline=outline,
5763
- width=2,
5764
- tags=tags,
5765
- )
5766
- self.tag_raise(iid)
5767
- else:
5768
- self.itemconfig(
5769
- iid,
5770
- fill=fill,
5771
- outline="",
5772
- tags=tags,
5773
- )
5774
- else:
5775
- if self.PAR.ops.show_selected_cells_border:
5776
- iid = self.create_rectangle(
5777
- x1,
5778
- y1,
5779
- x2,
5780
- y2,
5781
- fill="",
5782
- outline=outline,
5783
- width=2,
5784
- tags=tags,
5785
- )
5786
- else:
5787
- iid = self.create_rectangle(
5788
- x1,
5789
- y1,
5790
- x2,
5791
- y2,
5792
- fill=fill,
5793
- outline="",
5794
- tags=tags,
5795
- )
5796
- if not self.PAR.ops.show_selected_cells_border:
5797
- self.tag_lower(iid)
5798
- self.lower_selection_boxes()
5786
+ self.disp_boxes.add(iid)
5799
5787
  return iid
5800
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
+
5801
5812
  def create_selection_box(
5802
5813
  self,
5803
5814
  r1: int,
@@ -5815,23 +5826,16 @@ class MainTable(tk.Canvas):
5815
5826
  if self.row_positions == [0]:
5816
5827
  r1 = 0
5817
5828
  r2 = 0
5818
- self.itemconfig("cells", state="normal")
5819
5829
  if type_ == "cells":
5820
- fill_tags = ("cells", f"{r1}_{c1}_{r2}_{c2}")
5821
- border_tags = ("cellsbd", f"{r1}_{c1}_{r2}_{c2}")
5822
5830
  mt_bg = self.PAR.ops.table_selected_cells_bg
5823
5831
  mt_border_col = self.PAR.ops.table_selected_cells_border_fg
5824
5832
  elif type_ == "rows":
5825
- fill_tags = ("rows", f"{r1}_{c1}_{r2}_{c2}")
5826
- border_tags = ("rowsbd", f"{r1}_{c1}_{r2}_{c2}")
5827
5833
  mt_bg = self.PAR.ops.table_selected_rows_bg
5828
5834
  mt_border_col = self.PAR.ops.table_selected_rows_border_fg
5829
5835
  elif type_ == "columns":
5830
- fill_tags = ("columns", f"{r1}_{c1}_{r2}_{c2}")
5831
- border_tags = ("columnsbd", f"{r1}_{c1}_{r2}_{c2}")
5832
5836
  mt_bg = self.PAR.ops.table_selected_columns_bg
5833
5837
  mt_border_col = self.PAR.ops.table_selected_columns_border_fg
5834
- fill_iid = self.create_rectangle(
5838
+ fill_iid = self.display_box(
5835
5839
  self.col_positions[c1],
5836
5840
  self.row_positions[r1],
5837
5841
  self.canvasx(self.winfo_width()) if self.PAR.ops.selected_rows_to_end_of_window else self.col_positions[c2],
@@ -5839,26 +5843,20 @@ class MainTable(tk.Canvas):
5839
5843
  fill=mt_bg,
5840
5844
  outline="",
5841
5845
  state=state,
5842
- tags=fill_tags,
5846
+ tags=type_,
5847
+ width=1,
5843
5848
  )
5844
- tag_addon = f"iid_{fill_iid}"
5845
- self.addtag_withtag(tag_addon, fill_iid)
5846
- self.last_selected = fill_iid
5847
- tag_index_header_type = fill_tags + (tag_addon,)
5848
- tag_index_header = ("cells", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5849
- ch_tags = tag_index_header if type_ == "rows" else tag_index_header_type
5850
- ri_tags = tag_index_header if type_ == "columns" else tag_index_header_type
5851
- border_tags = border_tags + (tag_addon,)
5852
- self.RI.create_rectangle(
5849
+ index_iid = self.RI.display_box(
5853
5850
  0,
5854
5851
  self.row_positions[r1],
5855
5852
  self.RI.current_width - 1,
5856
5853
  self.row_positions[r2],
5857
5854
  fill=self.PAR.ops.index_selected_rows_bg if type_ == "rows" else self.PAR.ops.index_selected_cells_bg,
5858
5855
  outline="",
5859
- tags=ri_tags,
5856
+ state="normal",
5857
+ tags="cells" if type_ == "columns" else type_,
5860
5858
  )
5861
- self.CH.create_rectangle(
5859
+ header_iid = self.CH.display_box(
5862
5860
  self.col_positions[c1],
5863
5861
  0,
5864
5862
  self.col_positions[c2],
@@ -5867,51 +5865,54 @@ class MainTable(tk.Canvas):
5867
5865
  self.PAR.ops.header_selected_columns_bg if type_ == "columns" else self.PAR.ops.header_selected_cells_bg
5868
5866
  ),
5869
5867
  outline="",
5870
- tags=ch_tags,
5868
+ state="normal",
5869
+ tags="cells" if type_ == "rows" else type_,
5871
5870
  )
5872
- if set_current:
5873
- if set_current is True:
5874
- curr_r = r1
5875
- curr_c = c1
5876
- elif isinstance(set_current, tuple):
5877
- curr_r = set_current[0]
5878
- curr_c = set_current[1]
5879
- currently_selected_tags = (
5880
- "selected", # tags[0] name
5881
- f"{r1}_{c1}_{r2}_{c2}", # tags[1] dimensions of box it's attached to
5882
- tag_addon, # tags[2] iid of box it's attached to
5883
- f"{curr_r}_{curr_c}", # tags[3] position of currently selected box
5884
- f"type_{type_}", # tags[4] type of box it's attached to
5885
- )
5886
- self.create_currently_selected_box(curr_r, curr_c, tags=currently_selected_tags)
5871
+ bd_iid = None
5887
5872
  if self.PAR.ops.show_selected_cells_border and (
5888
5873
  (self.being_drawn_item is None and self.RI.being_drawn_item is None and self.CH.being_drawn_item is None)
5889
- or len(self.anything_selected()) > 1
5874
+ or self.selection_boxes
5890
5875
  ):
5891
- self.create_rectangle(
5876
+ bd_iid = self.display_box(
5892
5877
  self.col_positions[c1],
5893
5878
  self.row_positions[r1],
5894
5879
  self.col_positions[c2],
5895
5880
  self.row_positions[r2],
5896
5881
  fill="",
5897
5882
  outline=mt_border_col,
5898
- tags=border_tags,
5883
+ state="normal",
5884
+ tags=f"{type_}bd",
5885
+ width=1,
5899
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)
5900
5904
  self.lower_selection_boxes()
5901
5905
  if run_binding:
5902
5906
  self.run_selection_binding(type_)
5903
5907
  return fill_iid
5904
5908
 
5905
5909
  def lower_selection_boxes(self) -> None:
5906
- self.tag_lower("rows")
5907
- self.RI.tag_lower("rows")
5908
- self.tag_lower("columns")
5909
- self.CH.tag_lower("columns")
5910
- self.tag_lower("cells")
5911
- self.RI.tag_lower("cells")
5912
- self.CH.tag_lower("cells")
5913
- if self.PAR.ops.show_selected_cells_border:
5914
- 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)
5915
5916
 
5916
5917
  def recreate_selection_box(
5917
5918
  self,
@@ -5920,26 +5921,24 @@ class MainTable(tk.Canvas):
5920
5921
  r2: int,
5921
5922
  c2: int,
5922
5923
  fill_iid: int,
5924
+ state: str = "",
5923
5925
  run_binding: bool = False,
5924
- ) -> None:
5925
- alltags = self.gettags(fill_iid)
5926
- type_ = alltags[0]
5927
- 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)
5928
5929
  if type_ == "cells":
5929
- fill_tags = ("cells", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5930
- border_tags = ("cellsbd", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5931
5930
  mt_bg = self.PAR.ops.table_selected_cells_bg
5932
5931
  mt_border_col = self.PAR.ops.table_selected_cells_border_fg
5933
5932
  elif type_ == "rows":
5934
- fill_tags = ("rows", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5935
- border_tags = ("rowsbd", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5936
5933
  mt_bg = self.PAR.ops.table_selected_rows_bg
5937
5934
  mt_border_col = self.PAR.ops.table_selected_rows_border_fg
5938
5935
  elif type_ == "columns":
5939
- fill_tags = ("columns", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5940
- border_tags = ("columnsbd", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5941
5936
  mt_bg = self.PAR.ops.table_selected_columns_bg
5942
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))
5943
5942
  self.coords(
5944
5943
  fill_iid,
5945
5944
  self.col_positions[c1],
@@ -5951,114 +5950,101 @@ class MainTable(tk.Canvas):
5951
5950
  fill_iid,
5952
5951
  fill=mt_bg,
5953
5952
  outline="",
5954
- tags=fill_tags,
5953
+ tags=type_,
5954
+ state=state,
5955
5955
  )
5956
- tag_index_header_type = fill_tags
5957
- tag_index_header = ("cells", f"{r1}_{c1}_{r2}_{c2}", tag_addon)
5958
- ch_tags = tag_index_header if type_ == "rows" else tag_index_header_type
5959
- ri_tags = tag_index_header if type_ == "columns" else tag_index_header_type
5960
5956
  self.RI.coords(
5961
- tag_addon,
5957
+ self.selection_boxes[fill_iid].index,
5962
5958
  0,
5963
5959
  self.row_positions[r1],
5964
5960
  self.RI.current_width - 1,
5965
5961
  self.row_positions[r2],
5966
5962
  )
5967
5963
  self.RI.itemconfig(
5968
- tag_addon,
5964
+ self.selection_boxes[fill_iid].index,
5969
5965
  fill=self.PAR.ops.index_selected_rows_bg if type_ == "rows" else self.PAR.ops.index_selected_cells_bg,
5970
5966
  outline="",
5971
- tags=ri_tags,
5967
+ tags="cells" if type_ == "columns" else type_,
5972
5968
  )
5973
5969
  self.CH.coords(
5974
- tag_addon,
5970
+ self.selection_boxes[fill_iid].header,
5975
5971
  self.col_positions[c1],
5976
5972
  0,
5977
5973
  self.col_positions[c2],
5978
5974
  self.CH.current_height - 1,
5979
5975
  )
5980
5976
  self.CH.itemconfig(
5981
- tag_addon,
5977
+ self.selection_boxes[fill_iid].header,
5982
5978
  fill=(
5983
5979
  self.PAR.ops.header_selected_columns_bg if type_ == "columns" else self.PAR.ops.header_selected_cells_bg
5984
5980
  ),
5985
5981
  outline="",
5986
- tags=ch_tags,
5982
+ tags="cells" if type_ == "rows" else type_,
5987
5983
  )
5988
- # check for border of selection box which is a separate item
5989
- border_item = [item for item in self.find_withtag(tag_addon) if self.gettags(item)[0].endswith("bd")]
5990
- if border_item:
5991
- border_item = border_item[0]
5984
+ if bd_iid := self.selection_boxes[fill_iid].bd_iid:
5992
5985
  if self.PAR.ops.show_selected_cells_border:
5993
5986
  self.coords(
5994
- border_item,
5987
+ bd_iid,
5995
5988
  self.col_positions[c1],
5996
5989
  self.row_positions[r1],
5997
5990
  self.col_positions[c2],
5998
5991
  self.row_positions[r2],
5999
5992
  )
6000
5993
  self.itemconfig(
6001
- border_item,
5994
+ bd_iid,
6002
5995
  fill="",
6003
5996
  outline=mt_border_col,
6004
- tags=border_tags,
5997
+ tags=f"{type_}bd",
5998
+ state="normal",
6005
5999
  )
6000
+ self.tag_raise(bd_iid)
6006
6001
  else:
6007
- self.delete(border_item)
6002
+ self.hide_box(bd_iid)
6008
6003
  if run_binding:
6009
6004
  self.run_selection_binding(type_)
6005
+ return fill_iid
6010
6006
 
6011
6007
  def run_selection_binding(self, type_: str) -> None:
6012
6008
  if type_ == "cells":
6009
+ sel_event = self.get_select_event(being_drawn_item=self.being_drawn_item)
6013
6010
  if self.selection_binding_func:
6014
- self.selection_binding_func(
6015
- self.get_select_event(being_drawn_item=self.being_drawn_item),
6016
- )
6011
+ self.selection_binding_func(sel_event)
6017
6012
  elif type_ == "rows":
6013
+ sel_event = self.get_select_event(being_drawn_item=self.RI.being_drawn_item)
6018
6014
  if self.RI.selection_binding_func:
6019
- self.RI.selection_binding_func(
6020
- self.get_select_event(being_drawn_item=self.RI.being_drawn_item),
6021
- )
6015
+ self.RI.selection_binding_func(sel_event)
6022
6016
  elif type_ == "columns":
6017
+ sel_event = self.get_select_event(being_drawn_item=self.CH.being_drawn_item)
6023
6018
  if self.CH.selection_binding_func:
6024
- self.CH.selection_binding_func(
6025
- self.get_select_event(being_drawn_item=self.CH.being_drawn_item),
6026
- )
6019
+ self.CH.selection_binding_func(sel_event)
6020
+ self.PAR.emit_event("<<SheetSelect>>", data=sel_event)
6027
6021
 
6028
6022
  def recreate_all_selection_boxes(self) -> None:
6029
- curr = self.currently_selected()
6030
- if not curr:
6023
+ if not self.selected:
6031
6024
  return
6032
- for item in self.get_selection_items(current=False):
6033
- tags = self.gettags(item)
6034
- 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
6035
6027
  if r1 >= len(self.row_positions) - 1 or c1 >= len(self.col_positions) - 1:
6036
- self.delete_item(item)
6028
+ self.hide_selection_box(item)
6037
6029
  continue
6038
6030
  if r2 > len(self.row_positions) - 1:
6039
6031
  r2 = len(self.row_positions) - 1
6040
6032
  if c2 > len(self.col_positions) - 1:
6041
6033
  c2 = len(self.col_positions) - 1
6042
6034
  self.recreate_selection_box(r1, c1, r2, c2, item)
6043
- self.set_currently_selected(tags=curr.tags)
6044
-
6045
- def to_item_int(self, item: int | str | tuple) -> int:
6046
- # item arg is a tuple of tags
6047
- if isinstance(item, tuple):
6048
- if isinstance(item, CurrentlySelectedClass):
6049
- return int(item[3][2].split("_")[1])
6050
- return int(item[2].split("_")[1])
6051
- # item arg is one of those tags
6052
- if isinstance(item, str):
6053
- return int(item.split("_")[1])
6054
- # item is probably an int
6055
- 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)
6056
6043
 
6057
6044
  def get_redraw_selections(self, startr: int, endr: int, startc: int, endc: int) -> dict:
6058
6045
  d = defaultdict(list)
6059
- for item in self.get_selection_items(current=False):
6060
- tags = self.gettags(item)
6061
- 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)
6062
6048
  d2 = {}
6063
6049
  if "cells" in d:
6064
6050
  d2["cells"] = {
@@ -6079,8 +6065,8 @@ class MainTable(tk.Canvas):
6079
6065
  min_y = float("inf")
6080
6066
  max_x = 0
6081
6067
  max_y = 0
6082
- for item in self.get_selection_items():
6083
- 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
6084
6070
  if r1 < min_y:
6085
6071
  min_y = r1
6086
6072
  if c1 < min_x:
@@ -6105,14 +6091,14 @@ class MainTable(tk.Canvas):
6105
6091
  within_r2 = within_range[1]
6106
6092
  if get_cells:
6107
6093
  if within_range is None:
6108
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6109
- 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
6110
6096
  s.update(set(product(range(r1, r2), range(0, len(self.col_positions) - 1))))
6111
6097
  if get_cells_as_rows:
6112
6098
  s.update(self.get_selected_cells())
6113
6099
  else:
6114
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6115
- 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
6116
6102
  if r1 >= within_r1 or r2 <= within_r2:
6117
6103
  s.update(
6118
6104
  set(
@@ -6135,14 +6121,14 @@ class MainTable(tk.Canvas):
6135
6121
  )
6136
6122
  else:
6137
6123
  if within_range is None:
6138
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6139
- 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
6140
6126
  s.update(set(range(r1, r2)))
6141
6127
  if get_cells_as_rows:
6142
6128
  s.update(set(tup[0] for tup in self.get_selected_cells()))
6143
6129
  else:
6144
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6145
- 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
6146
6132
  if r1 >= within_r1 or r2 <= within_r2:
6147
6133
  s.update(set(range(r1 if r1 > within_r1 else within_r1, r2 if r2 < within_r2 else within_r2)))
6148
6134
  if get_cells_as_rows:
@@ -6173,14 +6159,14 @@ class MainTable(tk.Canvas):
6173
6159
  within_c2 = within_range[1]
6174
6160
  if get_cells:
6175
6161
  if within_range is None:
6176
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6177
- 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
6178
6164
  s.update(set(product(range(c1, c2), range(0, len(self.row_positions) - 1))))
6179
6165
  if get_cells_as_cols:
6180
6166
  s.update(self.get_selected_cells())
6181
6167
  else:
6182
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6183
- 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
6184
6170
  if c1 >= within_c1 or c2 <= within_c2:
6185
6171
  s.update(
6186
6172
  set(
@@ -6203,14 +6189,14 @@ class MainTable(tk.Canvas):
6203
6189
  )
6204
6190
  else:
6205
6191
  if within_range is None:
6206
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6207
- 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
6208
6194
  s.update(set(range(c1, c2)))
6209
6195
  if get_cells_as_cols:
6210
6196
  s.update(set(tup[1] for tup in self.get_selected_cells()))
6211
6197
  else:
6212
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6213
- 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
6214
6200
  if c1 >= within_c1 or c2 <= within_c2:
6215
6201
  s.update(set(range(c1 if c1 > within_c1 else within_c1, c2 if c2 < within_c2 else within_c2)))
6216
6202
  if get_cells_as_cols:
@@ -6242,12 +6228,12 @@ class MainTable(tk.Canvas):
6242
6228
  within_r2 = within_range[2]
6243
6229
  within_c2 = within_range[3]
6244
6230
  if within_range is None:
6245
- for item in self.get_selection_items(rows=get_rows, columns=get_cols, current=False):
6246
- 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
6247
6233
  s.update(set(product(range(r1, r2), range(c1, c2))))
6248
6234
  else:
6249
- for item in self.get_selection_items(rows=get_rows, columns=get_cols, current=False):
6250
- 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
6251
6237
  if r1 >= within_r1 or c1 >= within_c1 or r2 <= within_r2 or c2 <= within_c2:
6252
6238
  s.update(
6253
6239
  set(
@@ -6260,14 +6246,10 @@ class MainTable(tk.Canvas):
6260
6246
  return s
6261
6247
 
6262
6248
  def get_all_selection_boxes(self) -> tuple[tuple[int, int, int, int]]:
6263
- 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())
6264
6250
 
6265
6251
  def get_all_selection_boxes_with_types(self) -> list[tuple[tuple[int, int, int, int], str]]:
6266
- boxes = []
6267
- for item in self.get_selection_items(current=False):
6268
- tags = self.gettags(item)
6269
- boxes.append((coords_tag_to_int_tuple(tags[1]), tags[0]))
6270
- return boxes
6252
+ return [(box.coords, box.type) for item, box in self.get_selection_items()]
6271
6253
 
6272
6254
  def all_selected(self) -> bool:
6273
6255
  for r1, c1, r2, c2 in self.get_all_selection_boxes():
@@ -6275,8 +6257,6 @@ class MainTable(tk.Canvas):
6275
6257
  return True
6276
6258
  return False
6277
6259
 
6278
- # don't have to use "selected" because you can't
6279
- # have a current without a selection box
6280
6260
  def cell_selected(
6281
6261
  self,
6282
6262
  r: int,
@@ -6286,8 +6266,8 @@ class MainTable(tk.Canvas):
6286
6266
  ) -> bool:
6287
6267
  if not isinstance(r, int) or not isinstance(c, int):
6288
6268
  return False
6289
- for item in self.get_selection_items(rows=inc_rows, columns=inc_cols, current=False):
6290
- 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
6291
6271
  if r1 <= r and c1 <= c and r2 > r and c2 > c:
6292
6272
  return True
6293
6273
  return False
@@ -6295,8 +6275,8 @@ class MainTable(tk.Canvas):
6295
6275
  def col_selected(self, c: int) -> bool:
6296
6276
  if not isinstance(c, int):
6297
6277
  return False
6298
- for item in self.get_selection_items(cells=False, rows=False, current=False):
6299
- 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
6300
6280
  if c1 <= c and c2 > c:
6301
6281
  return True
6302
6282
  return False
@@ -6304,8 +6284,8 @@ class MainTable(tk.Canvas):
6304
6284
  def row_selected(self, r: int) -> bool:
6305
6285
  if not isinstance(r, int):
6306
6286
  return False
6307
- for item in self.get_selection_items(cells=False, columns=False, current=False):
6308
- 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
6309
6289
  if r1 <= r and r2 > r:
6310
6290
  return True
6311
6291
  return False
@@ -6316,24 +6296,25 @@ class MainTable(tk.Canvas):
6316
6296
  exclude_rows: bool = False,
6317
6297
  exclude_cells: bool = False,
6318
6298
  ) -> list[int]:
6319
- return self.get_selection_items(
6320
- columns=not exclude_columns,
6321
- rows=not exclude_rows,
6322
- cells=not exclude_cells,
6323
- current=False,
6324
- )
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
+ ]
6325
6307
 
6326
6308
  def open_cell(
6327
6309
  self,
6328
6310
  event: object = None,
6329
6311
  ignore_existing_editor: bool = False,
6330
6312
  ) -> None:
6331
- 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):
6332
6314
  return
6333
- currently_selected = self.currently_selected()
6334
- if not currently_selected:
6315
+ if not self.selected:
6335
6316
  return
6336
- r, c = int(currently_selected[0]), int(currently_selected[1])
6317
+ r, c = self.selected.row, self.selected.column
6337
6318
  datacn = self.datacn(c)
6338
6319
  datarn = self.datarn(r)
6339
6320
  if self.get_cell_kwargs(datarn, datacn, key="readonly"):
@@ -6413,7 +6394,6 @@ class MainTable(tk.Canvas):
6413
6394
  text = event.char
6414
6395
  else:
6415
6396
  return False
6416
- self.text_editor_loc = (r, c)
6417
6397
  if self.extra_begin_edit_cell_func:
6418
6398
  try:
6419
6399
  text = self.extra_begin_edit_cell_func(
@@ -6422,9 +6402,9 @@ class MainTable(tk.Canvas):
6422
6402
  sheet=self.PAR.name,
6423
6403
  key=extra_func_key,
6424
6404
  value=text,
6425
- loc=tuple(self.text_editor_loc),
6405
+ loc=(r, c),
6426
6406
  boxes=self.get_boxes(),
6427
- selected=self.currently_selected(),
6407
+ selected=self.selected,
6428
6408
  )
6429
6409
  )
6430
6410
  except Exception:
@@ -6436,15 +6416,13 @@ class MainTable(tk.Canvas):
6436
6416
  text = "" if text is None else text
6437
6417
  if self.PAR.ops.cell_auto_resize_enabled:
6438
6418
  self.set_cell_size_to_text(r, c, only_set_if_too_small=True, redraw=True, run_binding=True)
6439
-
6440
- if (r, c) == self.text_editor_loc and self.text_editor is not None:
6441
- 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)
6442
6421
  return
6443
- if self.text_editor is not None:
6444
- self.destroy_text_editor()
6422
+ if self.text_editor.open:
6423
+ self.hide_text_editor()
6445
6424
  if not self.see(r=r, c=c, check_cell_visibility=True):
6446
6425
  self.refresh()
6447
- self.text_editor_loc = (r, c)
6448
6426
  x = self.col_positions[c]
6449
6427
  y = self.row_positions[r]
6450
6428
  w = self.col_positions[c + 1] - x + 1
@@ -6454,9 +6432,8 @@ class MainTable(tk.Canvas):
6454
6432
  c if self.all_columns_displayed else self.displayed_columns[c],
6455
6433
  none_to_empty_str = True)}"""
6456
6434
  bg, fg = self.PAR.ops.table_bg, self.PAR.ops.table_fg
6457
- self.text_editor = TextEditor(
6458
- self,
6459
- menu_kwargs=DotDict(
6435
+ kwargs = {
6436
+ "menu_kwargs": DotDict(
6460
6437
  {
6461
6438
  "font": self.PAR.ops.table_font,
6462
6439
  "foreground": self.PAR.ops.popup_menu_fg,
@@ -6465,35 +6442,40 @@ class MainTable(tk.Canvas):
6465
6442
  "activeforeground": self.PAR.ops.popup_menu_highlight_fg,
6466
6443
  }
6467
6444
  ),
6468
- sheet_ops=self.PAR.ops,
6469
- border_color=self.PAR.ops.table_selected_cells_border_fg,
6470
- text=text,
6471
- state=state,
6472
- width=w,
6473
- height=h,
6474
- show_border=self.PAR.ops.show_selected_cells_border,
6475
- bg=bg,
6476
- fg=fg,
6477
- align=self.get_cell_align(r, c),
6478
- r=r,
6479
- c=c,
6480
- newline_binding=self.text_editor_newline_binding,
6481
- )
6482
- self.text_editor.update_idletasks()
6483
- 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)
6484
6466
  if not dropdown:
6485
- self.text_editor.textedit.focus_set()
6486
- self.text_editor.scroll_to_bottom()
6487
- 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))
6488
6470
  if USER_OS == "darwin":
6489
- 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))
6490
6472
  for key, func in self.text_editor_user_bound_keys.items():
6491
- self.text_editor.textedit.bind(key, func)
6492
- self.text_editor.textedit.bind("<Tab>", lambda _x: self.close_text_editor((r, c, "Tab")))
6493
- 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")))
6494
6476
  if not dropdown:
6495
- self.text_editor.textedit.bind("<FocusOut>", lambda _x: self.close_text_editor((r, c, "FocusOut")))
6496
- 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")))
6497
6479
  return True
6498
6480
 
6499
6481
  # displayed indexes
@@ -6504,80 +6486,69 @@ class MainTable(tk.Canvas):
6504
6486
  event: object = None,
6505
6487
  check_lines: bool = True,
6506
6488
  ) -> None:
6507
- datarn = self.datarn(r)
6508
- datacn = self.datacn(c)
6509
- curr_height = self.text_editor.winfo_height()
6510
- 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:
6511
6491
  new_height = curr_height + self.table_xtra_lines_increment
6512
6492
  space_bot = self.get_space_bot(r)
6513
6493
  if new_height > space_bot:
6514
6494
  new_height = space_bot
6515
6495
  if new_height != curr_height:
6516
- self.text_editor.config(height=new_height)
6517
- kwargs = self.get_cell_kwargs(datarn, datacn, key="dropdown")
6518
- if kwargs:
6519
- 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()
6520
6499
  win_h, anchor = self.get_dropdown_height_anchor(r, c, text_editor_h)
6521
6500
  if anchor == "nw":
6522
6501
  self.coords(
6523
- kwargs["canvas_id"],
6502
+ self.dropdown.canvas_id,
6524
6503
  self.col_positions[c],
6525
6504
  self.row_positions[r] + text_editor_h - 1,
6526
6505
  )
6527
- self.itemconfig(kwargs["canvas_id"], anchor=anchor, height=win_h)
6506
+ self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
6528
6507
  elif anchor == "sw":
6529
6508
  self.coords(
6530
- kwargs["canvas_id"],
6509
+ self.dropdown.canvas_id,
6531
6510
  self.col_positions[c],
6532
6511
  self.row_positions[r],
6533
6512
  )
6534
- self.itemconfig(kwargs["canvas_id"], anchor=anchor, height=win_h)
6513
+ self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
6535
6514
 
6536
6515
  def refresh_open_window_positions(self):
6537
- if self.text_editor is not None:
6538
- r, c = self.text_editor_loc
6539
- 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])
6540
6519
  self.coords(
6541
- self.text_editor_id,
6520
+ self.text_editor.canvas_id,
6542
6521
  self.col_positions[c],
6543
6522
  self.row_positions[r],
6544
6523
  )
6545
- if self.existing_dropdown_window is not None:
6546
- r, c = self.get_existing_dropdown_coords()
6547
- if self.text_editor is None:
6548
- text_editor_h = self.row_positions[r + 1] - self.row_positions[r]
6549
- anchor = self.itemcget(self.existing_dropdown_canvas_id, "anchor")
6550
- win_h = 0
6551
- else:
6552
- 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()
6553
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
6554
6533
  if anchor == "nw":
6555
6534
  self.coords(
6556
- self.existing_dropdown_canvas_id,
6535
+ self.dropdown.canvas_id,
6557
6536
  self.col_positions[c],
6558
6537
  self.row_positions[r] + text_editor_h - 1,
6559
6538
  )
6560
- # self.itemconfig(self.existing_dropdown_canvas_id, anchor=anchor, height=win_h)
6539
+ # self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
6561
6540
  elif anchor == "sw":
6562
6541
  self.coords(
6563
- self.existing_dropdown_canvas_id,
6542
+ self.dropdown.canvas_id,
6564
6543
  self.col_positions[c],
6565
6544
  self.row_positions[r],
6566
6545
  )
6567
- # self.itemconfig(self.existing_dropdown_canvas_id, anchor=anchor, height=win_h)
6546
+ # self.itemconfig(self.dropdown.canvas_id, anchor=anchor, height=win_h)
6568
6547
 
6569
- def destroy_text_editor(self, reason: None | str = None) -> None:
6570
- self.text_editor_loc = None
6571
- try:
6572
- self.delete(self.text_editor_id)
6573
- except Exception:
6574
- pass
6575
- try:
6576
- self.text_editor.destroy()
6577
- except Exception:
6578
- pass
6579
- self.text_editor = None
6580
- 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
6581
6552
  if reason == "Escape":
6582
6553
  self.focus_set()
6583
6554
 
@@ -6589,20 +6560,17 @@ class MainTable(tk.Canvas):
6589
6560
  # checking if text editor should be closed or not
6590
6561
  focused = self.focus_get()
6591
6562
  try:
6592
- if focused == self.text_editor.textedit.rc_popup_menu:
6563
+ if focused == self.text_editor.tktext.rc_popup_menu:
6593
6564
  return "break"
6594
6565
  except Exception:
6595
6566
  pass
6596
6567
  if focused is None and editor_info:
6597
6568
  return "break"
6598
6569
  if editor_info[2] == "Escape":
6599
- self.destroy_text_editor("Escape")
6600
- self.close_dropdown_window()
6570
+ self.hide_text_editor_and_dropdown()
6601
6571
  return
6602
6572
  # setting cell data with text editor value
6603
6573
  self.text_editor_value = self.text_editor.get()
6604
- self.destroy_text_editor()
6605
- currently_selected = self.currently_selected()
6606
6574
  r, c = editor_info[0], editor_info[1]
6607
6575
  datarn, datacn = self.datarn(r), self.datacn(c)
6608
6576
  event_data = event_dict(
@@ -6613,7 +6581,7 @@ class MainTable(tk.Canvas):
6613
6581
  value=self.text_editor_value,
6614
6582
  loc=(r, c),
6615
6583
  boxes=self.get_boxes(),
6616
- selected=currently_selected,
6584
+ selected=self.selected,
6617
6585
  )
6618
6586
  edited = False
6619
6587
  set_data = partial(
@@ -6636,12 +6604,13 @@ class MainTable(tk.Canvas):
6636
6604
  if (
6637
6605
  r is not None
6638
6606
  and c is not None
6639
- and currently_selected
6640
- and r == currently_selected[0]
6641
- and c == currently_selected[1]
6607
+ and self.selected
6608
+ and r == self.selected.row
6609
+ and c == self.selected.column
6642
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))
6643
6612
  ):
6644
- r1, c1, r2, c2 = self.get_box_containing_current()
6613
+ r1, c1, r2, c2 = self.selection_boxes[self.selected.fill_iid].coords
6645
6614
  numcols = c2 - c1
6646
6615
  numrows = r2 - r1
6647
6616
  if numcols == 1 and numrows == 1:
@@ -6689,7 +6658,7 @@ class MainTable(tk.Canvas):
6689
6658
  new_r = r1
6690
6659
  elif numrows > 1:
6691
6660
  new_r = r + 1
6692
- self.move_currently_selected_within_box(new_r, new_c)
6661
+ self.set_currently_selected(new_r, new_c, item=self.selected.fill_iid)
6693
6662
  self.see(
6694
6663
  new_r,
6695
6664
  new_c,
@@ -6697,20 +6666,18 @@ class MainTable(tk.Canvas):
6697
6666
  bottom_right_corner=True,
6698
6667
  check_cell_visibility=True,
6699
6668
  )
6700
- self.close_dropdown_window(r, c)
6701
6669
  self.recreate_all_selection_boxes()
6702
- self.refresh()
6670
+ self.hide_text_editor_and_dropdown()
6703
6671
  if editor_info[2] != "FocusOut":
6704
6672
  self.focus_set()
6705
6673
  return "break"
6706
6674
 
6707
6675
  def tab_key(self, event: object = None) -> str:
6708
- currently_selected = self.currently_selected()
6709
- if not currently_selected:
6676
+ if not self.selected:
6710
6677
  return
6711
- r = currently_selected.row
6712
- c = currently_selected.column
6713
- 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
6714
6681
  numcols = c2 - c1
6715
6682
  numrows = r2 - r1
6716
6683
  if numcols == 1 and numrows == 1:
@@ -6731,7 +6698,7 @@ class MainTable(tk.Canvas):
6731
6698
  new_r = r1
6732
6699
  elif numrows > 1:
6733
6700
  new_r = r + 1
6734
- self.move_currently_selected_within_box(new_r, new_c)
6701
+ self.set_currently_selected(new_r, new_c, item=self.selected.fill_iid)
6735
6702
  self.see(
6736
6703
  new_r,
6737
6704
  new_c,
@@ -6811,8 +6778,7 @@ class MainTable(tk.Canvas):
6811
6778
  c: int,
6812
6779
  event: object = None,
6813
6780
  ) -> None:
6814
- self.destroy_text_editor("Escape")
6815
- self.destroy_opened_dropdown_window()
6781
+ self.hide_text_editor("Escape")
6816
6782
  datarn = self.datarn(r)
6817
6783
  datacn = self.datacn(c)
6818
6784
  kwargs = self.get_cell_kwargs(datarn, datacn, key="dropdown")
@@ -6820,69 +6786,75 @@ class MainTable(tk.Canvas):
6820
6786
  if not self.open_text_editor(event=event, r=r, c=c, dropdown=True):
6821
6787
  return
6822
6788
  win_h, anchor = self.get_dropdown_height_anchor(r, c)
6823
- window = self.PAR.dropdown_class(
6824
- self.winfo_toplevel(),
6825
- r,
6826
- c,
6827
- width=self.col_positions[c + 1] - self.col_positions[c] + 1,
6828
- height=win_h,
6829
- font=self.PAR.ops.table_font,
6830
- colors={
6831
- "bg": self.PAR.ops.popup_menu_bg,
6832
- "fg": self.PAR.ops.popup_menu_fg,
6833
- "highlight_bg": self.PAR.ops.popup_menu_highlight_bg,
6834
- "highlight_fg": self.PAR.ops.popup_menu_highlight_fg,
6835
- },
6836
- outline_color=self.get_selected_box_bg_fg(type_="cells")[1],
6837
- outline_thickness=2,
6838
- values=kwargs["values"],
6839
- close_dropdown_window=self.close_dropdown_window,
6840
- search_function=kwargs["search_function"],
6841
- arrowkey_RIGHT=self.arrowkey_RIGHT,
6842
- arrowkey_LEFT=self.arrowkey_LEFT,
6843
- align="w",
6844
- ) # self.get_cell_align(r, c)
6845
- if kwargs["state"] == "normal":
6846
- if anchor == "nw":
6847
- 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
6848
6792
  else:
6849
- ypos = self.row_positions[r]
6850
- kwargs["canvas_id"] = self.create_window((self.col_positions[c], ypos), window=window, anchor=anchor)
6851
- 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(
6852
6831
  "<<TextModified>>",
6853
- lambda x: window.search_and_see(
6832
+ lambda x: self.dropdown.window.search_and_see(
6854
6833
  event_dict(
6855
6834
  name="table_dropdown_modified",
6856
6835
  sheet=self.PAR.name,
6857
6836
  value=self.text_editor.get(),
6858
6837
  loc=(r, c),
6859
6838
  boxes=self.get_boxes(),
6860
- selected=self.currently_selected(),
6839
+ selected=self.selected,
6861
6840
  )
6862
6841
  ),
6863
6842
  )
6864
6843
  if kwargs["modified_function"] is not None:
6865
- window.modified_function = kwargs["modified_function"]
6844
+ self.dropdown.window.modified_function = kwargs["modified_function"]
6866
6845
  self.update_idletasks()
6867
6846
  try:
6868
- self.after(1, lambda: self.text_editor.textedit.focus())
6869
- 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())
6870
6849
  except Exception:
6871
6850
  return
6872
6851
  redraw = False
6873
6852
  else:
6874
- if anchor == "nw":
6875
- ypos = self.row_positions[r + 1]
6876
- else:
6877
- ypos = self.row_positions[r]
6878
- kwargs["canvas_id"] = self.create_window((self.col_positions[c], ypos), window=window, anchor=anchor)
6879
6853
  self.update_idletasks()
6880
- window.bind("<FocusOut>", lambda x: self.close_dropdown_window(r, c))
6881
- window.focus()
6854
+ self.dropdown.window.bind("<FocusOut>", lambda x: self.close_dropdown_window(r, c))
6855
+ self.dropdown.window.focus()
6882
6856
  redraw = True
6883
- self.existing_dropdown_window = window
6884
- kwargs["window"] = window
6885
- self.existing_dropdown_canvas_id = kwargs["canvas_id"]
6857
+ self.dropdown.open = True
6886
6858
  if redraw:
6887
6859
  self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=False)
6888
6860
 
@@ -6907,7 +6879,7 @@ class MainTable(tk.Canvas):
6907
6879
  value=selection,
6908
6880
  loc=(r, c),
6909
6881
  boxes=self.get_boxes(),
6910
- selected=self.currently_selected(),
6882
+ selected=self.selected,
6911
6883
  )
6912
6884
  if kwargs["select_function"] is not None:
6913
6885
  kwargs["select_function"](event_data)
@@ -6935,26 +6907,20 @@ class MainTable(tk.Canvas):
6935
6907
  try_binding(self.extra_end_edit_cell_func, event_data)
6936
6908
  self.focus_set()
6937
6909
  self.recreate_all_selection_boxes()
6938
- self.destroy_text_editor("Escape")
6939
- 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()
6940
6915
  if redraw:
6941
6916
  self.refresh()
6942
6917
 
6943
- def get_existing_dropdown_coords(self) -> tuple[int, int] | None:
6944
- if self.existing_dropdown_window is not None:
6945
- return int(self.existing_dropdown_window.r), int(self.existing_dropdown_window.c)
6946
- return None
6947
-
6948
- def mouseclick_outside_editor_or_dropdown(self) -> tuple:
6949
- closed_dd_coords = self.get_existing_dropdown_coords()
6950
- if self.text_editor_loc is not None and self.text_editor is not None:
6951
- self.close_text_editor(editor_info=self.text_editor_loc + ("ButtonPress-1",))
6952
- else:
6953
- self.destroy_text_editor("Escape")
6954
- if closed_dd_coords is not None:
6955
- self.destroy_opened_dropdown_window(
6956
- closed_dd_coords[0], closed_dd_coords[1]
6957
- ) # 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()
6958
6924
  return closed_dd_coords
6959
6925
 
6960
6926
  def mouseclick_outside_editor_or_dropdown_all_canvases(self):
@@ -6962,48 +6928,10 @@ class MainTable(tk.Canvas):
6962
6928
  self.RI.mouseclick_outside_editor_or_dropdown()
6963
6929
  return self.mouseclick_outside_editor_or_dropdown()
6964
6930
 
6965
- # function can receive 4 None args
6966
- def destroy_opened_dropdown_window(
6967
- self,
6968
- r: int | None = None,
6969
- c: int | None = None,
6970
- datarn: int | None = None,
6971
- datacn: int | None = None,
6972
- ):
6973
- if r is None and datarn is None and c is None and datacn is None and self.existing_dropdown_window is not None:
6974
- r, c = self.get_existing_dropdown_coords()
6975
- if c is not None or datacn is not None:
6976
- if datacn is None:
6977
- datacn_ = c if self.all_columns_displayed else self.displayed_columns[c]
6978
- else:
6979
- datacn_ = datacn
6980
- else:
6981
- datacn_ = None
6982
- if r is not None or datarn is not None:
6983
- if datarn is None:
6984
- datarn_ = r if self.all_rows_displayed else self.displayed_rows[r]
6985
- else:
6986
- datarn_ = datarn
6987
- else:
6988
- datarn_ = None
6989
- try:
6990
- self.delete(self.existing_dropdown_canvas_id)
6991
- except Exception:
6992
- pass
6993
- self.existing_dropdown_canvas_id = None
6994
- try:
6995
- self.existing_dropdown_window.destroy()
6996
- except Exception:
6997
- pass
6998
- kwargs = self.get_cell_kwargs(datarn_, datacn_, key="dropdown")
6999
- if kwargs:
7000
- kwargs["canvas_id"] = "no dropdown open"
7001
- kwargs["window"] = "no dropdown open"
7002
- try:
7003
- self.delete(kwargs["canvas_id"])
7004
- except Exception:
7005
- pass
7006
- 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
7007
6935
 
7008
6936
  def click_checkbox(
7009
6937
  self,
@@ -7038,7 +6966,7 @@ class MainTable(tk.Canvas):
7038
6966
  value=value,
7039
6967
  loc=(r, c),
7040
6968
  boxes=self.get_boxes(),
7041
- selected=self.currently_selected(),
6969
+ selected=self.selected,
7042
6970
  )
7043
6971
  if kwargs["check_function"] is not None:
7044
6972
  kwargs["check_function"](event_data)
@@ -7068,7 +6996,7 @@ class MainTable(tk.Canvas):
7068
6996
  sheet=self.PAR.name,
7069
6997
  cells_table={(datarn, datacn): self.get_cell_data(datarn, datacn)},
7070
6998
  boxes=self.get_boxes(),
7071
- selected=self.currently_selected(),
6999
+ selected=self.selected,
7072
7000
  )
7073
7001
  if not check_input_valid or self.input_valid_for_cell(datarn, datacn, value):
7074
7002
  if self.undo_enabled and undo:
@@ -7287,11 +7215,11 @@ class MainTable(tk.Canvas):
7287
7215
  return True
7288
7216
  if self.cell_equal_to(datarn, datacn, value, ignore_empty=ignore_empty):
7289
7217
  return False
7290
- if self.get_cell_kwargs(datarn, datacn, key="checkbox"):
7291
- return is_bool_like(value)
7292
7218
  kwargs = self.get_cell_kwargs(datarn, datacn, key="dropdown")
7293
7219
  if kwargs and kwargs["validate_input"] and value not in kwargs["values"]:
7294
7220
  return False
7221
+ if self.get_cell_kwargs(datarn, datacn, key="checkbox"):
7222
+ return is_bool_like(value)
7295
7223
  return True
7296
7224
 
7297
7225
  def cell_equal_to(self, datarn: int, datacn: int, value: object, ignore_empty: bool = False, **kwargs) -> bool: