tksheet 7.4.13__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
@@ -491,7 +491,7 @@ class MainTable(tk.Canvas):
491
491
  def get_find_window_dimensions_coords(self, w_width: int | None) -> tuple[int, int, int, int]:
492
492
  if w_width is None:
493
493
  w_width = self.winfo_width()
494
- width = min(self.get_txt_w("X" * 23), w_width - 7)
494
+ width = min(self.wrap_get_char_w("X") * 23, w_width - 7)
495
495
  height = self.min_row_height
496
496
  if self.find_window.window and self.find_window.window.replace_visible:
497
497
  height *= 2
@@ -706,36 +706,55 @@ class MainTable(tk.Canvas):
706
706
  return find in str(value).lower()
707
707
 
708
708
  def find_within_current_box(
709
- 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,
710
714
  ) -> None | tuple[int, int, int]:
711
- 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(
712
725
  *current_box.coords,
713
- self.selected.row,
714
- self.selected.column,
726
+ start_r,
727
+ start_c,
715
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,
716
734
  )
717
- return next(
718
- (
719
- (r, c, current_box.fill_iid)
720
- for r, c in box_gen_coords(
721
- *current_box.coords,
722
- start_r,
723
- start_c,
724
- reverse=reverse,
725
- all_rows_displayed=self.all_rows_displayed,
726
- all_cols_displayed=self.all_columns_displayed,
727
- displayed_rows=self.displayed_rows,
728
- displayed_cols=self.displayed_columns,
729
- no_wrap=True,
730
- )
731
- if (
735
+ if stop:
736
+ for r, c in iterable:
737
+ if (r, c) == stop:
738
+ return None
739
+ elif (
732
740
  self.find_match(find, r, c) # will not show hidden rows
733
741
  and (self.all_rows_displayed or bisect_in(self.displayed_rows, r))
734
742
  and (self.all_columns_displayed or bisect_in(self.displayed_columns, c))
735
- )
736
- ),
737
- None,
738
- )
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
+ )
739
758
 
740
759
  def find_within_non_current_boxes(self, current_id: int, find: str, reverse: bool) -> None | tuple[int, int, int]:
741
760
  fn = partial(
@@ -791,15 +810,20 @@ class MainTable(tk.Canvas):
791
810
  current_box = self.selection_boxes[self.selected.fill_iid]
792
811
  current_id = self.selected.fill_iid
793
812
  if is_last_cell(*current_box.coords, self.selected.row, self.selected.column, reverse=reverse):
794
- if coord := self.find_within_non_current_boxes(current_id=current_id, find=find, reverse=reverse):
795
- return coord
796
- 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
+ ):
797
816
  return coord
798
817
  else:
799
- if coord := self.find_within_current_box(current_box=current_box, find=find, reverse=reverse):
800
- return coord
801
- 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
+ ):
802
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
803
827
  return None
804
828
 
805
829
  def find_all_cells(self, find: str, reverse: bool = False) -> tuple[int, int, None] | None:
@@ -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)
@@ -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:
@@ -5801,7 +5853,7 @@ class MainTable(tk.Canvas):
5801
5853
  if (lnr := len(r)) > total_columns:
5802
5854
  r = r[:total_columns]
5803
5855
  elif lnr < total_columns:
5804
- 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))
5805
5857
 
5806
5858
  def equalize_data_row_lengths(
5807
5859
  self,
@@ -5816,9 +5868,10 @@ class MainTable(tk.Canvas):
5816
5868
  total_data_cols = max(total_data_cols, len(self.col_positions) - 1)
5817
5869
  if not isinstance(self._headers, int) and include_header and total_data_cols > len(self._headers):
5818
5870
  self.CH.fix_header(total_data_cols - 1)
5871
+ empty_v = self.get_value_for_empty_cell
5819
5872
  for rn, r in enumerate(self.data):
5820
5873
  if total_data_cols > (lnr := len(r)):
5821
- 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))
5822
5875
  return total_data_cols
5823
5876
 
5824
5877
  def get_canvas_visible_area(self) -> tuple[float, float, float, float]:
@@ -6033,7 +6086,7 @@ class MainTable(tk.Canvas):
6033
6086
  else:
6034
6087
  self.itemconfig(iid, fill=fill, outline=outline, state="normal")
6035
6088
  else:
6036
- iid = self.create_rectangle(coords, fill=fill, outline=outline, tags="h")
6089
+ iid = self.create_rectangle(coords, fill=fill, outline=outline)
6037
6090
  self.disp_high[iid] = True
6038
6091
  return True
6039
6092
 
@@ -6043,129 +6096,22 @@ class MainTable(tk.Canvas):
6043
6096
  iid, sh = self.hidd_grid.popitem()
6044
6097
  self.coords(iid, points)
6045
6098
  if sh:
6046
- self.itemconfig(
6047
- iid,
6048
- fill=self.PAR.ops.table_grid_fg,
6049
- width=1,
6050
- capstyle=tk.BUTT,
6051
- joinstyle=tk.ROUND,
6052
- )
6099
+ self.itemconfig(iid, fill=self.PAR.ops.table_grid_fg, width=1, capstyle="butt", joinstyle="round")
6053
6100
  else:
6054
6101
  self.itemconfig(
6055
6102
  iid,
6056
6103
  fill=self.PAR.ops.table_grid_fg,
6057
6104
  width=1,
6058
- capstyle=tk.BUTT,
6059
- joinstyle=tk.ROUND,
6105
+ capstyle="butt",
6106
+ joinstyle="round",
6060
6107
  state="normal",
6061
6108
  )
6062
6109
  else:
6063
6110
  iid = self.create_line(
6064
- points,
6065
- fill=self.PAR.ops.table_grid_fg,
6066
- width=1,
6067
- capstyle=tk.BUTT,
6068
- joinstyle=tk.ROUND,
6069
- tag="g",
6111
+ points, fill=self.PAR.ops.table_grid_fg, width=1, capstyle="butt", joinstyle="round"
6070
6112
  )
6071
6113
  self.disp_grid[iid] = True
6072
6114
 
6073
- def redraw_dropdown(
6074
- self,
6075
- x1: int | float,
6076
- y1: int | float,
6077
- x2: int | float,
6078
- y2: int | float,
6079
- fill: str,
6080
- outline: str,
6081
- draw_outline: bool = True,
6082
- draw_arrow: bool = True,
6083
- open_: bool = False,
6084
- ) -> None:
6085
- if draw_outline and self.PAR.ops.show_dropdown_borders:
6086
- self.redraw_highlight(x1 + 1, y1 + 1, x2, y2, fill="", outline=self.PAR.ops.table_fg)
6087
- if draw_arrow:
6088
- mod = (self.table_txt_height - 1) if self.table_txt_height % 2 else self.table_txt_height
6089
- small_mod = int(mod / 5)
6090
- mid_y = int(self.min_row_height / 2)
6091
- if open_:
6092
- # up arrow
6093
- points = (
6094
- x2 - 4 - small_mod - small_mod - small_mod - small_mod,
6095
- y1 + mid_y + small_mod,
6096
- x2 - 4 - small_mod - small_mod,
6097
- y1 + mid_y - small_mod,
6098
- x2 - 4,
6099
- y1 + mid_y + small_mod,
6100
- )
6101
- else:
6102
- # down arrow
6103
- points = (
6104
- x2 - 4 - small_mod - small_mod - small_mod - small_mod,
6105
- y1 + mid_y - small_mod,
6106
- x2 - 4 - small_mod - small_mod,
6107
- y1 + mid_y + small_mod,
6108
- x2 - 4,
6109
- y1 + mid_y - small_mod,
6110
- )
6111
- if self.hidd_dropdown:
6112
- t, sh = self.hidd_dropdown.popitem()
6113
- self.coords(t, points)
6114
- if sh:
6115
- self.itemconfig(t, fill=fill)
6116
- else:
6117
- self.itemconfig(t, fill=fill, state="normal")
6118
- self.lift(t)
6119
- else:
6120
- t = self.create_line(
6121
- points,
6122
- fill=fill,
6123
- width=2,
6124
- capstyle=tk.ROUND,
6125
- joinstyle=tk.BEVEL,
6126
- )
6127
- self.disp_dropdown[t] = True
6128
-
6129
- def redraw_checkbox(
6130
- self,
6131
- x1: int | float,
6132
- y1: int | float,
6133
- x2: int | float,
6134
- y2: int | float,
6135
- fill: str,
6136
- outline: str,
6137
- draw_check: bool = False,
6138
- ) -> None:
6139
- points = rounded_box_coords(x1, y1, x2, y2)
6140
- if self.hidd_checkbox:
6141
- t, sh = self.hidd_checkbox.popitem()
6142
- self.coords(t, points)
6143
- if sh:
6144
- self.itemconfig(t, fill=outline, outline=fill)
6145
- else:
6146
- self.itemconfig(t, fill=outline, outline=fill, state="normal")
6147
- self.lift(t)
6148
- else:
6149
- t = self.create_polygon(points, fill=outline, outline=fill, smooth=True)
6150
- self.disp_checkbox[t] = True
6151
- if draw_check:
6152
- x1 = x1 + 4
6153
- y1 = y1 + 4
6154
- x2 = x2 - 3
6155
- y2 = y2 - 3
6156
- points = rounded_box_coords(x1, y1, x2, y2, radius=4)
6157
- if self.hidd_checkbox:
6158
- t, sh = self.hidd_checkbox.popitem()
6159
- self.coords(t, points)
6160
- if sh:
6161
- self.itemconfig(t, fill=fill, outline=outline)
6162
- else:
6163
- self.itemconfig(t, fill=fill, outline=outline, state="normal")
6164
- self.lift(t)
6165
- else:
6166
- t = self.create_polygon(points, fill=fill, outline=outline, smooth=True)
6167
- self.disp_checkbox[t] = True
6168
-
6169
6115
  def _auto_resize_columns(self, can_width: float, col_pos_exists: bool) -> bool:
6170
6116
  if self.PAR.ops.auto_resize_columns and self.allow_auto_resize_columns and col_pos_exists:
6171
6117
  max_w = can_width - self.PAR.ops.empty_horizontal
@@ -6308,19 +6254,358 @@ class MainTable(tk.Canvas):
6308
6254
  return cells
6309
6255
 
6310
6256
  def wrap_get_char_w(self, c: str) -> int:
6311
- self.txt_measure_canvas.itemconfig(
6312
- self.txt_measure_canvas_text,
6313
- text=_test_str + c,
6314
- font=self.table_font,
6315
- )
6316
- b = self.txt_measure_canvas.bbox(self.txt_measure_canvas_text)
6317
6257
  if c in self.char_widths[self.table_font]:
6318
6258
  return self.char_widths[self.table_font][c]
6319
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)
6320
6266
  wd = b[2] - b[0] - self.table_test_str_w
6321
6267
  self.char_widths[self.table_font][c] = wd
6322
6268
  return wd
6323
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
+
6324
6609
  def main_table_redraw_grid_and_text(
6325
6610
  self,
6326
6611
  redraw_header: bool = False,
@@ -6361,7 +6646,6 @@ class MainTable(tk.Canvas):
6361
6646
  or setting_views
6362
6647
  ):
6363
6648
  return False
6364
-
6365
6649
  scrollpos_top = self.canvasy(0)
6366
6650
  scrollpos_bot = self.canvasy(can_height)
6367
6651
  scrollpos_left = self.canvasx(0)
@@ -6374,7 +6658,7 @@ class MainTable(tk.Canvas):
6374
6658
  text_end_row = grid_end_row - 1 if grid_end_row == len(self.row_positions) else grid_end_row
6375
6659
  text_start_col = grid_start_col - 1 if grid_start_col else grid_start_col
6376
6660
  text_end_col = grid_end_col - 1 if grid_end_col == len(self.col_positions) else grid_end_col
6377
- # manage find window
6661
+
6378
6662
  if self.find_window.open:
6379
6663
  self.reposition_find_window()
6380
6664
  # check if auto resizing row index
@@ -6386,297 +6670,8 @@ class MainTable(tk.Canvas):
6386
6670
  )
6387
6671
  if resized_cols or resized_rows or changed_w:
6388
6672
  self.recreate_all_selection_boxes()
6389
- if changed_w:
6390
- for widget in (self, self.RI, self.CH, self.TL):
6391
- widget.update_idletasks()
6392
- return
6393
- # important vars
6394
6673
  x_stop = min(last_col_line_pos, scrollpos_right)
6395
6674
  y_stop = min(last_row_line_pos, scrollpos_bot)
6396
- # redraw table
6397
- if redraw_table:
6398
- # reset canvas item storage
6399
- self.hidd_text.update(self.disp_text)
6400
- self.disp_text = {}
6401
- self.hidd_high.update(self.disp_high)
6402
- self.disp_high = {}
6403
- self.hidd_grid.update(self.disp_grid)
6404
- self.disp_grid = {}
6405
- self.hidd_dropdown.update(self.disp_dropdown)
6406
- self.disp_dropdown = {}
6407
- self.hidd_checkbox.update(self.disp_checkbox)
6408
- self.disp_checkbox = {}
6409
- points = []
6410
- # manage horizontal grid lines
6411
- if self.PAR.ops.show_horizontal_grid and row_pos_exists:
6412
- if self.PAR.ops.horizontal_grid_to_end_of_window:
6413
- x_grid_stop = scrollpos_right + can_width
6414
- else:
6415
- x_grid_stop = x_stop + 1 if last_col_line_pos > scrollpos_right else x_stop - 1
6416
- points.extend(
6417
- get_horizontal_gridline_points(
6418
- left=scrollpos_left,
6419
- stop=x_grid_stop,
6420
- positions=self.row_positions,
6421
- start=grid_start_row,
6422
- end=grid_end_row,
6423
- )
6424
- )
6425
- # manage vertical grid lines
6426
- if self.PAR.ops.show_vertical_grid and col_pos_exists:
6427
- if self.PAR.ops.vertical_grid_to_end_of_window:
6428
- y_grid_stop = scrollpos_bot + can_height
6429
- else:
6430
- y_grid_stop = y_stop + 1 if last_row_line_pos > scrollpos_bot else y_stop - 1
6431
- if self.PAR.ops.show_horizontal_grid:
6432
- points.extend([scrollpos_left - 2, grid_end_row, grid_start_col - 2, scrollpos_top - 2])
6433
- points.extend(
6434
- get_vertical_gridline_points(
6435
- top=scrollpos_top,
6436
- stop=y_grid_stop,
6437
- positions=self.col_positions,
6438
- start=grid_start_col,
6439
- end=grid_end_col,
6440
- )
6441
- )
6442
- if points:
6443
- self.redraw_gridline(points)
6444
-
6445
- font = self.PAR.ops.table_font
6446
- dd_coords = self.dropdown.get_coords()
6447
- selections = self.get_redraw_selections(text_start_row, grid_end_row, text_start_col, grid_end_col)
6448
- sel_cells_bg = color_tup(self.PAR.ops.table_selected_cells_bg)
6449
- sel_cols_bg = color_tup(self.PAR.ops.table_selected_columns_bg)
6450
- sel_rows_bg = color_tup(self.PAR.ops.table_selected_rows_bg)
6451
- current_loc = (self.selected.row, self.selected.column) if self.selected else ()
6452
- if self.PAR.ops.alternate_color:
6453
- alternate_color = Highlight(
6454
- bg=self.PAR.ops.alternate_color,
6455
- fg=None,
6456
- end=False,
6457
- )
6458
- if self.selected and box_is_single_cell(*self.selected.box) and self.PAR.ops.show_selected_cells_border:
6459
- dont_blend = current_loc
6460
- else:
6461
- dont_blend = ()
6462
- else:
6463
- alternate_color = None
6464
- dont_blend = ()
6465
- if self.PAR.ops.show_selected_cells_border:
6466
- override = ()
6467
- else:
6468
- override = (
6469
- color_tup(self.PAR.ops.table_selected_cells_fg),
6470
- color_tup(self.PAR.ops.table_selected_columns_fg),
6471
- color_tup(self.PAR.ops.table_selected_rows_fg),
6472
- )
6473
- allow_overflow = self.PAR.ops.allow_cell_overflow
6474
- wrap = self.PAR.ops.table_wrap
6475
- cells = self._redraw_precache_cells(
6476
- text_start_row=text_start_row,
6477
- text_end_row=text_end_row,
6478
- text_start_col=text_start_col,
6479
- text_end_col=text_end_col,
6480
- )
6481
- for r in range(text_start_row, text_end_row):
6482
- rtopgridln = self.row_positions[r]
6483
- rbotgridln = self.row_positions[r + 1]
6484
- datarn = cells["datarn"][r]
6485
-
6486
- for c in range(text_start_col, text_end_col):
6487
- cleftgridln = self.col_positions[c]
6488
- crightgridln = self.col_positions[c + 1]
6489
- datacn = cells["datacn"][c]
6490
- t = (datarn, datacn)
6491
-
6492
- fill, dd_drawn = self.redraw_highlight_get_text_fg(
6493
- r=r,
6494
- c=c,
6495
- fc=cleftgridln,
6496
- fr=rtopgridln,
6497
- sc=crightgridln,
6498
- sr=rbotgridln,
6499
- sel_cells_bg=override[0] if override and (r, c) == current_loc else sel_cells_bg,
6500
- sel_cols_bg=override[1] if override and (r, c) == current_loc else sel_cols_bg,
6501
- sel_rows_bg=override[2] if override and (r, c) == current_loc else sel_rows_bg,
6502
- selections=selections,
6503
- datarn=datarn,
6504
- datacn=datacn,
6505
- can_width=can_width,
6506
- dont_blend=(r, c) == dont_blend,
6507
- alternate_color=alternate_color,
6508
- has_dd=t in cells["dropdown"],
6509
- )
6510
- if t in self.cell_options and "align" in self.cell_options[(datarn, datacn)]:
6511
- align = self.cell_options[(datarn, datacn)]["align"]
6512
- elif datarn in self.row_options and "align" in self.row_options[datarn]:
6513
- align = self.row_options[datarn]["align"]
6514
- elif datacn in self.col_options and "align" in self.col_options[datacn]:
6515
- align = self.col_options[datacn]["align"]
6516
- else:
6517
- align = self.align
6518
-
6519
- kws = cells["dropdown"][t] if t in cells["dropdown"] else None # noqa: SIM401
6520
- if kws:
6521
- max_width = crightgridln - cleftgridln - self.table_txt_height - 5
6522
- if align[-1] == "w":
6523
- draw_x = cleftgridln + 2
6524
- elif align[-1] == "e":
6525
- draw_x = crightgridln - 5 - self.table_txt_height
6526
- elif align[-1] == "n":
6527
- draw_x = cleftgridln + (crightgridln - cleftgridln - self.table_txt_height) / 2
6528
- self.redraw_dropdown(
6529
- cleftgridln,
6530
- rtopgridln,
6531
- crightgridln,
6532
- self.row_positions[r + 1],
6533
- fill=fill if kws["state"] != "disabled" else self.PAR.ops.table_grid_fg,
6534
- outline=fill,
6535
- draw_outline=not dd_drawn,
6536
- draw_arrow=max_width >= 5,
6537
- open_=dd_coords == (r, c),
6538
- )
6539
- else:
6540
- max_width = crightgridln - cleftgridln - 2
6541
- if align[-1] == "w":
6542
- draw_x = cleftgridln + 2
6543
- elif align[-1] == "e":
6544
- draw_x = crightgridln - 2
6545
- elif align[-1] == "n":
6546
- draw_x = cleftgridln + (crightgridln - cleftgridln) / 2
6547
-
6548
- if t in cells["checkbox"]:
6549
- kws = cells["checkbox"][t]
6550
- if max_width > self.table_txt_height + 1:
6551
- box_w = self.table_txt_height + 1
6552
- if align[-1] == "w":
6553
- draw_x += box_w + 3
6554
- elif align[-1] == "n":
6555
- draw_x += box_w / 2 + 1
6556
- max_width -= box_w + 4
6557
- try:
6558
- draw_check = bool(self.data[datarn][datacn])
6559
- except Exception:
6560
- draw_check = False
6561
- self.redraw_checkbox(
6562
- cleftgridln + 2,
6563
- rtopgridln + 2,
6564
- cleftgridln + self.table_txt_height + 3,
6565
- rtopgridln + self.table_txt_height + 3,
6566
- fill=fill if kws["state"] == "normal" else self.PAR.ops.table_grid_fg,
6567
- outline="",
6568
- draw_check=draw_check,
6569
- )
6570
- text = cells[t]
6571
- if not text or (align[-1] == "w" and draw_x > scrollpos_right) or cleftgridln + 5 > scrollpos_right:
6572
- continue
6573
- if allow_overflow and not kws:
6574
- if align[-1] == "w":
6575
- max_width += sum(self._overflow(cells, range(c + 1, text_end_col), datarn))
6576
- elif align[-1] == "e":
6577
- max_width += sum(self._overflow(cells, reversed(range(text_start_col, c)), datarn))
6578
- if max_width <= 1:
6579
- continue
6580
- start_line = max(0, int((scrollpos_top - rtopgridln) / self.table_txt_height))
6581
- draw_y = rtopgridln + 3 + (start_line * self.table_txt_height)
6582
- gen_lines = wrap_text(
6583
- text=text,
6584
- max_width=max_width,
6585
- max_lines=int((rbotgridln - rtopgridln - 2) / self.table_txt_height),
6586
- char_width_fn=self.wrap_get_char_w,
6587
- widths=self.char_widths[font],
6588
- wrap=wrap,
6589
- start_line=start_line,
6590
- )
6591
- if align[-1] == "w" or align[-1] == "e":
6592
- if self.hidd_text:
6593
- iid, showing = self.hidd_text.popitem()
6594
- self.coords(iid, draw_x, draw_y)
6595
- if showing:
6596
- self.itemconfig(
6597
- iid,
6598
- text="\n".join(gen_lines),
6599
- fill=fill,
6600
- font=font,
6601
- anchor=align,
6602
- )
6603
- else:
6604
- self.itemconfig(
6605
- iid,
6606
- text="\n".join(gen_lines),
6607
- fill=fill,
6608
- font=font,
6609
- anchor=align,
6610
- state="normal",
6611
- )
6612
- else:
6613
- iid = self.create_text(
6614
- draw_x,
6615
- draw_y,
6616
- text="\n".join(gen_lines),
6617
- fill=fill,
6618
- font=font,
6619
- anchor=align,
6620
- tags="t",
6621
- )
6622
- self.disp_text[iid] = True
6623
-
6624
- elif align[-1] == "n":
6625
- for t in gen_lines:
6626
- if self.hidd_text:
6627
- iid, showing = self.hidd_text.popitem()
6628
- self.coords(iid, draw_x, draw_y)
6629
- if showing:
6630
- self.itemconfig(
6631
- iid,
6632
- text=t,
6633
- fill=fill,
6634
- font=font,
6635
- anchor=align,
6636
- )
6637
- else:
6638
- self.itemconfig(
6639
- iid,
6640
- text=t,
6641
- fill=fill,
6642
- font=font,
6643
- anchor=align,
6644
- state="normal",
6645
- )
6646
- else:
6647
- iid = self.create_text(
6648
- draw_x,
6649
- draw_y,
6650
- text=t,
6651
- fill=fill,
6652
- font=font,
6653
- anchor=align,
6654
- tags="t",
6655
- )
6656
- self.disp_text[iid] = True
6657
- draw_y += self.table_txt_height
6658
- for dct in (
6659
- self.hidd_text,
6660
- self.hidd_high,
6661
- self.hidd_grid,
6662
- self.hidd_dropdown,
6663
- self.hidd_checkbox,
6664
- ):
6665
- for iid, showing in dct.items():
6666
- if showing:
6667
- self.itemconfig(iid, state="hidden")
6668
- dct[iid] = False
6669
- if self.PAR.ops.show_selected_cells_border:
6670
- for _, box in self.selection_boxes.items():
6671
- if box.bd_iid:
6672
- self.tag_raise(box.bd_iid)
6673
- if self.selected:
6674
- self.tag_raise(self.selected.iid)
6675
- if self.RI.disp_resize_lines:
6676
- self.tag_raise("rh")
6677
- if self.CH.disp_resize_lines:
6678
- self.tag_raise("rw")
6679
- self.tag_raise("t")
6680
6675
  if redraw_header and self.show_header:
6681
6676
  self.CH.redraw_grid_and_text(
6682
6677
  last_col_line_pos=last_col_line_pos,
@@ -6703,6 +6698,29 @@ class MainTable(tk.Canvas):
6703
6698
  row_pos_exists=row_pos_exists,
6704
6699
  set_scrollregion=set_scrollregion,
6705
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
+ )
6706
6724
  event_data = {"sheetname": "", "header": redraw_header, "row_index": redraw_row_index, "table": redraw_table}
6707
6725
  self.PAR.emit_event("<<SheetRedrawn>>", data=event_data)
6708
6726
  return True
@@ -7990,15 +8008,15 @@ class MainTable(tk.Canvas):
7990
8008
  return ""
7991
8009
 
7992
8010
  def get_empty_row_seq(
7993
- self,
7994
- datarn: int,
7995
- end: int,
7996
- start: int = 0,
7997
- r_ops: bool = True,
7998
- c_ops: bool = True,
8011
+ self, datarn: int, end: int, start: int = 0, r_ops: bool = True, c_ops: bool = True
7999
8012
  ) -> list[Any]:
8000
8013
  return [self.get_value_for_empty_cell(datarn, datacn, r_ops=r_ops, c_ops=c_ops) for datacn in range(start, end)]
8001
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
+
8002
8020
  def fix_row_len(self, datarn: int, datacn: int) -> None:
8003
8021
  self.data[datarn].extend(self.get_empty_row_seq(datarn, end=datacn + 1, start=len(self.data[datarn])))
8004
8022