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