tksheet 7.1.6__py3-none-any.whl → 7.1.7__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
@@ -56,7 +56,7 @@ from .functions import (
56
56
  ev_stack_dict,
57
57
  event_dict,
58
58
  gen_formatted,
59
- get_checkbox_points,
59
+ rounded_box_coords,
60
60
  get_new_indexes,
61
61
  get_seq_without_gaps_at_index,
62
62
  index_exists,
@@ -999,101 +999,104 @@ class MainTable(tk.Canvas):
999
999
  tags: {full_new_idxs[k] for k in tagged} for tags, tagged in self.tagged_columns.items()
1000
1000
  }
1001
1001
  self.CH.cell_options = {full_new_idxs[k]: v for k, v in self.CH.cell_options.items()}
1002
- totalrows = self.total_data_rows()
1003
- new_ops = self.PAR.create_options_from_span
1004
- qkspan = self.span()
1005
- for span in self.named_spans.values():
1006
- # span is neither a cell options nor col options span, continue
1007
- if not isinstance(span["from_c"], int):
1008
- continue
1009
- oldupto_colrange, newupto_colrange, newfrom, newupto = span_idxs_post_move(
1010
- data_new_idxs,
1011
- full_new_idxs,
1012
- totalcols,
1013
- span,
1014
- "c",
1015
- )
1016
- # add cell/col kwargs for columns that are new to the span
1017
- old_span_idxs = set(full_new_idxs[k] for k in range(span["from_c"], oldupto_colrange))
1018
- for k in range(newfrom, newupto_colrange):
1019
- if k not in old_span_idxs:
1020
- oldidx = full_old_idxs[k]
1021
- # event_data is used to preserve old cell value
1022
- # in case cells are modified by
1023
- # formatting, checkboxes, dropdown boxes
1024
- if (
1025
- span["type_"] in val_modifying_options
1026
- and span["header"]
1027
- and oldidx not in event_data["cells"]["header"]
1028
- ):
1029
- event_data["cells"]["header"][oldidx] = self.CH.get_cell_data(k)
1030
- # the span targets columns
1031
- if span["from_r"] is None:
1032
- if span["type_"] in val_modifying_options:
1033
- for datarn in range(len(self.data)):
1034
- if (datarn, oldidx) not in event_data["cells"]["table"]:
1035
- event_data["cells"]["table"][(datarn, oldidx)] = self.get_cell_data(datarn, k)
1036
- # create new col options
1037
- new_ops(
1038
- mod_span(
1039
- qkspan,
1040
- span,
1041
- from_c=k,
1042
- upto_c=k + 1,
1043
- )
1044
- )
1045
- # the span targets cells
1046
- else:
1047
- rng_upto_r = totalrows if span["upto_r"] is None else span["upto_r"]
1048
- for datarn in range(span["from_r"], rng_upto_r):
1049
- if (
1050
- span["type_"] in val_modifying_options
1051
- and (datarn, oldidx) not in event_data["cells"]["table"]
1052
- ):
1053
- event_data["cells"]["table"][(datarn, oldidx)] = self.get_cell_data(datarn, k)
1054
- # create new cell options
1002
+ if self.named_spans:
1003
+ totalrows = self.total_data_rows()
1004
+ new_ops = self.PAR.create_options_from_span
1005
+ qkspan = self.span()
1006
+ for span in self.named_spans.values():
1007
+ # span is neither a cell options nor col options span, continue
1008
+ if not isinstance(span["from_c"], int):
1009
+ continue
1010
+ oldupto_colrange, newupto_colrange, newfrom, newupto = span_idxs_post_move(
1011
+ data_new_idxs,
1012
+ full_new_idxs,
1013
+ totalcols,
1014
+ span,
1015
+ "c",
1016
+ )
1017
+ # add cell/col kwargs for columns that are new to the span
1018
+ old_span_idxs = set(full_new_idxs[k] for k in range(span["from_c"], oldupto_colrange))
1019
+ for k in range(newfrom, newupto_colrange):
1020
+ if k not in old_span_idxs:
1021
+ oldidx = full_old_idxs[k]
1022
+ # event_data is used to preserve old cell value
1023
+ # in case cells are modified by
1024
+ # formatting, checkboxes, dropdown boxes
1025
+ if (
1026
+ span["type_"] in val_modifying_options
1027
+ and span["header"]
1028
+ and oldidx not in event_data["cells"]["header"]
1029
+ ):
1030
+ event_data["cells"]["header"][oldidx] = self.CH.get_cell_data(k)
1031
+ # the span targets columns
1032
+ if span["from_r"] is None:
1033
+ if span["type_"] in val_modifying_options:
1034
+ for datarn in range(len(self.data)):
1035
+ if (datarn, oldidx) not in event_data["cells"]["table"]:
1036
+ event_data["cells"]["table"][(datarn, oldidx)] = self.get_cell_data(
1037
+ datarn, k
1038
+ )
1039
+ # create new col options
1055
1040
  new_ops(
1056
1041
  mod_span(
1057
1042
  qkspan,
1058
1043
  span,
1059
- from_r=datarn,
1060
- upto_r=datarn + 1,
1061
1044
  from_c=k,
1062
1045
  upto_c=k + 1,
1063
1046
  )
1064
1047
  )
1065
- # remove span specific kwargs from cells/columns
1066
- # that are no longer in the span,
1067
- # cell options/col options keys are new idxs
1068
- for k in range(span["from_c"], oldupto_colrange):
1069
- # has it moved outside of new span coords
1070
- if (isinstance(newupto, int) and (full_new_idxs[k] < newfrom or full_new_idxs[k] >= newupto)) or (
1071
- newupto is None and full_new_idxs[k] < newfrom
1072
- ):
1073
- # span includes header
1048
+ # the span targets cells
1049
+ else:
1050
+ rng_upto_r = totalrows if span["upto_r"] is None else span["upto_r"]
1051
+ for datarn in range(span["from_r"], rng_upto_r):
1052
+ if (
1053
+ span["type_"] in val_modifying_options
1054
+ and (datarn, oldidx) not in event_data["cells"]["table"]
1055
+ ):
1056
+ event_data["cells"]["table"][(datarn, oldidx)] = self.get_cell_data(datarn, k)
1057
+ # create new cell options
1058
+ new_ops(
1059
+ mod_span(
1060
+ qkspan,
1061
+ span,
1062
+ from_r=datarn,
1063
+ upto_r=datarn + 1,
1064
+ from_c=k,
1065
+ upto_c=k + 1,
1066
+ )
1067
+ )
1068
+ # remove span specific kwargs from cells/columns
1069
+ # that are no longer in the span,
1070
+ # cell options/col options keys are new idxs
1071
+ for k in range(span["from_c"], oldupto_colrange):
1072
+ # has it moved outside of new span coords
1074
1073
  if (
1075
- span["header"]
1076
- and full_new_idxs[k] in self.CH.cell_options
1077
- and span["type_"] in self.CH.cell_options[full_new_idxs[k]]
1078
- ):
1079
- del self.CH.cell_options[full_new_idxs[k]][span["type_"]]
1080
- # span is for col options
1081
- if span["from_r"] is None:
1074
+ isinstance(newupto, int) and (full_new_idxs[k] < newfrom or full_new_idxs[k] >= newupto)
1075
+ ) or (newupto is None and full_new_idxs[k] < newfrom):
1076
+ # span includes header
1082
1077
  if (
1083
- full_new_idxs[k] in self.col_options
1084
- and span["type_"] in self.col_options[full_new_idxs[k]]
1078
+ span["header"]
1079
+ and full_new_idxs[k] in self.CH.cell_options
1080
+ and span["type_"] in self.CH.cell_options[full_new_idxs[k]]
1085
1081
  ):
1086
- del self.col_options[full_new_idxs[k]][span["type_"]]
1087
- # span is for cell options
1088
- else:
1089
- rng_upto_r = totalrows if span["upto_r"] is None else span["upto_r"]
1090
- for r in range(span["from_r"], rng_upto_r):
1091
- if (r, full_new_idxs[k]) in self.cell_options and span["type_"] in self.cell_options[
1092
- (r, full_new_idxs[k])
1093
- ]:
1094
- del self.cell_options[(r, full_new_idxs[k])][span["type_"]]
1095
- # finally, change the span coords
1096
- span["from_c"], span["upto_c"] = newfrom, newupto
1082
+ del self.CH.cell_options[full_new_idxs[k]][span["type_"]]
1083
+ # span is for col options
1084
+ if span["from_r"] is None:
1085
+ if (
1086
+ full_new_idxs[k] in self.col_options
1087
+ and span["type_"] in self.col_options[full_new_idxs[k]]
1088
+ ):
1089
+ del self.col_options[full_new_idxs[k]][span["type_"]]
1090
+ # span is for cell options
1091
+ else:
1092
+ rng_upto_r = totalrows if span["upto_r"] is None else span["upto_r"]
1093
+ for r in range(span["from_r"], rng_upto_r):
1094
+ if (r, full_new_idxs[k]) in self.cell_options and span[
1095
+ "type_"
1096
+ ] in self.cell_options[(r, full_new_idxs[k])]:
1097
+ del self.cell_options[(r, full_new_idxs[k])][span["type_"]]
1098
+ # finally, change the span coords
1099
+ span["from_c"], span["upto_c"] = newfrom, newupto
1097
1100
  if data_indexes:
1098
1101
  self.displayed_columns = sorted(full_new_idxs[k] for k in self.displayed_columns)
1099
1102
  return data_new_idxs, disp_new_idxs, event_data
@@ -1216,101 +1219,104 @@ class MainTable(tk.Canvas):
1216
1219
  self.row_options = {full_new_idxs[k]: v for k, v in self.row_options.items()}
1217
1220
  self.RI.cell_options = {full_new_idxs[k]: v for k, v in self.RI.cell_options.items()}
1218
1221
  self.RI.tree_rns = {v: full_new_idxs[k] for v, k in self.RI.tree_rns.items()}
1219
- totalcols = self.total_data_cols()
1220
- new_ops = self.PAR.create_options_from_span
1221
- qkspan = self.span()
1222
- for span in self.named_spans.values():
1223
- # span is neither a cell options nor row options span, continue
1224
- if not isinstance(span["from_r"], int):
1225
- continue
1226
- oldupto_rowrange, newupto_rowrange, newfrom, newupto = span_idxs_post_move(
1227
- data_new_idxs,
1228
- full_new_idxs,
1229
- totalrows,
1230
- span,
1231
- "r",
1232
- )
1233
- # add cell/row kwargs for rows that are new to the span
1234
- old_span_idxs = set(full_new_idxs[k] for k in range(span["from_r"], oldupto_rowrange))
1235
- for k in range(newfrom, newupto_rowrange):
1236
- if k not in old_span_idxs:
1237
- oldidx = full_old_idxs[k]
1238
- # event_data is used to preserve old cell value
1239
- # in case cells are modified by
1240
- # formatting, checkboxes, dropdown boxes
1241
- if (
1242
- span["type_"] in val_modifying_options
1243
- and span["index"]
1244
- and oldidx not in event_data["cells"]["index"]
1245
- ):
1246
- event_data["cells"]["index"][oldidx] = self.RI.get_cell_data(k)
1247
- # the span targets rows
1248
- if span["from_c"] is None:
1249
- if span["type_"] in val_modifying_options:
1250
- for datacn in range(len(self.data[k])):
1251
- if (oldidx, datacn) not in event_data["cells"]["table"]:
1252
- event_data["cells"]["table"][(oldidx, datacn)] = self.get_cell_data(k, datacn)
1253
- # create new row options
1254
- new_ops(
1255
- mod_span(
1256
- qkspan,
1257
- span,
1258
- from_r=k,
1259
- upto_r=k + 1,
1260
- )
1261
- )
1262
- # the span targets cells
1263
- else:
1264
- rng_upto_c = totalcols if span["upto_c"] is None else span["upto_c"]
1265
- for datacn in range(span["from_c"], rng_upto_c):
1266
- if (
1267
- span["type_"] in val_modifying_options
1268
- and (oldidx, datacn) not in event_data["cells"]["table"]
1269
- ):
1270
- event_data["cells"]["table"][(oldidx, datacn)] = self.get_cell_data(k, datacn)
1271
- # create new cell options
1222
+ if self.named_spans:
1223
+ totalcols = self.total_data_cols()
1224
+ new_ops = self.PAR.create_options_from_span
1225
+ qkspan = self.span()
1226
+ for span in self.named_spans.values():
1227
+ # span is neither a cell options nor row options span, continue
1228
+ if not isinstance(span["from_r"], int):
1229
+ continue
1230
+ oldupto_rowrange, newupto_rowrange, newfrom, newupto = span_idxs_post_move(
1231
+ data_new_idxs,
1232
+ full_new_idxs,
1233
+ totalrows,
1234
+ span,
1235
+ "r",
1236
+ )
1237
+ # add cell/row kwargs for rows that are new to the span
1238
+ old_span_idxs = set(full_new_idxs[k] for k in range(span["from_r"], oldupto_rowrange))
1239
+ for k in range(newfrom, newupto_rowrange):
1240
+ if k not in old_span_idxs:
1241
+ oldidx = full_old_idxs[k]
1242
+ # event_data is used to preserve old cell value
1243
+ # in case cells are modified by
1244
+ # formatting, checkboxes, dropdown boxes
1245
+ if (
1246
+ span["type_"] in val_modifying_options
1247
+ and span["index"]
1248
+ and oldidx not in event_data["cells"]["index"]
1249
+ ):
1250
+ event_data["cells"]["index"][oldidx] = self.RI.get_cell_data(k)
1251
+ # the span targets rows
1252
+ if span["from_c"] is None:
1253
+ if span["type_"] in val_modifying_options:
1254
+ for datacn in range(len(self.data[k])):
1255
+ if (oldidx, datacn) not in event_data["cells"]["table"]:
1256
+ event_data["cells"]["table"][(oldidx, datacn)] = self.get_cell_data(
1257
+ k, datacn
1258
+ )
1259
+ # create new row options
1272
1260
  new_ops(
1273
1261
  mod_span(
1274
1262
  qkspan,
1275
1263
  span,
1276
1264
  from_r=k,
1277
1265
  upto_r=k + 1,
1278
- from_c=datacn,
1279
- upto_c=datacn + 1,
1280
1266
  )
1281
1267
  )
1282
- # remove span specific kwargs from cells/rows
1283
- # that are no longer in the span,
1284
- # cell options/row options keys are new idxs
1285
- for k in range(span["from_r"], oldupto_rowrange):
1286
- # has it moved outside of new span coords
1287
- if (isinstance(newupto, int) and (full_new_idxs[k] < newfrom or full_new_idxs[k] >= newupto)) or (
1288
- newupto is None and full_new_idxs[k] < newfrom
1289
- ):
1290
- # span includes index
1268
+ # the span targets cells
1269
+ else:
1270
+ rng_upto_c = totalcols if span["upto_c"] is None else span["upto_c"]
1271
+ for datacn in range(span["from_c"], rng_upto_c):
1272
+ if (
1273
+ span["type_"] in val_modifying_options
1274
+ and (oldidx, datacn) not in event_data["cells"]["table"]
1275
+ ):
1276
+ event_data["cells"]["table"][(oldidx, datacn)] = self.get_cell_data(k, datacn)
1277
+ # create new cell options
1278
+ new_ops(
1279
+ mod_span(
1280
+ qkspan,
1281
+ span,
1282
+ from_r=k,
1283
+ upto_r=k + 1,
1284
+ from_c=datacn,
1285
+ upto_c=datacn + 1,
1286
+ )
1287
+ )
1288
+ # remove span specific kwargs from cells/rows
1289
+ # that are no longer in the span,
1290
+ # cell options/row options keys are new idxs
1291
+ for k in range(span["from_r"], oldupto_rowrange):
1292
+ # has it moved outside of new span coords
1291
1293
  if (
1292
- span["index"]
1293
- and full_new_idxs[k] in self.RI.cell_options
1294
- and span["type_"] in self.RI.cell_options[full_new_idxs[k]]
1295
- ):
1296
- del self.RI.cell_options[full_new_idxs[k]][span["type_"]]
1297
- # span is for row options
1298
- if span["from_c"] is None:
1294
+ isinstance(newupto, int) and (full_new_idxs[k] < newfrom or full_new_idxs[k] >= newupto)
1295
+ ) or (newupto is None and full_new_idxs[k] < newfrom):
1296
+ # span includes index
1299
1297
  if (
1300
- full_new_idxs[k] in self.row_options
1301
- and span["type_"] in self.row_options[full_new_idxs[k]]
1298
+ span["index"]
1299
+ and full_new_idxs[k] in self.RI.cell_options
1300
+ and span["type_"] in self.RI.cell_options[full_new_idxs[k]]
1302
1301
  ):
1303
- del self.row_options[full_new_idxs[k]][span["type_"]]
1304
- # span is for cell options
1305
- else:
1306
- rng_upto_c = totalcols if span["upto_c"] is None else span["upto_c"]
1307
- for c in range(span["from_c"], rng_upto_c):
1308
- if (full_new_idxs[k], c) in self.cell_options and span["type_"] in self.cell_options[
1309
- (full_new_idxs[k], c)
1310
- ]:
1311
- del self.cell_options[(full_new_idxs[k], c)][span["type_"]]
1312
- # finally, change the span coords
1313
- span["from_r"], span["upto_r"] = newfrom, newupto
1302
+ del self.RI.cell_options[full_new_idxs[k]][span["type_"]]
1303
+ # span is for row options
1304
+ if span["from_c"] is None:
1305
+ if (
1306
+ full_new_idxs[k] in self.row_options
1307
+ and span["type_"] in self.row_options[full_new_idxs[k]]
1308
+ ):
1309
+ del self.row_options[full_new_idxs[k]][span["type_"]]
1310
+ # span is for cell options
1311
+ else:
1312
+ rng_upto_c = totalcols if span["upto_c"] is None else span["upto_c"]
1313
+ for c in range(span["from_c"], rng_upto_c):
1314
+ if (full_new_idxs[k], c) in self.cell_options and span[
1315
+ "type_"
1316
+ ] in self.cell_options[(full_new_idxs[k], c)]:
1317
+ del self.cell_options[(full_new_idxs[k], c)][span["type_"]]
1318
+ # finally, change the span coords
1319
+ span["from_r"], span["upto_r"] = newfrom, newupto
1314
1320
  if data_indexes:
1315
1321
  self.displayed_rows = sorted(full_new_idxs[k] for k in self.displayed_rows)
1316
1322
  return data_new_idxs, disp_new_idxs, event_data
@@ -2785,6 +2791,7 @@ class MainTable(tk.Canvas):
2785
2791
  c = self.identify_col(x=event.x)
2786
2792
  if self.single_selection_enabled and self.not_currently_resizing():
2787
2793
  if r < len(self.row_positions) - 1 and c < len(self.col_positions) - 1:
2794
+ self.being_drawn_item = True
2788
2795
  self.being_drawn_item = self.select_cell(r, c, redraw=True)
2789
2796
  elif self.toggle_selection_enabled and self.not_currently_resizing():
2790
2797
  r = self.identify_row(y=event.y)
@@ -3021,7 +3028,11 @@ class MainTable(tk.Canvas):
3021
3028
  c_to_sel,
3022
3029
  item=self.create_selection_box(
3023
3030
  *to_sel,
3024
- state="hidden" if (to_sel[2] - to_sel[0] == 1 and to_sel[3] - to_sel[1] == 1) else "normal",
3031
+ state=(
3032
+ "hidden"
3033
+ if (to_sel.upto_r - to_sel.from_r == 1 and to_sel.upto_c - to_sel.from_c == 1)
3034
+ else "normal"
3035
+ ),
3025
3036
  set_current=False,
3026
3037
  ),
3027
3038
  )
@@ -5147,7 +5158,7 @@ class MainTable(tk.Canvas):
5147
5158
  tag: str | tuple,
5148
5159
  draw_check: bool = False,
5149
5160
  ) -> None:
5150
- points = get_checkbox_points(x1, y1, x2, y2)
5161
+ points = rounded_box_coords(x1, y1, x2, y2)
5151
5162
  if self.hidd_checkbox:
5152
5163
  t, sh = self.hidd_checkbox.popitem()
5153
5164
  self.coords(t, points)
@@ -5164,7 +5175,7 @@ class MainTable(tk.Canvas):
5164
5175
  y1 = y1 + 4
5165
5176
  x2 = x2 - 3
5166
5177
  y2 = y2 - 3
5167
- points = get_checkbox_points(x1, y1, x2, y2, radius=4)
5178
+ points = rounded_box_coords(x1, y1, x2, y2, radius=4)
5168
5179
  if self.hidd_checkbox:
5169
5180
  t, sh = self.hidd_checkbox.popitem()
5170
5181
  self.coords(t, points)
@@ -5796,24 +5807,34 @@ class MainTable(tk.Canvas):
5796
5807
  state: str,
5797
5808
  tags: str | tuple[str],
5798
5809
  width: int,
5810
+ iid: None | int = None,
5799
5811
  ) -> int:
5800
- if self.hidd_boxes:
5801
- iid = self.hidd_boxes.pop()
5812
+ coords = rounded_box_coords(
5813
+ x1,
5814
+ y1,
5815
+ x2,
5816
+ y2,
5817
+ radius=9 if self.PAR.ops.rounded_boxes else 0,
5818
+ )
5819
+ if isinstance(iid, int):
5802
5820
  self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags, width=width)
5803
- self.coords(iid, x1, y1, x2, y2)
5821
+ self.coords(iid, coords)
5804
5822
  else:
5805
- iid = self.create_rectangle(
5806
- x1,
5807
- y1,
5808
- x2,
5809
- y2,
5810
- fill=fill,
5811
- outline=outline,
5812
- state=state,
5813
- tags=tags,
5814
- width=width,
5815
- )
5816
- self.disp_boxes.add(iid)
5823
+ if self.hidd_boxes:
5824
+ iid = self.hidd_boxes.pop()
5825
+ self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags, width=width)
5826
+ self.coords(iid, coords)
5827
+ else:
5828
+ iid = self.create_polygon(
5829
+ coords,
5830
+ fill=fill,
5831
+ outline=outline,
5832
+ state=state,
5833
+ tags=tags,
5834
+ width=width,
5835
+ smooth=True,
5836
+ )
5837
+ self.disp_boxes.add(iid)
5817
5838
  return iid
5818
5839
 
5819
5840
  def hide_box(self, item: int | None) -> None:
@@ -5866,29 +5887,32 @@ class MainTable(tk.Canvas):
5866
5887
  elif type_ == "columns":
5867
5888
  mt_bg = self.PAR.ops.table_selected_columns_bg
5868
5889
  mt_border_col = self.PAR.ops.table_selected_columns_border_fg
5890
+ if self.selection_boxes:
5891
+ self.itemconfig(next(reversed(self.selection_boxes)), state="normal")
5892
+ x1, y1, x2, y2 = self.box_sheet_coords_x_canvas_coords(r1, c1, r2, c2, type_)
5869
5893
  fill_iid = self.display_box(
5870
- self.col_positions[c1],
5871
- self.row_positions[r1],
5872
- self.canvasx(self.winfo_width()) if self.PAR.ops.selected_rows_to_end_of_window else self.col_positions[c2],
5873
- self.row_positions[r2],
5894
+ x1,
5895
+ y1,
5896
+ x2,
5897
+ y2,
5874
5898
  fill=mt_bg,
5875
5899
  outline="",
5876
- state=state,
5900
+ state=state if self.PAR.ops.show_selected_cells_border else "normal",
5877
5901
  tags=type_,
5878
5902
  width=1,
5879
5903
  )
5880
5904
  index_iid = self.RI.display_box(
5881
- 0,
5882
- self.row_positions[r1],
5905
+ 1,
5906
+ y1,
5883
5907
  self.RI.current_width - 1,
5884
- self.row_positions[r2],
5908
+ y2,
5885
5909
  fill=self.PAR.ops.index_selected_rows_bg if type_ == "rows" else self.PAR.ops.index_selected_cells_bg,
5886
5910
  outline="",
5887
5911
  state="normal",
5888
5912
  tags="cells" if type_ == "columns" else type_,
5889
5913
  )
5890
5914
  header_iid = self.CH.display_box(
5891
- self.col_positions[c1],
5915
+ x1,
5892
5916
  0,
5893
5917
  self.col_positions[c2],
5894
5918
  self.CH.current_height - 1,
@@ -5905,10 +5929,10 @@ class MainTable(tk.Canvas):
5905
5929
  or self.selection_boxes
5906
5930
  ):
5907
5931
  bd_iid = self.display_box(
5908
- self.col_positions[c1],
5909
- self.row_positions[r1],
5910
- self.col_positions[c2],
5911
- self.row_positions[r2],
5932
+ x1,
5933
+ y1,
5934
+ x2,
5935
+ y2,
5912
5936
  fill="",
5913
5937
  outline=mt_border_col,
5914
5938
  state="normal",
@@ -5951,6 +5975,23 @@ class MainTable(tk.Canvas):
5951
5975
  if self.PAR.ops.show_selected_cells_border:
5952
5976
  self.tag_raise(self.selected.iid)
5953
5977
 
5978
+ def box_sheet_coords_x_canvas_coords(
5979
+ self,
5980
+ r1: int,
5981
+ c1: int,
5982
+ r2: int,
5983
+ c2: int,
5984
+ type_: Literal["cells", "rows", "columns"],
5985
+ ) -> tuple[float, float, float, float]:
5986
+ x1 = self.col_positions[c1]
5987
+ y1 = self.row_positions[r1]
5988
+ y2 = self.row_positions[r2]
5989
+ if type_ == "rows" and self.PAR.ops.selected_rows_to_end_of_window:
5990
+ x2 = self.canvasx(self.winfo_width())
5991
+ else:
5992
+ x2 = self.col_positions[c2]
5993
+ return x1, y1, x2, y2
5994
+
5954
5995
  def recreate_selection_box(
5955
5996
  self,
5956
5997
  r1: int,
@@ -5973,66 +6014,53 @@ class MainTable(tk.Canvas):
5973
6014
  mt_bg = self.PAR.ops.table_selected_columns_bg
5974
6015
  mt_border_col = self.PAR.ops.table_selected_columns_border_fg
5975
6016
  if not state:
5976
- state = "normal" if (r2 - r1 > 1 or c2 - c1 > 1) else "hidden"
6017
+ if r2 - r1 > 1 or c2 - c1 > 1:
6018
+ state = "normal"
6019
+ elif next(reversed(self.selection_boxes)) == fill_iid:
6020
+ state = "hidden"
6021
+ else:
6022
+ state = "normal"
5977
6023
  if self.selected.fill_iid == fill_iid:
5978
6024
  self.selected = self.selected._replace(box=Box_nt(r1, c1, r2, c2))
5979
- self.coords(
5980
- fill_iid,
5981
- self.col_positions[c1],
5982
- self.row_positions[r1],
5983
- self.canvasx(self.winfo_width()) if self.PAR.ops.selected_rows_to_end_of_window else self.col_positions[c2],
5984
- self.row_positions[r2],
5985
- )
5986
- self.itemconfig(
5987
- fill_iid,
5988
- fill=mt_bg,
5989
- outline="",
5990
- tags=type_,
5991
- state=state,
5992
- )
5993
- self.RI.coords(
5994
- self.selection_boxes[fill_iid].index,
5995
- 0,
5996
- self.row_positions[r1],
6025
+ x1, y1, x2, y2 = self.box_sheet_coords_x_canvas_coords(r1, c1, r2, c2, type_)
6026
+ self.display_box(x1, y1, x2, y2, fill=mt_bg, outline="", state=state, tags=type_, width=1, iid=fill_iid)
6027
+ self.RI.display_box(
6028
+ 1,
6029
+ y1,
5997
6030
  self.RI.current_width - 1,
5998
- self.row_positions[r2],
5999
- )
6000
- self.RI.itemconfig(
6001
- self.selection_boxes[fill_iid].index,
6031
+ y2,
6002
6032
  fill=self.PAR.ops.index_selected_rows_bg if type_ == "rows" else self.PAR.ops.index_selected_cells_bg,
6003
6033
  outline="",
6034
+ state="normal",
6004
6035
  tags="cells" if type_ == "columns" else type_,
6036
+ iid=self.selection_boxes[fill_iid].index,
6005
6037
  )
6006
- self.CH.coords(
6007
- self.selection_boxes[fill_iid].header,
6008
- self.col_positions[c1],
6038
+ self.CH.display_box(
6039
+ x1,
6009
6040
  0,
6010
6041
  self.col_positions[c2],
6011
6042
  self.CH.current_height - 1,
6012
- )
6013
- self.CH.itemconfig(
6014
- self.selection_boxes[fill_iid].header,
6015
6043
  fill=(
6016
6044
  self.PAR.ops.header_selected_columns_bg if type_ == "columns" else self.PAR.ops.header_selected_cells_bg
6017
6045
  ),
6018
6046
  outline="",
6047
+ state="normal",
6019
6048
  tags="cells" if type_ == "rows" else type_,
6049
+ iid=self.selection_boxes[fill_iid].header,
6020
6050
  )
6021
- if bd_iid := self.selection_boxes[fill_iid].bd_iid:
6051
+ if (bd_iid := self.selection_boxes[fill_iid].bd_iid):
6022
6052
  if self.PAR.ops.show_selected_cells_border:
6023
- self.coords(
6024
- bd_iid,
6025
- self.col_positions[c1],
6026
- self.row_positions[r1],
6027
- self.col_positions[c2],
6028
- self.row_positions[r2],
6029
- )
6030
- self.itemconfig(
6031
- bd_iid,
6053
+ self.display_box(
6054
+ x1,
6055
+ y1,
6056
+ x2,
6057
+ y2,
6032
6058
  fill="",
6033
6059
  outline=mt_border_col,
6034
- tags=f"{type_}bd",
6035
6060
  state="normal",
6061
+ tags=f"{type_}bd",
6062
+ width=1,
6063
+ iid=bd_iid,
6036
6064
  )
6037
6065
  self.tag_raise(bd_iid)
6038
6066
  else:
@@ -6079,23 +6107,23 @@ class MainTable(tk.Canvas):
6079
6107
  self.set_currently_selected(box.coords.from_r, box.coords.from_c, item=box.fill_iid)
6080
6108
 
6081
6109
  def get_redraw_selections(self, startr: int, endr: int, startc: int, endc: int) -> dict:
6082
- d = defaultdict(list)
6110
+ d = defaultdict(set)
6083
6111
  for item, box in self.get_selection_items():
6084
- d[box.type_].append(box.coords)
6085
- d2 = {}
6086
- if "cells" in d:
6087
- d2["cells"] = {
6088
- (r, c)
6089
- for r in range(startr, endr)
6090
- for c in range(startc, endc)
6091
- for r1, c1, r2, c2 in d["cells"]
6092
- if r1 <= r and c1 <= c and r2 > r and c2 > c
6093
- }
6094
- if "rows" in d:
6095
- d2["rows"] = {r for r in range(startr, endr) for r1, c1, r2, c2 in d["rows"] if r1 <= r and r2 > r}
6096
- if "columns" in d:
6097
- d2["columns"] = {c for c in range(startc, endc) for r1, c1, r2, c2 in d["columns"] if c1 <= c and c2 > c}
6098
- return d2
6112
+ r1, c1, r2, c2 = box.coords
6113
+ if box.type_ == "cells":
6114
+ for r in range(startr, endr):
6115
+ for c in range(startc, endc):
6116
+ if r1 <= r and c1 <= c and r2 > r and c2 > c:
6117
+ d["cells"].add((r, c))
6118
+ elif box.type_ == "rows":
6119
+ for r in range(startr, endr):
6120
+ if r1 <= r and r2 > r:
6121
+ d["rows"].add(r)
6122
+ elif box.type_ == "columns":
6123
+ for c in range(startc, endc):
6124
+ if c1 <= c and c2 > c:
6125
+ d["columns"].add(c)
6126
+ return d
6099
6127
 
6100
6128
  def get_selected_min_max(self) -> tuple[int, int, int, int] | tuple[None, None, None, None]:
6101
6129
  min_x = float("inf")
@@ -6599,6 +6627,8 @@ class MainTable(tk.Canvas):
6599
6627
 
6600
6628
  def hide_text_editor(self, reason: None | str = None) -> None:
6601
6629
  if self.text_editor.open:
6630
+ for b in ("<Alt-Return>", "<Option-Return>", "<Tab>", "<Return>", "<FocusOut>", "<Escape>"):
6631
+ self.text_editor.tktext.unbind(b)
6602
6632
  self.itemconfig(self.text_editor.canvas_id, state="hidden")
6603
6633
  self.text_editor.open = False
6604
6634
  if reason == "Escape":
@@ -6621,15 +6651,15 @@ class MainTable(tk.Canvas):
6621
6651
  self.hide_text_editor_and_dropdown()
6622
6652
  return
6623
6653
  # setting cell data with text editor value
6624
- self.text_editor_value = self.text_editor.get()
6654
+ text_editor_value = self.text_editor.get()
6625
6655
  r, c = editor_info[0], editor_info[1]
6626
6656
  datarn, datacn = self.datarn(r), self.datacn(c)
6627
6657
  event_data = event_dict(
6628
6658
  name="end_edit_table",
6629
6659
  sheet=self.PAR.name,
6630
- cells_table={(datarn, datacn): self.text_editor_value},
6660
+ cells_table={(datarn, datacn): text_editor_value},
6631
6661
  key=editor_info[2],
6632
- value=self.text_editor_value,
6662
+ value=text_editor_value,
6633
6663
  loc=(r, c),
6634
6664
  boxes=self.get_boxes(),
6635
6665
  selected=self.selected,
@@ -6645,11 +6675,11 @@ class MainTable(tk.Canvas):
6645
6675
  check_input_valid=False,
6646
6676
  )
6647
6677
  if self.edit_validation_func:
6648
- self.text_editor_value = self.edit_validation_func(event_data)
6649
- if self.text_editor_value is not None and self.input_valid_for_cell(datarn, datacn, self.text_editor_value):
6650
- edited = set_data(value=self.text_editor_value)
6651
- elif self.input_valid_for_cell(datarn, datacn, self.text_editor_value):
6652
- edited = set_data(value=self.text_editor_value)
6678
+ text_editor_value = self.edit_validation_func(event_data)
6679
+ if text_editor_value is not None and self.input_valid_for_cell(datarn, datacn, text_editor_value):
6680
+ edited = set_data(value=text_editor_value)
6681
+ elif self.input_valid_for_cell(datarn, datacn, text_editor_value):
6682
+ edited = set_data(value=text_editor_value)
6653
6683
  if edited:
6654
6684
  try_binding(self.extra_end_edit_cell_func, event_data)
6655
6685
  if (
@@ -6659,7 +6689,7 @@ class MainTable(tk.Canvas):
6659
6689
  and r == self.selected.row
6660
6690
  and c == self.selected.column
6661
6691
  and (self.single_selection_enabled or self.toggle_selection_enabled)
6662
- and (edited or self.cell_equal_to(datarn, datacn, self.text_editor_value))
6692
+ and (edited or self.cell_equal_to(datarn, datacn, text_editor_value))
6663
6693
  ):
6664
6694
  r1, c1, r2, c2 = self.selection_boxes[self.selected.fill_iid].coords
6665
6695
  numcols = c2 - c1
@@ -6977,6 +7007,7 @@ class MainTable(tk.Canvas):
6977
7007
 
6978
7008
  def hide_dropdown_window(self) -> None:
6979
7009
  if self.dropdown.open:
7010
+ self.dropdown.window.unbind("<FocusOut>")
6980
7011
  self.itemconfig(self.dropdown.canvas_id, state="hidden")
6981
7012
  self.dropdown.open = False
6982
7013
 
@@ -7028,12 +7059,14 @@ class MainTable(tk.Canvas):
7028
7059
  c: int = 0,
7029
7060
  datarn: int | None = None,
7030
7061
  datacn: int | None = None,
7031
- value: str = "",
7062
+ value: str | None = None,
7032
7063
  undo: bool = True,
7033
7064
  cell_resize: bool = True,
7034
7065
  redraw: bool = True,
7035
7066
  check_input_valid: bool = True,
7036
7067
  ) -> bool:
7068
+ if value is None:
7069
+ value = ""
7037
7070
  if datacn is None:
7038
7071
  datacn = self.datacn(c)
7039
7072
  if datarn is None: