tksheet 7.4.12__py3-none-any.whl → 7.4.14__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
@@ -8,7 +8,6 @@ from collections import defaultdict, deque
8
8
  from collections.abc import Callable, Generator, Hashable, Iterator, Sequence
9
9
  from functools import partial
10
10
  from itertools import accumulate, chain, cycle, filterfalse, islice, repeat
11
- from math import ceil, floor
12
11
  from operator import itemgetter
13
12
  from re import IGNORECASE, escape, sub
14
13
  from tkinter import TclError
@@ -75,8 +74,8 @@ from .functions import (
75
74
  mod_event_val,
76
75
  mod_span,
77
76
  mod_span_widget,
78
- move_elements_by_mapping,
79
77
  move_elements_by_mapping_gen,
78
+ move_fast,
80
79
  new_tk_event,
81
80
  next_cell,
82
81
  push_n,
@@ -323,7 +322,7 @@ class MainTable(tk.Canvas):
323
322
  and kwargs["total_rows"] > 0
324
323
  and kwargs["total_cols"] > 0
325
324
  ):
326
- self.data = [list(repeat("", kwargs["total_cols"])) for i in range(kwargs["total_rows"])]
325
+ self.data = [list(repeat("", kwargs["total_cols"])) for _ in range(kwargs["total_rows"])]
327
326
  _header = kwargs["header"] if kwargs["header"] is not None else kwargs["headers"]
328
327
  if isinstance(_header, int):
329
328
  self._headers = _header
@@ -492,7 +491,7 @@ class MainTable(tk.Canvas):
492
491
  def get_find_window_dimensions_coords(self, w_width: int | None) -> tuple[int, int, int, int]:
493
492
  if w_width is None:
494
493
  w_width = self.winfo_width()
495
- width = min(self.get_txt_w("X" * 23), w_width - 7)
494
+ width = min(self.wrap_get_char_w("X") * 23, w_width - 7)
496
495
  height = self.min_row_height
497
496
  if self.find_window.window and self.find_window.window.replace_visible:
498
497
  height *= 2
@@ -707,36 +706,55 @@ class MainTable(tk.Canvas):
707
706
  return find in str(value).lower()
708
707
 
709
708
  def find_within_current_box(
710
- self, current_box: SelectionBox, find: str, reverse: bool
709
+ self,
710
+ current_box: SelectionBox,
711
+ find: str,
712
+ reverse: bool,
713
+ stop: None | tuple[int, int] = None,
711
714
  ) -> None | tuple[int, int, int]:
712
- start_r, start_c = next_cell(
715
+ if stop:
716
+ start_r, start_c = current_box.coords[0], current_box.coords[1]
717
+ else:
718
+ start_r, start_c = next_cell(
719
+ *current_box.coords,
720
+ self.selected.row,
721
+ self.selected.column,
722
+ reverse=reverse,
723
+ )
724
+ iterable = box_gen_coords(
713
725
  *current_box.coords,
714
- self.selected.row,
715
- self.selected.column,
726
+ start_r,
727
+ start_c,
716
728
  reverse=reverse,
729
+ all_rows_displayed=self.all_rows_displayed,
730
+ all_cols_displayed=self.all_columns_displayed,
731
+ displayed_rows=self.displayed_rows,
732
+ displayed_cols=self.displayed_columns,
733
+ no_wrap=True,
717
734
  )
718
- return next(
719
- (
720
- (r, c, current_box.fill_iid)
721
- for r, c in box_gen_coords(
722
- *current_box.coords,
723
- start_r,
724
- start_c,
725
- reverse=reverse,
726
- all_rows_displayed=self.all_rows_displayed,
727
- all_cols_displayed=self.all_columns_displayed,
728
- displayed_rows=self.displayed_rows,
729
- displayed_cols=self.displayed_columns,
730
- no_wrap=True,
731
- )
732
- if (
735
+ if stop:
736
+ for r, c in iterable:
737
+ if (r, c) == stop:
738
+ return None
739
+ elif (
733
740
  self.find_match(find, r, c) # will not show hidden rows
734
741
  and (self.all_rows_displayed or bisect_in(self.displayed_rows, r))
735
742
  and (self.all_columns_displayed or bisect_in(self.displayed_columns, c))
736
- )
737
- ),
738
- None,
739
- )
743
+ ):
744
+ return (r, c, current_box.fill_iid)
745
+ else:
746
+ return next(
747
+ (
748
+ (r, c, current_box.fill_iid)
749
+ for r, c in iterable
750
+ if (
751
+ self.find_match(find, r, c) # will not show hidden rows
752
+ and (self.all_rows_displayed or bisect_in(self.displayed_rows, r))
753
+ and (self.all_columns_displayed or bisect_in(self.displayed_columns, c))
754
+ )
755
+ ),
756
+ None,
757
+ )
740
758
 
741
759
  def find_within_non_current_boxes(self, current_id: int, find: str, reverse: bool) -> None | tuple[int, int, int]:
742
760
  fn = partial(
@@ -792,15 +810,20 @@ class MainTable(tk.Canvas):
792
810
  current_box = self.selection_boxes[self.selected.fill_iid]
793
811
  current_id = self.selected.fill_iid
794
812
  if is_last_cell(*current_box.coords, self.selected.row, self.selected.column, reverse=reverse):
795
- if coord := self.find_within_non_current_boxes(current_id=current_id, find=find, reverse=reverse):
796
- return coord
797
- if coord := self.find_within_current_box(current_box=current_box, find=find, reverse=reverse):
813
+ if (coord := self.find_within_non_current_boxes(current_id=current_id, find=find, reverse=reverse)) or (
814
+ coord := self.find_within_current_box(current_box=current_box, find=find, reverse=reverse)
815
+ ):
798
816
  return coord
799
817
  else:
800
- if coord := self.find_within_current_box(current_box=current_box, find=find, reverse=reverse):
801
- return coord
802
- if coord := self.find_within_non_current_boxes(current_id=current_id, find=find, reverse=reverse):
818
+ if (coord := self.find_within_current_box(current_box=current_box, find=find, reverse=reverse)) or (
819
+ coord := self.find_within_non_current_boxes(current_id=current_id, find=find, reverse=reverse)
820
+ ):
803
821
  return coord
822
+ elif self.selected.row != current_box.coords[0] or self.selected.column != current_box.coords[1]:
823
+ stop = (self.datarn(self.selected.row), self.datacn(self.selected.column))
824
+ coord = self.find_within_current_box(current_box=current_box, find=find, reverse=reverse, stop=stop)
825
+ if coord:
826
+ return coord
804
827
  return None
805
828
 
806
829
  def find_all_cells(self, find: str, reverse: bool = False) -> tuple[int, int, None] | None:
@@ -1498,11 +1521,6 @@ class MainTable(tk.Canvas):
1498
1521
  event_data: EventDataDict | None = None,
1499
1522
  ) -> tuple[dict[int, int], dict[int, int], EventDataDict]:
1500
1523
  self.saved_column_widths = {}
1501
- if not isinstance(totalcols, int):
1502
- totalcols = max(data_new_idxs.values(), default=0)
1503
- if totalcols:
1504
- totalcols += 1
1505
- totalcols = self.equalize_data_row_lengths(at_least_cols=totalcols)
1506
1524
  if not event_data:
1507
1525
  event_data = self.new_event_dict("move_columns", state=True)
1508
1526
  if not event_data["moved"]["columns"]:
@@ -1539,26 +1557,26 @@ class MainTable(tk.Canvas):
1539
1557
  )
1540
1558
  else:
1541
1559
  self.recreate_all_selection_boxes()
1560
+
1542
1561
  if move_data:
1543
- self.data = list(
1544
- map(
1545
- move_elements_by_mapping,
1546
- self.data,
1547
- repeat(data_new_idxs),
1548
- repeat(data_old_idxs),
1549
- ),
1550
- )
1562
+ if not isinstance(totalcols, int):
1563
+ totalcols = max(data_new_idxs.values(), default=0)
1564
+ if totalcols:
1565
+ totalcols += 1
1566
+ totalcols = self.equalize_data_row_lengths(at_least_cols=totalcols)
1567
+
1568
+ self.data = [move_fast(k, data_new_idxs, data_old_idxs) for k in self.data]
1551
1569
  maxidx = len_to_idx(totalcols)
1552
1570
  self.CH.fix_header(maxidx)
1553
1571
  if isinstance(self._headers, list) and self._headers:
1554
- self._headers = move_elements_by_mapping(self._headers, data_new_idxs, data_old_idxs)
1572
+ self._headers = move_fast(self._headers, data_new_idxs, data_old_idxs)
1555
1573
  maxidx = self.get_max_column_idx(maxidx)
1556
- full_new_idxs = self.get_full_new_idxs(
1574
+ full_new_idxs, full_old_idxs = self.get_full_new_idxs(
1557
1575
  max_idx=maxidx,
1558
1576
  new_idxs=data_new_idxs,
1559
1577
  old_idxs=data_old_idxs,
1578
+ get_inverse=True,
1560
1579
  )
1561
- full_old_idxs = dict(zip(full_new_idxs.values(), full_new_idxs))
1562
1580
  self.tagged_cells = {
1563
1581
  tags: {(k[0], full_new_idxs[k[1]]) for k in tagged} for tags, tagged in self.tagged_cells.items()
1564
1582
  }
@@ -1731,14 +1749,14 @@ class MainTable(tk.Canvas):
1731
1749
  data_old_idxs: dict[int, int],
1732
1750
  maxidx: int,
1733
1751
  ) -> None:
1734
- self.data = move_elements_by_mapping(
1752
+ self.data = move_fast(
1735
1753
  self.data,
1736
1754
  data_new_idxs,
1737
1755
  data_old_idxs,
1738
1756
  )
1739
1757
  self.RI.fix_index(maxidx)
1740
1758
  if isinstance(self._row_index, list) and self._row_index:
1741
- self._row_index = move_elements_by_mapping(self._row_index, data_new_idxs, data_old_idxs)
1759
+ self._row_index = move_fast(self._row_index, data_new_idxs, data_old_idxs)
1742
1760
 
1743
1761
  def move_rows_adjust_options_dict(
1744
1762
  self,
@@ -1790,12 +1808,12 @@ class MainTable(tk.Canvas):
1790
1808
  else:
1791
1809
  self.move_rows_data(data_new_idxs, data_old_idxs, maxidx)
1792
1810
  maxidx = self.get_max_row_idx(maxidx)
1793
- full_new_idxs = self.get_full_new_idxs(
1811
+ full_new_idxs, full_old_idxs = self.get_full_new_idxs(
1794
1812
  max_idx=maxidx,
1795
1813
  new_idxs=data_new_idxs,
1796
1814
  old_idxs=data_old_idxs,
1815
+ get_inverse=True,
1797
1816
  )
1798
- full_old_idxs = dict(zip(full_new_idxs.values(), full_new_idxs))
1799
1817
  self.tagged_cells = {
1800
1818
  tags: {(full_new_idxs[k[0]], k[1]) for k in tagged} for tags, tagged in self.tagged_cells.items()
1801
1819
  }
@@ -1956,6 +1974,7 @@ class MainTable(tk.Canvas):
1956
1974
  max_idx: int,
1957
1975
  new_idxs: dict[int, int],
1958
1976
  old_idxs: None | dict[int, int] = None,
1977
+ get_inverse: bool = False,
1959
1978
  ) -> dict[int, int]:
1960
1979
  # return a dict of all row or column indexes
1961
1980
  # old indexes and new indexes, not just the
@@ -1963,13 +1982,18 @@ class MainTable(tk.Canvas):
1963
1982
  # {old index: new index, ...}
1964
1983
  # all the way from 0 to max_idx
1965
1984
  if old_idxs is None:
1966
- old_idxs = dict(zip(new_idxs.values(), new_idxs))
1967
- return dict(
1968
- zip(
1969
- move_elements_by_mapping_gen(tuple(range(max_idx + 1)), new_idxs, old_idxs),
1970
- range(max_idx + 1),
1971
- )
1972
- )
1985
+ old_idxs = {v: k for k, v in new_idxs.items()}
1986
+ if get_inverse:
1987
+ d = {}
1988
+ d_in = {}
1989
+ for v, k in enumerate(move_elements_by_mapping_gen(tuple(range(max_idx + 1)), new_idxs, old_idxs)):
1990
+ d[k] = v
1991
+ d_in[v] = k
1992
+ return d, d_in
1993
+ else:
1994
+ return {
1995
+ k: v for v, k in enumerate(move_elements_by_mapping_gen(tuple(range(max_idx + 1)), new_idxs, old_idxs))
1996
+ }
1973
1997
 
1974
1998
  def undo(self, event: Any = None) -> None | EventDataDict:
1975
1999
  if not self.undo_stack:
@@ -4047,7 +4071,7 @@ class MainTable(tk.Canvas):
4047
4071
  self.yview_scroll(-1, "units")
4048
4072
  self.RI.yview_scroll(-1, "units")
4049
4073
  self.y_move_synced_scrolls("moveto", self.yview()[0])
4050
- self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
4074
+ self.main_table_redraw_grid_and_text(redraw_header=False, redraw_row_index=True)
4051
4075
 
4052
4076
  def shift_mousewheel(self, event: Any) -> None:
4053
4077
  if event.delta < 0 or event.num == 5:
@@ -4060,7 +4084,7 @@ class MainTable(tk.Canvas):
4060
4084
  self.xview_scroll(-1, "units")
4061
4085
  self.CH.xview_scroll(-1, "units")
4062
4086
  self.x_move_synced_scrolls("moveto", self.xview()[0])
4063
- self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
4087
+ self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=False)
4064
4088
 
4065
4089
  def ctrl_mousewheel(self, event: Any) -> None:
4066
4090
  if event.delta < 0 or event.num == 5:
@@ -4235,6 +4259,27 @@ class MainTable(tk.Canvas):
4235
4259
  self.table_txt_width, self.table_txt_height = self.get_txt_dimensions("|", self.PAR.ops.table_font)
4236
4260
  self.min_row_height = max(6, self.table_txt_height, self.index_txt_height) + 6
4237
4261
 
4262
+ # dropdown stuff
4263
+ mod = (self.table_txt_height - 1) if self.table_txt_height % 2 else self.table_txt_height
4264
+ small_mod = int(mod / 5)
4265
+ mid_y = int(self.min_row_height / 2)
4266
+ self.dd_up_arrow = (
4267
+ 4 + 4 * small_mod,
4268
+ mid_y + small_mod,
4269
+ 4 + 2 * small_mod,
4270
+ mid_y - small_mod,
4271
+ 4,
4272
+ mid_y + small_mod,
4273
+ )
4274
+ self.dd_down_arrow = (
4275
+ 4 + 4 * small_mod,
4276
+ mid_y - small_mod,
4277
+ 4 + 2 * small_mod,
4278
+ mid_y + small_mod,
4279
+ 4,
4280
+ mid_y - small_mod,
4281
+ )
4282
+
4238
4283
  def set_index_font(self, newfont: tuple | None = None, row_heights: bool = True) -> tuple[str, int, str]:
4239
4284
  if newfont:
4240
4285
  self.check_font(newfont)
@@ -4441,7 +4486,7 @@ class MainTable(tk.Canvas):
4441
4486
  self.cells_cache = self._redraw_precache_cells(disprn, disprn + 1, 0, len(self.col_positions) - 1)
4442
4487
  if not (align := self.get_cell_kwargs(datarn, datacn, key="align")):
4443
4488
  align = self.align
4444
- if align.endswith("w"):
4489
+ if align[-1] == "w":
4445
4490
  max_width += sum(
4446
4491
  self._overflow(
4447
4492
  self.cells_cache,
@@ -4449,7 +4494,7 @@ class MainTable(tk.Canvas):
4449
4494
  datarn,
4450
4495
  )
4451
4496
  )
4452
- elif align.endswith("e"):
4497
+ elif align[-1] == "e":
4453
4498
  max_width += sum(
4454
4499
  self._overflow(
4455
4500
  self.cells_cache,
@@ -4520,14 +4565,21 @@ class MainTable(tk.Canvas):
4520
4565
  else:
4521
4566
  tw = min_column_width
4522
4567
  h = min_rh
4523
- if self.get_cell_kwargs(
4524
- datarn,
4525
- datacn,
4526
- key="dropdown",
4527
- ) or self.get_cell_kwargs(
4528
- datarn,
4529
- datacn,
4530
- key="checkbox",
4568
+ # self.get_cell_kwargs not used here to boost performance
4569
+ if (
4570
+ (datarn, datacn) in self.cell_options
4571
+ and "dropdown" in self.cell_options[(datarn, datacn)]
4572
+ or datarn in self.row_options
4573
+ and "dropdown" in self.row_options[datarn]
4574
+ or datacn in self.col_options
4575
+ and "dropdown" in self.col_options[datacn]
4576
+ ) or (
4577
+ (datarn, datacn) in self.cell_options
4578
+ and "checkbox" in self.cell_options[(datarn, datacn)]
4579
+ or datarn in self.row_options
4580
+ and "checkbox" in self.row_options[datarn]
4581
+ or datacn in self.col_options
4582
+ and "checkbox" in self.col_options[datacn]
4531
4583
  ):
4532
4584
  tw += qtxth
4533
4585
  if tw > w:
@@ -4768,6 +4820,7 @@ class MainTable(tk.Canvas):
4768
4820
  self,
4769
4821
  rows: list[int] | tuple[int],
4770
4822
  create_ops: bool = True,
4823
+ tree: bool = True,
4771
4824
  ) -> None:
4772
4825
  self.tagged_cells = {
4773
4826
  tags: {(push_n(r, rows), c) for (r, c) in tagged} for tags, tagged in self.tagged_cells.items()
@@ -4777,7 +4830,8 @@ class MainTable(tk.Canvas):
4777
4830
  self.tagged_rows = {tags: {push_n(r, rows) for r in tagged} for tags, tagged in self.tagged_rows.items()}
4778
4831
  self.row_options = {push_n(r, rows): v for r, v in self.row_options.items()}
4779
4832
  self.RI.cell_options = {push_n(r, rows): v for r, v in self.RI.cell_options.items()}
4780
- self.RI.rns = {k: push_n(r, rows) for k, r in self.RI.rns.items()}
4833
+ if tree:
4834
+ self.RI.rns = {k: push_n(r, rows) for k, r in self.RI.rns.items()}
4781
4835
  # if there are named spans where rows were added
4782
4836
  # add options to gap which was created by adding rows
4783
4837
  totalcols = None
@@ -5044,7 +5098,7 @@ class MainTable(tk.Canvas):
5044
5098
  event_data["added"]["rows"] = {
5045
5099
  "table": {},
5046
5100
  "index": {},
5047
- "row_heights": {rn: default_height for rn in range(len(self.row_positions) - 1, maxrn + 1)},
5101
+ "row_heights": dict.fromkeys(range(len(self.row_positions) - 1, maxrn + 1), default_height),
5048
5102
  }
5049
5103
  if not from_undo:
5050
5104
  self.set_row_positions(
@@ -5168,7 +5222,7 @@ class MainTable(tk.Canvas):
5168
5222
  event_data["added"]["columns"] = {
5169
5223
  "table": {},
5170
5224
  "header": {},
5171
- "column_widths": {cn: default_width for cn in range(len(self.col_positions) - 1, maxcn + 1)},
5225
+ "column_widths": dict.fromkeys(range(len(self.col_positions) - 1, maxcn + 1), default_width),
5172
5226
  }
5173
5227
  if not from_undo:
5174
5228
  self.set_col_positions(
@@ -5181,6 +5235,7 @@ class MainTable(tk.Canvas):
5181
5235
  self.adjust_options_post_add_rows(
5182
5236
  rows=tuple(rows),
5183
5237
  create_ops=create_ops,
5238
+ tree=tree,
5184
5239
  )
5185
5240
  event_data["added"]["rows"] = {
5186
5241
  "table": rows,
@@ -5798,7 +5853,7 @@ class MainTable(tk.Canvas):
5798
5853
  if (lnr := len(r)) > total_columns:
5799
5854
  r = r[:total_columns]
5800
5855
  elif lnr < total_columns:
5801
- r += self.get_empty_row_seq(rn, end=total_columns, start=lnr)
5856
+ r.extend(self.gen_empty_row_seq(rn, end=total_columns, start=lnr))
5802
5857
 
5803
5858
  def equalize_data_row_lengths(
5804
5859
  self,
@@ -5813,9 +5868,10 @@ class MainTable(tk.Canvas):
5813
5868
  total_data_cols = max(total_data_cols, len(self.col_positions) - 1)
5814
5869
  if not isinstance(self._headers, int) and include_header and total_data_cols > len(self._headers):
5815
5870
  self.CH.fix_header(total_data_cols - 1)
5871
+ empty_v = self.get_value_for_empty_cell
5816
5872
  for rn, r in enumerate(self.data):
5817
5873
  if total_data_cols > (lnr := len(r)):
5818
- r += self.get_empty_row_seq(rn, end=total_data_cols, start=lnr)
5874
+ r.extend(empty_v(rn, c, r_ops=True, c_ops=True) for c in range(lnr, total_data_cols))
5819
5875
  return total_data_cols
5820
5876
 
5821
5877
  def get_canvas_visible_area(self) -> tuple[float, float, float, float]:
@@ -6030,7 +6086,7 @@ class MainTable(tk.Canvas):
6030
6086
  else:
6031
6087
  self.itemconfig(iid, fill=fill, outline=outline, state="normal")
6032
6088
  else:
6033
- iid = self.create_rectangle(coords, fill=fill, outline=outline, tags="h")
6089
+ iid = self.create_rectangle(coords, fill=fill, outline=outline)
6034
6090
  self.disp_high[iid] = True
6035
6091
  return True
6036
6092
 
@@ -6040,129 +6096,22 @@ class MainTable(tk.Canvas):
6040
6096
  iid, sh = self.hidd_grid.popitem()
6041
6097
  self.coords(iid, points)
6042
6098
  if sh:
6043
- self.itemconfig(
6044
- iid,
6045
- fill=self.PAR.ops.table_grid_fg,
6046
- width=1,
6047
- capstyle=tk.BUTT,
6048
- joinstyle=tk.ROUND,
6049
- )
6099
+ self.itemconfig(iid, fill=self.PAR.ops.table_grid_fg, width=1, capstyle="butt", joinstyle="round")
6050
6100
  else:
6051
6101
  self.itemconfig(
6052
6102
  iid,
6053
6103
  fill=self.PAR.ops.table_grid_fg,
6054
6104
  width=1,
6055
- capstyle=tk.BUTT,
6056
- joinstyle=tk.ROUND,
6105
+ capstyle="butt",
6106
+ joinstyle="round",
6057
6107
  state="normal",
6058
6108
  )
6059
6109
  else:
6060
6110
  iid = self.create_line(
6061
- points,
6062
- fill=self.PAR.ops.table_grid_fg,
6063
- width=1,
6064
- capstyle=tk.BUTT,
6065
- joinstyle=tk.ROUND,
6066
- tag="g",
6111
+ points, fill=self.PAR.ops.table_grid_fg, width=1, capstyle="butt", joinstyle="round"
6067
6112
  )
6068
6113
  self.disp_grid[iid] = True
6069
6114
 
6070
- def redraw_dropdown(
6071
- self,
6072
- x1: int | float,
6073
- y1: int | float,
6074
- x2: int | float,
6075
- y2: int | float,
6076
- fill: str,
6077
- outline: str,
6078
- draw_outline: bool = True,
6079
- draw_arrow: bool = True,
6080
- open_: bool = False,
6081
- ) -> None:
6082
- if draw_outline and self.PAR.ops.show_dropdown_borders:
6083
- self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.PAR.ops.table_fg)
6084
- if draw_arrow:
6085
- mod = (self.table_txt_height - 1) if self.table_txt_height % 2 else self.table_txt_height
6086
- small_mod = int(mod / 5)
6087
- mid_y = floor(self.min_row_height / 2)
6088
- if open_:
6089
- # up arrow
6090
- points = (
6091
- x2 - 4 - small_mod - small_mod - small_mod - small_mod,
6092
- y1 + mid_y + small_mod,
6093
- x2 - 4 - small_mod - small_mod,
6094
- y1 + mid_y - small_mod,
6095
- x2 - 4,
6096
- y1 + mid_y + small_mod,
6097
- )
6098
- else:
6099
- # down arrow
6100
- points = (
6101
- x2 - 4 - small_mod - small_mod - small_mod - small_mod,
6102
- y1 + mid_y - small_mod,
6103
- x2 - 4 - small_mod - small_mod,
6104
- y1 + mid_y + small_mod,
6105
- x2 - 4,
6106
- y1 + mid_y - small_mod,
6107
- )
6108
- if self.hidd_dropdown:
6109
- t, sh = self.hidd_dropdown.popitem()
6110
- self.coords(t, points)
6111
- if sh:
6112
- self.itemconfig(t, fill=fill)
6113
- else:
6114
- self.itemconfig(t, fill=fill, state="normal")
6115
- self.lift(t)
6116
- else:
6117
- t = self.create_line(
6118
- points,
6119
- fill=fill,
6120
- width=2,
6121
- capstyle=tk.ROUND,
6122
- joinstyle=tk.BEVEL,
6123
- )
6124
- self.disp_dropdown[t] = True
6125
-
6126
- def redraw_checkbox(
6127
- self,
6128
- x1: int | float,
6129
- y1: int | float,
6130
- x2: int | float,
6131
- y2: int | float,
6132
- fill: str,
6133
- outline: str,
6134
- draw_check: bool = False,
6135
- ) -> None:
6136
- points = rounded_box_coords(x1, y1, x2, y2)
6137
- if self.hidd_checkbox:
6138
- t, sh = self.hidd_checkbox.popitem()
6139
- self.coords(t, points)
6140
- if sh:
6141
- self.itemconfig(t, fill=outline, outline=fill)
6142
- else:
6143
- self.itemconfig(t, fill=outline, outline=fill, state="normal")
6144
- self.lift(t)
6145
- else:
6146
- t = self.create_polygon(points, fill=outline, outline=fill, smooth=True)
6147
- self.disp_checkbox[t] = True
6148
- if draw_check:
6149
- x1 = x1 + 4
6150
- y1 = y1 + 4
6151
- x2 = x2 - 3
6152
- y2 = y2 - 3
6153
- points = rounded_box_coords(x1, y1, x2, y2, radius=4)
6154
- if self.hidd_checkbox:
6155
- t, sh = self.hidd_checkbox.popitem()
6156
- self.coords(t, points)
6157
- if sh:
6158
- self.itemconfig(t, fill=fill, outline=outline)
6159
- else:
6160
- self.itemconfig(t, fill=fill, outline=outline, state="normal")
6161
- self.lift(t)
6162
- else:
6163
- t = self.create_polygon(points, fill=fill, outline=outline, smooth=True)
6164
- self.disp_checkbox[t] = True
6165
-
6166
6115
  def _auto_resize_columns(self, can_width: float, col_pos_exists: bool) -> bool:
6167
6116
  if self.PAR.ops.auto_resize_columns and self.allow_auto_resize_columns and col_pos_exists:
6168
6117
  max_w = can_width - self.PAR.ops.empty_horizontal
@@ -6283,35 +6232,380 @@ class MainTable(tk.Canvas):
6283
6232
  # self.get_cell_kwargs not used here to boost performance
6284
6233
  if t in self.cell_options and "dropdown" in self.cell_options[t]:
6285
6234
  cells["dropdown"][t] = self.cell_options[t]["dropdown"]
6235
+
6286
6236
  elif datarn in self.row_options and "dropdown" in self.row_options[datarn]:
6287
6237
  cells["dropdown"][t] = self.row_options[datarn]["dropdown"]
6238
+
6288
6239
  elif datacn in self.col_options and "dropdown" in self.col_options[datacn]:
6289
6240
  cells["dropdown"][t] = self.col_options[datacn]["dropdown"]
6241
+
6290
6242
  else:
6291
6243
  if t in self.cell_options and "checkbox" in self.cell_options[t]:
6292
6244
  cells["checkbox"][t] = self.cell_options[t]["checkbox"]
6245
+
6293
6246
  elif datarn in self.row_options and "checkbox" in self.row_options[datarn]:
6294
6247
  cells["checkbox"][t] = self.row_options[datarn]["checkbox"]
6248
+
6295
6249
  elif datacn in self.col_options and "checkbox" in self.col_options[datacn]:
6296
6250
  cells["checkbox"][t] = self.col_options[datacn]["checkbox"]
6297
6251
 
6298
6252
  cells[t] = self.cell_str(datarn, datacn, get_displayed=True)
6253
+
6299
6254
  return cells
6300
6255
 
6301
6256
  def wrap_get_char_w(self, c: str) -> int:
6302
- self.txt_measure_canvas.itemconfig(
6303
- self.txt_measure_canvas_text,
6304
- text=_test_str + c,
6305
- font=self.table_font,
6306
- )
6307
- b = self.txt_measure_canvas.bbox(self.txt_measure_canvas_text)
6308
6257
  if c in self.char_widths[self.table_font]:
6309
6258
  return self.char_widths[self.table_font][c]
6310
6259
  else:
6260
+ self.txt_measure_canvas.itemconfig(
6261
+ self.txt_measure_canvas_text,
6262
+ text=_test_str + c,
6263
+ font=self.table_font,
6264
+ )
6265
+ b = self.txt_measure_canvas.bbox(self.txt_measure_canvas_text)
6311
6266
  wd = b[2] - b[0] - self.table_test_str_w
6312
6267
  self.char_widths[self.table_font][c] = wd
6313
6268
  return wd
6314
6269
 
6270
+ def redraw_grid_and_text(
6271
+ self,
6272
+ last_row_line_pos: float,
6273
+ last_col_line_pos: float,
6274
+ scrollpos_top: int,
6275
+ scrollpos_bot: int,
6276
+ scrollpos_left: int,
6277
+ scrollpos_right: int,
6278
+ x_stop: int | float,
6279
+ y_stop: int | float,
6280
+ col_pos_exists: bool,
6281
+ row_pos_exists: bool,
6282
+ can_width: int,
6283
+ can_height: int,
6284
+ grid_start_row: int,
6285
+ grid_end_row: int,
6286
+ grid_start_col: int,
6287
+ grid_end_col: int,
6288
+ text_start_row: int,
6289
+ text_end_row: int,
6290
+ text_start_col: int,
6291
+ text_end_col: int,
6292
+ ) -> None:
6293
+ # reset canvas item storage
6294
+ self.hidd_text.update(self.disp_text)
6295
+ self.disp_text = {}
6296
+ self.hidd_high.update(self.disp_high)
6297
+ self.disp_high = {}
6298
+ self.hidd_grid.update(self.disp_grid)
6299
+ self.disp_grid = {}
6300
+ self.hidd_dropdown.update(self.disp_dropdown)
6301
+ self.disp_dropdown = {}
6302
+ self.hidd_checkbox.update(self.disp_checkbox)
6303
+ self.disp_checkbox = {}
6304
+ points = []
6305
+ # manage horizontal grid lines
6306
+ if self.PAR.ops.show_horizontal_grid and row_pos_exists:
6307
+ if self.PAR.ops.horizontal_grid_to_end_of_window:
6308
+ x_grid_stop = scrollpos_right + can_width
6309
+ else:
6310
+ x_grid_stop = x_stop + 1 if last_col_line_pos > scrollpos_right else x_stop - 1
6311
+ points.extend(
6312
+ get_horizontal_gridline_points(
6313
+ left=scrollpos_left,
6314
+ stop=x_grid_stop,
6315
+ positions=self.row_positions,
6316
+ start=grid_start_row,
6317
+ end=grid_end_row,
6318
+ )
6319
+ )
6320
+ # manage vertical grid lines
6321
+ if self.PAR.ops.show_vertical_grid and col_pos_exists:
6322
+ if self.PAR.ops.vertical_grid_to_end_of_window:
6323
+ y_grid_stop = scrollpos_bot + can_height
6324
+ else:
6325
+ y_grid_stop = y_stop + 1 if last_row_line_pos > scrollpos_bot else y_stop - 1
6326
+ if self.PAR.ops.show_horizontal_grid:
6327
+ points.extend([scrollpos_left - 2, grid_end_row, grid_start_col - 2, scrollpos_top - 2])
6328
+ points.extend(
6329
+ get_vertical_gridline_points(
6330
+ top=scrollpos_top,
6331
+ stop=y_grid_stop,
6332
+ positions=self.col_positions,
6333
+ start=grid_start_col,
6334
+ end=grid_end_col,
6335
+ )
6336
+ )
6337
+ if points:
6338
+ self.redraw_gridline(points)
6339
+
6340
+ font = self.PAR.ops.table_font
6341
+ dd_coords = self.dropdown.get_coords()
6342
+ selections = self.get_redraw_selections(text_start_row, grid_end_row, text_start_col, grid_end_col)
6343
+ sel_cells_bg = color_tup(self.PAR.ops.table_selected_cells_bg)
6344
+ sel_cols_bg = color_tup(self.PAR.ops.table_selected_columns_bg)
6345
+ sel_rows_bg = color_tup(self.PAR.ops.table_selected_rows_bg)
6346
+ current_loc = (self.selected.row, self.selected.column) if self.selected else ()
6347
+ if self.PAR.ops.alternate_color:
6348
+ alternate_color = Highlight(
6349
+ bg=self.PAR.ops.alternate_color,
6350
+ fg=None,
6351
+ end=False,
6352
+ )
6353
+ if self.selected and box_is_single_cell(*self.selected.box) and self.PAR.ops.show_selected_cells_border:
6354
+ dont_blend = current_loc
6355
+ else:
6356
+ dont_blend = ()
6357
+ else:
6358
+ alternate_color = None
6359
+ dont_blend = ()
6360
+ if self.PAR.ops.show_selected_cells_border:
6361
+ override = ()
6362
+ else:
6363
+ override = (
6364
+ color_tup(self.PAR.ops.table_selected_cells_fg),
6365
+ color_tup(self.PAR.ops.table_selected_columns_fg),
6366
+ color_tup(self.PAR.ops.table_selected_rows_fg),
6367
+ )
6368
+ allow_overflow = self.PAR.ops.allow_cell_overflow
6369
+ wrap = self.PAR.ops.table_wrap
6370
+ cells = self._redraw_precache_cells(
6371
+ text_start_row=text_start_row,
6372
+ text_end_row=text_end_row,
6373
+ text_start_col=text_start_col,
6374
+ text_end_col=text_end_col,
6375
+ )
6376
+
6377
+ # This is a little messy but
6378
+ # we try to avoid any function use to maximise performance
6379
+
6380
+ for r in range(text_start_row, text_end_row):
6381
+ rtopgridln = self.row_positions[r]
6382
+ rbotgridln = self.row_positions[r + 1]
6383
+ datarn = cells["datarn"][r]
6384
+
6385
+ for c in range(text_start_col, text_end_col):
6386
+ cleftgridln = self.col_positions[c]
6387
+ crightgridln = self.col_positions[c + 1]
6388
+ datacn = cells["datacn"][c]
6389
+ disp_loc = (r, c)
6390
+ loc = (datarn, datacn)
6391
+
6392
+ fill, dd_drawn = self.redraw_highlight_get_text_fg(
6393
+ r=r,
6394
+ c=c,
6395
+ fc=cleftgridln,
6396
+ fr=rtopgridln,
6397
+ sc=crightgridln,
6398
+ sr=rbotgridln,
6399
+ sel_cells_bg=override[0] if override and disp_loc == current_loc else sel_cells_bg,
6400
+ sel_cols_bg=override[1] if override and disp_loc == current_loc else sel_cols_bg,
6401
+ sel_rows_bg=override[2] if override and disp_loc == current_loc else sel_rows_bg,
6402
+ selections=selections,
6403
+ datarn=datarn,
6404
+ datacn=datacn,
6405
+ can_width=can_width,
6406
+ dont_blend=disp_loc == dont_blend,
6407
+ alternate_color=alternate_color,
6408
+ has_dd=loc in cells["dropdown"],
6409
+ )
6410
+ if loc in self.cell_options and "align" in self.cell_options[(datarn, datacn)]:
6411
+ align = self.cell_options[(datarn, datacn)]["align"]
6412
+ elif datarn in self.row_options and "align" in self.row_options[datarn]:
6413
+ align = self.row_options[datarn]["align"]
6414
+ elif datacn in self.col_options and "align" in self.col_options[datacn]:
6415
+ align = self.col_options[datacn]["align"]
6416
+ else:
6417
+ align = self.align
6418
+
6419
+ kws = cells["dropdown"][loc] if loc in cells["dropdown"] else None
6420
+ if kws:
6421
+ max_width = crightgridln - cleftgridln - self.table_txt_height - 5
6422
+ if align[-1] == "w":
6423
+ draw_x = cleftgridln + 2
6424
+ elif align[-1] == "e":
6425
+ draw_x = crightgridln - 5 - self.table_txt_height
6426
+ elif align[-1] == "n":
6427
+ draw_x = cleftgridln + (crightgridln - cleftgridln - self.table_txt_height) / 2
6428
+
6429
+ # redraw dropdown
6430
+
6431
+ x1 = cleftgridln
6432
+ y1 = rtopgridln
6433
+ x2 = crightgridln
6434
+ y2 = self.row_positions[r + 1]
6435
+ if not dd_drawn and self.PAR.ops.show_dropdown_borders:
6436
+ self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.PAR.ops.table_fg)
6437
+ if max_width >= 5:
6438
+ if dd_coords == disp_loc:
6439
+ # up arrow
6440
+ points = (
6441
+ x2 - self.dd_up_arrow[0],
6442
+ y1 + self.dd_up_arrow[1],
6443
+ x2 - self.dd_up_arrow[2],
6444
+ y1 + self.dd_up_arrow[3],
6445
+ x2 - self.dd_up_arrow[4],
6446
+ y1 + self.dd_up_arrow[5],
6447
+ )
6448
+ else:
6449
+ # down arrow
6450
+ points = (
6451
+ x2 - self.dd_down_arrow[0],
6452
+ y1 + self.dd_down_arrow[1],
6453
+ x2 - self.dd_down_arrow[2],
6454
+ y1 + self.dd_down_arrow[3],
6455
+ x2 - self.dd_down_arrow[4],
6456
+ y1 + self.dd_down_arrow[5],
6457
+ )
6458
+ _fill = fill if kws["state"] != "disabled" else self.PAR.ops.table_grid_fg
6459
+ if self.hidd_dropdown:
6460
+ cid, sh = self.hidd_dropdown.popitem()
6461
+ self.coords(cid, points)
6462
+ if sh:
6463
+ self.itemconfig(cid, fill=_fill)
6464
+ else:
6465
+ self.itemconfig(cid, fill=_fill, state="normal")
6466
+ else:
6467
+ cid = self.create_line(
6468
+ points, fill=_fill, width=2, capstyle="round", joinstyle="bevel", tag="lift"
6469
+ )
6470
+ self.disp_dropdown[cid] = True
6471
+
6472
+ elif loc in cells["checkbox"]:
6473
+ kws = cells["checkbox"][loc]
6474
+
6475
+ if align[-1] == "w":
6476
+ draw_x = cleftgridln + 2
6477
+ elif align[-1] == "e":
6478
+ draw_x = crightgridln - 2
6479
+ elif align[-1] == "n":
6480
+ draw_x = cleftgridln + (crightgridln - cleftgridln) / 2
6481
+
6482
+ max_width = crightgridln - cleftgridln - 2
6483
+
6484
+ if max_width > self.table_txt_height + 1:
6485
+ box_w = self.table_txt_height + 1
6486
+ if align[-1] == "w":
6487
+ draw_x += box_w + 3
6488
+ elif align[-1] == "n":
6489
+ draw_x += box_w / 2 + 1
6490
+ max_width -= box_w + 4
6491
+ try:
6492
+ draw_check = bool(self.data[datarn][datacn])
6493
+ except Exception:
6494
+ draw_check = False
6495
+
6496
+ # redraw checkbox
6497
+
6498
+ x1 = cleftgridln + 2
6499
+ y1 = rtopgridln + 2
6500
+ x2 = cleftgridln + self.table_txt_height + 3
6501
+ y2 = rtopgridln + self.table_txt_height + 3
6502
+ points = rounded_box_coords(x1, y1, x2, y2)
6503
+ _fill = fill if kws["state"] == "normal" else self.PAR.ops.table_grid_fg
6504
+ if self.hidd_checkbox:
6505
+ cid, sh = self.hidd_checkbox.popitem()
6506
+ self.coords(cid, points)
6507
+ if sh:
6508
+ self.itemconfig(cid, fill="", outline=_fill)
6509
+ else:
6510
+ self.itemconfig(cid, fill="", outline=_fill, state="normal")
6511
+ else:
6512
+ cid = self.create_polygon(points, fill="", outline=_fill, smooth=True, tag="lift")
6513
+ self.disp_checkbox[cid] = True
6514
+ if draw_check:
6515
+ points = rounded_box_coords(x1 + 4, y1 + 4, x2 - 3, y2 - 3, radius=4)
6516
+ if self.hidd_checkbox:
6517
+ cid, sh = self.hidd_checkbox.popitem()
6518
+ self.coords(cid, points)
6519
+ if sh:
6520
+ self.itemconfig(cid, fill=_fill, outline="")
6521
+ else:
6522
+ self.itemconfig(cid, fill=_fill, outline="", state="normal")
6523
+ else:
6524
+ cid = self.create_polygon(points, fill=_fill, outline="", smooth=True, tag="lift")
6525
+ self.disp_checkbox[cid] = True
6526
+
6527
+ else:
6528
+ max_width = crightgridln - cleftgridln - 2
6529
+ if align[-1] == "w":
6530
+ draw_x = cleftgridln + 2
6531
+ elif align[-1] == "e":
6532
+ draw_x = crightgridln - 2
6533
+ elif align[-1] == "n":
6534
+ draw_x = cleftgridln + (crightgridln - cleftgridln) / 2
6535
+
6536
+ # redraw text
6537
+
6538
+ text = cells[loc]
6539
+ if not text or (align[-1] == "w" and draw_x > scrollpos_right) or cleftgridln + 5 > scrollpos_right:
6540
+ continue
6541
+ if allow_overflow and not kws:
6542
+ if align[-1] == "w":
6543
+ max_width += sum(self._overflow(cells, range(c + 1, text_end_col), datarn))
6544
+ elif align[-1] == "e":
6545
+ max_width += sum(self._overflow(cells, reversed(range(text_start_col, c)), datarn))
6546
+ if max_width <= 1:
6547
+ continue
6548
+ start_line = max(0, int((scrollpos_top - rtopgridln) / self.table_txt_height))
6549
+ draw_y = rtopgridln + 3 + (start_line * self.table_txt_height)
6550
+ gen_lines = wrap_text(
6551
+ text=text,
6552
+ max_width=max_width,
6553
+ max_lines=int((rbotgridln - rtopgridln - 2) / self.table_txt_height),
6554
+ char_width_fn=self.wrap_get_char_w,
6555
+ widths=self.char_widths[font],
6556
+ wrap=wrap,
6557
+ start_line=start_line,
6558
+ )
6559
+ if align[-1] == "w" or align[-1] == "e":
6560
+ if self.hidd_text:
6561
+ iid, showing = self.hidd_text.popitem()
6562
+ self.coords(iid, draw_x, draw_y)
6563
+ if showing:
6564
+ self.itemconfig(iid, text="\n".join(gen_lines), fill=fill, font=font, anchor=align)
6565
+ else:
6566
+ self.itemconfig(
6567
+ iid, text="\n".join(gen_lines), fill=fill, font=font, anchor=align, state="normal"
6568
+ )
6569
+ else:
6570
+ iid = self.create_text(
6571
+ draw_x, draw_y, text="\n".join(gen_lines), fill=fill, font=font, anchor=align, tag="lift"
6572
+ )
6573
+ self.disp_text[iid] = True
6574
+
6575
+ elif align[-1] == "n":
6576
+ for t in gen_lines:
6577
+ if self.hidd_text:
6578
+ iid, showing = self.hidd_text.popitem()
6579
+ self.coords(iid, draw_x, draw_y)
6580
+ if showing:
6581
+ self.itemconfig(iid, text=t, fill=fill, font=font, anchor=align)
6582
+ else:
6583
+ self.itemconfig(iid, text=t, fill=fill, font=font, anchor=align, state="normal")
6584
+ else:
6585
+ iid = self.create_text(
6586
+ draw_x, draw_y, text=t, fill=fill, font=font, anchor=align, tag="lift"
6587
+ )
6588
+ self.disp_text[iid] = True
6589
+ draw_y += self.table_txt_height
6590
+ for dct in (
6591
+ self.hidd_text,
6592
+ self.hidd_high,
6593
+ self.hidd_grid,
6594
+ self.hidd_dropdown,
6595
+ self.hidd_checkbox,
6596
+ ):
6597
+ for iid, showing in dct.items():
6598
+ if showing:
6599
+ self.itemconfig(iid, state="hidden")
6600
+ dct[iid] = False
6601
+ if self.PAR.ops.show_selected_cells_border:
6602
+ for _, box in self.selection_boxes.items():
6603
+ if box.bd_iid:
6604
+ self.tag_raise(box.bd_iid)
6605
+ if self.selected:
6606
+ self.tag_raise(self.selected.iid)
6607
+ self.lift("lift")
6608
+
6315
6609
  def main_table_redraw_grid_and_text(
6316
6610
  self,
6317
6611
  redraw_header: bool = False,
@@ -6352,7 +6646,6 @@ class MainTable(tk.Canvas):
6352
6646
  or setting_views
6353
6647
  ):
6354
6648
  return False
6355
-
6356
6649
  scrollpos_top = self.canvasy(0)
6357
6650
  scrollpos_bot = self.canvasy(can_height)
6358
6651
  scrollpos_left = self.canvasx(0)
@@ -6365,7 +6658,7 @@ class MainTable(tk.Canvas):
6365
6658
  text_end_row = grid_end_row - 1 if grid_end_row == len(self.row_positions) else grid_end_row
6366
6659
  text_start_col = grid_start_col - 1 if grid_start_col else grid_start_col
6367
6660
  text_end_col = grid_end_col - 1 if grid_end_col == len(self.col_positions) else grid_end_col
6368
- # manage find window
6661
+
6369
6662
  if self.find_window.open:
6370
6663
  self.reposition_find_window()
6371
6664
  # check if auto resizing row index
@@ -6377,302 +6670,8 @@ class MainTable(tk.Canvas):
6377
6670
  )
6378
6671
  if resized_cols or resized_rows or changed_w:
6379
6672
  self.recreate_all_selection_boxes()
6380
- if changed_w:
6381
- for widget in (self, self.RI, self.CH, self.TL):
6382
- widget.update_idletasks()
6383
- # important vars
6384
6673
  x_stop = min(last_col_line_pos, scrollpos_right)
6385
6674
  y_stop = min(last_row_line_pos, scrollpos_bot)
6386
- # redraw table
6387
- if redraw_table:
6388
- # reset canvas item storage
6389
- self.hidd_text.update(self.disp_text)
6390
- self.disp_text = {}
6391
- self.hidd_high.update(self.disp_high)
6392
- self.disp_high = {}
6393
- self.hidd_grid.update(self.disp_grid)
6394
- self.disp_grid = {}
6395
- self.hidd_dropdown.update(self.disp_dropdown)
6396
- self.disp_dropdown = {}
6397
- self.hidd_checkbox.update(self.disp_checkbox)
6398
- self.disp_checkbox = {}
6399
- points = []
6400
- # manage horizontal grid lines
6401
- if self.PAR.ops.show_horizontal_grid and row_pos_exists:
6402
- if self.PAR.ops.horizontal_grid_to_end_of_window:
6403
- x_grid_stop = scrollpos_right + can_width
6404
- else:
6405
- x_grid_stop = x_stop + 1 if last_col_line_pos > scrollpos_right else x_stop - 1
6406
- points.extend(
6407
- get_horizontal_gridline_points(
6408
- left=scrollpos_left,
6409
- stop=x_grid_stop,
6410
- positions=self.row_positions,
6411
- start=grid_start_row,
6412
- end=grid_end_row,
6413
- )
6414
- )
6415
- # manage vertical grid lines
6416
- if self.PAR.ops.show_vertical_grid and col_pos_exists:
6417
- if self.PAR.ops.vertical_grid_to_end_of_window:
6418
- y_grid_stop = scrollpos_bot + can_height
6419
- else:
6420
- y_grid_stop = y_stop + 1 if last_row_line_pos > scrollpos_bot else y_stop - 1
6421
- if self.PAR.ops.show_horizontal_grid:
6422
- points.extend([scrollpos_left - 2, grid_end_row, grid_start_col - 2, scrollpos_top - 2])
6423
- points.extend(
6424
- get_vertical_gridline_points(
6425
- top=scrollpos_top,
6426
- stop=y_grid_stop,
6427
- positions=self.col_positions,
6428
- start=grid_start_col,
6429
- end=grid_end_col,
6430
- )
6431
- )
6432
- if points:
6433
- self.redraw_gridline(points)
6434
-
6435
- font = self.PAR.ops.table_font
6436
- dd_coords = self.dropdown.get_coords()
6437
- selections = self.get_redraw_selections(text_start_row, grid_end_row, text_start_col, grid_end_col)
6438
- sel_cells_bg = color_tup(self.PAR.ops.table_selected_cells_bg)
6439
- sel_cols_bg = color_tup(self.PAR.ops.table_selected_columns_bg)
6440
- sel_rows_bg = color_tup(self.PAR.ops.table_selected_rows_bg)
6441
- current_loc = (self.selected.row, self.selected.column) if self.selected else ()
6442
- if self.PAR.ops.alternate_color:
6443
- alternate_color = Highlight(
6444
- bg=self.PAR.ops.alternate_color,
6445
- fg=None,
6446
- end=False,
6447
- )
6448
- if self.selected and box_is_single_cell(*self.selected.box) and self.PAR.ops.show_selected_cells_border:
6449
- dont_blend = current_loc
6450
- else:
6451
- dont_blend = ()
6452
- else:
6453
- alternate_color = None
6454
- dont_blend = ()
6455
- if not self.PAR.ops.show_selected_cells_border:
6456
- override = (
6457
- color_tup(self.PAR.ops.table_selected_cells_fg),
6458
- color_tup(self.PAR.ops.table_selected_columns_fg),
6459
- color_tup(self.PAR.ops.table_selected_rows_fg),
6460
- )
6461
- else:
6462
- override = ()
6463
- allow_overflow = self.PAR.ops.allow_cell_overflow
6464
- wrap = self.PAR.ops.table_wrap
6465
- cells = self._redraw_precache_cells(
6466
- text_start_row=text_start_row,
6467
- text_end_row=text_end_row,
6468
- text_start_col=text_start_col,
6469
- text_end_col=text_end_col,
6470
- )
6471
- for r in range(text_start_row, text_end_row):
6472
- rtopgridln = self.row_positions[r]
6473
- rbotgridln = self.row_positions[r + 1]
6474
- datarn = cells["datarn"][r]
6475
-
6476
- for c in range(text_start_col, text_end_col):
6477
- cleftgridln = self.col_positions[c]
6478
- crightgridln = self.col_positions[c + 1]
6479
- datacn = cells["datacn"][c]
6480
- t = (datarn, datacn)
6481
-
6482
- fill, dd_drawn = self.redraw_highlight_get_text_fg(
6483
- r=r,
6484
- c=c,
6485
- fc=cleftgridln,
6486
- fr=rtopgridln,
6487
- sc=crightgridln,
6488
- sr=rbotgridln,
6489
- sel_cells_bg=override[0] if override and (r, c) == current_loc else sel_cells_bg,
6490
- sel_cols_bg=override[1] if override and (r, c) == current_loc else sel_cols_bg,
6491
- sel_rows_bg=override[2] if override and (r, c) == current_loc else sel_rows_bg,
6492
- selections=selections,
6493
- datarn=datarn,
6494
- datacn=datacn,
6495
- can_width=can_width,
6496
- dont_blend=(r, c) == dont_blend,
6497
- alternate_color=alternate_color,
6498
- has_dd=t in cells["dropdown"],
6499
- )
6500
- if t in self.cell_options and "align" in self.cell_options[(datarn, datacn)]:
6501
- align = self.cell_options[(datarn, datacn)]["align"]
6502
- elif datarn in self.row_options and "align" in self.row_options[datarn]:
6503
- align = self.row_options[datarn]["align"]
6504
- elif datacn in self.col_options and "align" in self.col_options[datacn]:
6505
- align = self.col_options[datacn]["align"]
6506
- else:
6507
- align = self.align
6508
-
6509
- kws = cells["dropdown"][t] if t in cells["dropdown"] else None # noqa: SIM401
6510
- if kws:
6511
- max_width = crightgridln - cleftgridln - self.table_txt_height - 5
6512
- if align.endswith("w"):
6513
- draw_x = cleftgridln + 2
6514
- elif align.endswith("e"):
6515
- draw_x = crightgridln - 5 - self.table_txt_height
6516
- elif align.endswith("n"):
6517
- draw_x = cleftgridln + ceil((crightgridln - cleftgridln - self.table_txt_height) / 2)
6518
- self.redraw_dropdown(
6519
- cleftgridln,
6520
- rtopgridln,
6521
- crightgridln,
6522
- self.row_positions[r + 1],
6523
- fill=fill if kws["state"] != "disabled" else self.PAR.ops.table_grid_fg,
6524
- outline=fill,
6525
- draw_outline=not dd_drawn,
6526
- draw_arrow=max_width >= 5,
6527
- open_=dd_coords == (r, c),
6528
- )
6529
- else:
6530
- max_width = crightgridln - cleftgridln - 2
6531
- if align.endswith("w"):
6532
- draw_x = cleftgridln + 2
6533
- elif align.endswith("e"):
6534
- draw_x = crightgridln - 2
6535
- elif align.endswith("n"):
6536
- draw_x = cleftgridln + floor((crightgridln - cleftgridln) / 2)
6537
-
6538
- kws = cells["checkbox"][t] if t in cells["checkbox"] else None # noqa: SIM401
6539
- if kws and max_width > self.table_txt_height + 1:
6540
- box_w = self.table_txt_height + 1
6541
- if align.endswith("w"):
6542
- draw_x += box_w + 3
6543
- elif align.endswith("n"):
6544
- draw_x += ceil(box_w / 2) + 1
6545
- max_width -= box_w + 4
6546
- try:
6547
- draw_check = bool(self.data[datarn][datacn])
6548
- except Exception:
6549
- draw_check = False
6550
- self.redraw_checkbox(
6551
- cleftgridln + 2,
6552
- rtopgridln + 2,
6553
- cleftgridln + self.table_txt_height + 3,
6554
- rtopgridln + self.table_txt_height + 3,
6555
- fill=fill if kws["state"] == "normal" else self.PAR.ops.table_grid_fg,
6556
- outline="",
6557
- draw_check=draw_check,
6558
- )
6559
- text = cells[t]
6560
- if (
6561
- not text
6562
- or (align.endswith("w") and draw_x > scrollpos_right)
6563
- or (align.endswith("e") and cleftgridln + 5 > scrollpos_right)
6564
- or (align.endswith("n") and cleftgridln + 5 > scrollpos_right)
6565
- ):
6566
- continue
6567
- if allow_overflow and not kws:
6568
- if align.endswith("w"):
6569
- max_width += sum(self._overflow(cells, range(c + 1, text_end_col), datarn))
6570
- elif align.endswith("e"):
6571
- max_width += sum(self._overflow(cells, reversed(range(text_start_col, c)), datarn))
6572
- elif align.endswith("n"):
6573
- ...
6574
- if max_width <= 1:
6575
- continue
6576
- start_line = max(0, int((scrollpos_top - rtopgridln) / self.table_txt_height))
6577
- draw_y = rtopgridln + 3 + (start_line * self.table_txt_height)
6578
- gen_lines = wrap_text(
6579
- text=text,
6580
- max_width=max_width,
6581
- max_lines=int((rbotgridln - rtopgridln - 2) / self.table_txt_height),
6582
- char_width_fn=self.wrap_get_char_w,
6583
- widths=self.char_widths[font],
6584
- wrap=wrap,
6585
- start_line=start_line,
6586
- )
6587
- if align.endswith(("w", "e")):
6588
- if self.hidd_text:
6589
- iid, showing = self.hidd_text.popitem()
6590
- self.coords(iid, draw_x, draw_y)
6591
- if showing:
6592
- self.itemconfig(
6593
- iid,
6594
- text="\n".join(gen_lines),
6595
- fill=fill,
6596
- font=font,
6597
- anchor=align,
6598
- )
6599
- else:
6600
- self.itemconfig(
6601
- iid,
6602
- text="\n".join(gen_lines),
6603
- fill=fill,
6604
- font=font,
6605
- anchor=align,
6606
- state="normal",
6607
- )
6608
- else:
6609
- iid = self.create_text(
6610
- draw_x,
6611
- draw_y,
6612
- text="\n".join(gen_lines),
6613
- fill=fill,
6614
- font=font,
6615
- anchor=align,
6616
- tags="t",
6617
- )
6618
- self.disp_text[iid] = True
6619
-
6620
- elif align.endswith("n"):
6621
- for text in gen_lines:
6622
- if self.hidd_text:
6623
- iid, showing = self.hidd_text.popitem()
6624
- self.coords(iid, draw_x, draw_y)
6625
- if showing:
6626
- self.itemconfig(
6627
- iid,
6628
- text=text,
6629
- fill=fill,
6630
- font=font,
6631
- anchor=align,
6632
- )
6633
- else:
6634
- self.itemconfig(
6635
- iid,
6636
- text=text,
6637
- fill=fill,
6638
- font=font,
6639
- anchor=align,
6640
- state="normal",
6641
- )
6642
- else:
6643
- iid = self.create_text(
6644
- draw_x,
6645
- draw_y,
6646
- text=text,
6647
- fill=fill,
6648
- font=font,
6649
- anchor=align,
6650
- tags="t",
6651
- )
6652
- self.disp_text[iid] = True
6653
- draw_y += self.table_txt_height
6654
- for dct in (
6655
- self.hidd_text,
6656
- self.hidd_high,
6657
- self.hidd_grid,
6658
- self.hidd_dropdown,
6659
- self.hidd_checkbox,
6660
- ):
6661
- for iid, showing in dct.items():
6662
- if showing:
6663
- self.itemconfig(iid, state="hidden")
6664
- dct[iid] = False
6665
- if self.PAR.ops.show_selected_cells_border:
6666
- for _, box in self.selection_boxes.items():
6667
- if box.bd_iid:
6668
- self.tag_raise(box.bd_iid)
6669
- if self.selected:
6670
- self.tag_raise(self.selected.iid)
6671
- self.tag_raise("t")
6672
- if self.RI.disp_resize_lines:
6673
- self.tag_raise("rh")
6674
- if self.CH.disp_resize_lines:
6675
- self.tag_raise("rw")
6676
6675
  if redraw_header and self.show_header:
6677
6676
  self.CH.redraw_grid_and_text(
6678
6677
  last_col_line_pos=last_col_line_pos,
@@ -6699,6 +6698,29 @@ class MainTable(tk.Canvas):
6699
6698
  row_pos_exists=row_pos_exists,
6700
6699
  set_scrollregion=set_scrollregion,
6701
6700
  )
6701
+ if redraw_table:
6702
+ self.redraw_grid_and_text(
6703
+ last_row_line_pos=last_row_line_pos,
6704
+ last_col_line_pos=last_col_line_pos,
6705
+ scrollpos_top=scrollpos_top,
6706
+ scrollpos_bot=scrollpos_bot,
6707
+ scrollpos_left=scrollpos_left,
6708
+ scrollpos_right=scrollpos_right,
6709
+ x_stop=x_stop,
6710
+ y_stop=y_stop,
6711
+ col_pos_exists=col_pos_exists,
6712
+ row_pos_exists=row_pos_exists,
6713
+ can_width=can_width,
6714
+ can_height=can_height,
6715
+ grid_start_row=grid_start_row,
6716
+ grid_end_row=grid_end_row,
6717
+ grid_start_col=grid_start_col,
6718
+ grid_end_col=grid_end_col,
6719
+ text_start_row=text_start_row,
6720
+ text_end_row=text_end_row,
6721
+ text_start_col=text_start_col,
6722
+ text_end_col=text_end_col,
6723
+ )
6702
6724
  event_data = {"sheetname": "", "header": redraw_header, "row_index": redraw_row_index, "table": redraw_table}
6703
6725
  self.PAR.emit_event("<<SheetRedrawn>>", data=event_data)
6704
6726
  return True
@@ -6781,7 +6803,7 @@ class MainTable(tk.Canvas):
6781
6803
  box = next(iter(reversed(self.selection_boxes.values())))
6782
6804
  r1, c1, r2, c2 = box.coords
6783
6805
  if r2 - r1 == 1 and c2 - c1 == 1:
6784
- self.itemconfig(box.fill_iid, state="hidden")
6806
+ box.state = "hidden"
6785
6807
  self.set_currently_selected(item=box.fill_iid)
6786
6808
 
6787
6809
  def coords_and_type(self, item: int) -> tuple:
@@ -7117,9 +7139,10 @@ class MainTable(tk.Canvas):
7117
7139
 
7118
7140
  def get_redraw_selections(self, startr: int, endr: int, startc: int, endc: int) -> dict:
7119
7141
  d = defaultdict(set)
7142
+ ignore_hidd_current = not self.PAR.ops.show_selected_cells_border
7120
7143
  for _, box in self.get_selection_items():
7121
7144
  r1, c1, r2, c2 = box.coords
7122
- if box.state == "normal":
7145
+ if box.state == "normal" or ignore_hidd_current:
7123
7146
  if box.type_ == "cells":
7124
7147
  for r in range(startr, endr):
7125
7148
  for c in range(startc, endc):
@@ -7985,15 +8008,15 @@ class MainTable(tk.Canvas):
7985
8008
  return ""
7986
8009
 
7987
8010
  def get_empty_row_seq(
7988
- self,
7989
- datarn: int,
7990
- end: int,
7991
- start: int = 0,
7992
- r_ops: bool = True,
7993
- c_ops: bool = True,
8011
+ self, datarn: int, end: int, start: int = 0, r_ops: bool = True, c_ops: bool = True
7994
8012
  ) -> list[Any]:
7995
8013
  return [self.get_value_for_empty_cell(datarn, datacn, r_ops=r_ops, c_ops=c_ops) for datacn in range(start, end)]
7996
8014
 
8015
+ def gen_empty_row_seq(
8016
+ self, datarn: int, end: int, start: int = 0, r_ops: bool = True, c_ops: bool = True
8017
+ ) -> Generator[Any]:
8018
+ yield from (self.get_value_for_empty_cell(datarn, c, r_ops=r_ops, c_ops=c_ops) for c in range(start, end))
8019
+
7997
8020
  def fix_row_len(self, datarn: int, datacn: int) -> None:
7998
8021
  self.data[datarn].extend(self.get_empty_row_seq(datarn, end=datacn + 1, start=len(self.data[datarn])))
7999
8022
 
@@ -8081,23 +8104,49 @@ class MainTable(tk.Canvas):
8081
8104
  cell value is not in datatypes kwarg
8082
8105
  if get displayed is true then Nones are replaced by
8083
8106
  """
8084
- kwargs = self.get_cell_kwargs(datarn, datacn, key=None)
8085
8107
  if get_displayed:
8086
- if kwargs and "dropdown" in kwargs:
8087
- if kwargs["dropdown"]["text"] is not None:
8088
- return f"{kwargs['dropdown']['text']}"
8089
- elif kwargs and "checkbox" in kwargs:
8090
- return f"{kwargs['checkbox']['text']}"
8108
+ # check for dropdown
8109
+ if (datarn, datacn) in self.cell_options and "dropdown" in self.cell_options[(datarn, datacn)]:
8110
+ kws = self.cell_options[(datarn, datacn)]["dropdown"]
8111
+ elif datarn in self.row_options and "dropdown" in self.row_options[datarn]:
8112
+ kws = self.row_options[datarn]["dropdown"]
8113
+ elif datacn in self.col_options and "dropdown" in self.col_options[datacn]:
8114
+ kws = self.col_options[datacn]["dropdown"]
8115
+ else:
8116
+ kws = None
8117
+ if kws and kws["text"] is not None:
8118
+ return f"{kws['text']}"
8119
+
8120
+ # check for checkbox
8121
+ if (datarn, datacn) in self.cell_options and "checkbox" in self.cell_options[(datarn, datacn)]:
8122
+ kws = self.cell_options[(datarn, datacn)]["checkbox"]
8123
+ elif datarn in self.row_options and "checkbox" in self.row_options[datarn]:
8124
+ kws = self.row_options[datarn]["checkbox"]
8125
+ elif datacn in self.col_options and "checkbox" in self.col_options[datacn]:
8126
+ kws = self.col_options[datacn]["checkbox"]
8127
+ else:
8128
+ kws = None
8129
+ if kws:
8130
+ return f"{kws['text']}"
8091
8131
  try:
8092
8132
  value = self.data[datarn][datacn]
8093
8133
  except Exception:
8094
8134
  value = ""
8095
- if "format" in kwargs:
8096
- if kwargs["format"]["formatter"] is None:
8135
+ # check for format
8136
+ if (datarn, datacn) in self.cell_options and "format" in self.cell_options[(datarn, datacn)]:
8137
+ kws = self.cell_options[(datarn, datacn)]["format"]
8138
+ elif datarn in self.row_options and "format" in self.row_options[datarn]:
8139
+ kws = self.row_options[datarn]["format"]
8140
+ elif datacn in self.col_options and "format" in self.col_options[datacn]:
8141
+ kws = self.col_options[datacn]["format"]
8142
+ else:
8143
+ kws = None
8144
+ if kws:
8145
+ if kws["formatter"] is None:
8097
8146
  if get_displayed:
8098
- return data_to_str(value, **kwargs["format"])
8147
+ return data_to_str(value, **kws)
8099
8148
  else:
8100
- return f"{get_data_with_valid_check(value, **kwargs['format'])}"
8149
+ return f"{get_data_with_valid_check(value, **kws)}"
8101
8150
  else:
8102
8151
  if get_displayed:
8103
8152
  # assumed given formatter class has __str__()
@@ -8106,7 +8155,7 @@ class MainTable(tk.Canvas):
8106
8155
  # assumed given formatter class has get_data_with_valid_check()
8107
8156
  return f"{value.get_data_with_valid_check()}"
8108
8157
  else:
8109
- return "" if value is None else value if isinstance(value, str) else f"{value}"
8158
+ return "" if value is None else str(value)
8110
8159
 
8111
8160
  def get_cell_data(
8112
8161
  self,