tksheet 7.4.24__py3-none-any.whl → 7.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tksheet/main_table.py CHANGED
@@ -71,6 +71,7 @@ from .functions import (
71
71
  is_last_cell,
72
72
  is_type_int,
73
73
  len_to_idx,
74
+ menu_item_exists,
74
75
  mod_event_val,
75
76
  mod_span,
76
77
  move_elements_by_mapping_gen,
@@ -285,19 +286,24 @@ class MainTable(tk.Canvas):
285
286
  self.align = kwargs["align"]
286
287
  self.PAR.ops.table_font = FontTuple(
287
288
  self.PAR.ops.table_font[0],
288
- max(1, int(self.PAR.ops.table_font[1] * kwargs["zoom"] / 100)),
289
+ max(1, int(round(self.PAR.ops.table_font[1]) * kwargs["zoom"] / 100)),
289
290
  self.PAR.ops.table_font[2],
290
291
  )
291
292
  self.PAR.ops.index_font = FontTuple(
292
293
  self.PAR.ops.index_font[0],
293
- max(1, int(self.PAR.ops.index_font[1] * kwargs["zoom"] / 100)),
294
+ max(1, int(round(self.PAR.ops.index_font[1]) * kwargs["zoom"] / 100)),
294
295
  self.PAR.ops.index_font[2],
295
296
  )
296
297
  self.PAR.ops.header_font = FontTuple(
297
298
  self.PAR.ops.header_font[0],
298
- max(1, int(self.PAR.ops.header_font[1] * kwargs["zoom"] / 100)),
299
+ max(1, int(round(self.PAR.ops.header_font[1]) * kwargs["zoom"] / 100)),
299
300
  self.PAR.ops.header_font[2],
300
301
  )
302
+ self.PAR.ops.popup_menu_font = FontTuple(
303
+ self.PAR.ops.popup_menu_font[0],
304
+ max(1, int(round(self.PAR.ops.popup_menu_font[1]) * kwargs["zoom"] / 100)),
305
+ self.PAR.ops.popup_menu_font[2],
306
+ )
301
307
  self.txt_measure_canvas = tk.Canvas(self)
302
308
  self.txt_measure_canvas_text = self.txt_measure_canvas.create_text(0, 0, text="", font=self.PAR.ops.table_font)
303
309
 
@@ -456,28 +462,84 @@ class MainTable(tk.Canvas):
456
462
  self.tagged_rows = {}
457
463
  self.tagged_columns = {}
458
464
 
465
+ def create_ctrl_outline(
466
+ self,
467
+ x1: int,
468
+ y1: int,
469
+ x2: int,
470
+ y2: int,
471
+ fill: str,
472
+ dash: tuple[int, int],
473
+ width: int,
474
+ outline: str,
475
+ tags: str | tuple[str, ...],
476
+ ) -> int:
477
+ if self.hidd_ctrl_outline:
478
+ t, sh = self.hidd_ctrl_outline.popitem()
479
+ self.coords(t, x1, y1, x2, y2)
480
+ if sh:
481
+ self.itemconfig(t, fill=fill, dash=dash, width=width, outline=outline, tags=tags)
482
+ else:
483
+ self.itemconfig(
484
+ t,
485
+ fill=fill,
486
+ dash=dash,
487
+ width=width,
488
+ outline=outline,
489
+ tags=tags,
490
+ state="normal",
491
+ )
492
+ else:
493
+ t = self.create_rectangle(
494
+ x1,
495
+ y1,
496
+ x2,
497
+ y2,
498
+ fill=fill,
499
+ dash=dash,
500
+ width=width,
501
+ outline=outline,
502
+ tags=tags,
503
+ )
504
+ self.lift(t)
505
+ self.disp_ctrl_outline[t] = True
506
+ return t
507
+
508
+ def delete_ctrl_outlines(self, iid: int | None = None) -> None:
509
+ if isinstance(iid, int) and iid in self.disp_ctrl_outline:
510
+ self.hidd_ctrl_outline[iid] = self.disp_ctrl_outline.pop(iid)
511
+ self.itemconfig(iid, state="hidden")
512
+ self.hidd_ctrl_outline[iid] = False
513
+ else:
514
+ self.hidd_ctrl_outline.update(self.disp_ctrl_outline)
515
+ self.disp_ctrl_outline = {}
516
+ for t, sh in self.hidd_ctrl_outline.items():
517
+ if sh:
518
+ self.itemconfig(t, state="hidden")
519
+ self.hidd_ctrl_outline[t] = False
520
+
459
521
  def show_ctrl_outline(
460
522
  self,
461
523
  canvas: Literal["table"] = "table",
462
524
  start_cell: tuple[int, int] = (0, 0),
463
525
  end_cell: tuple[int, int] = (0, 0),
464
- dash: tuple[int, int] = (20, 20),
526
+ dash: tuple[int, int] = (15, 15),
465
527
  outline: str | None = None,
466
528
  delete_on_timer: bool = True,
467
529
  ) -> None:
468
- self.create_ctrl_outline(
530
+ iid = self.create_ctrl_outline(
469
531
  self.col_positions[start_cell[0]] + 1,
470
532
  self.row_positions[start_cell[1]] + 1,
471
- self.col_positions[end_cell[0]] - 1,
472
- self.row_positions[end_cell[1]] - 1,
533
+ self.col_positions[end_cell[0]],
534
+ self.row_positions[end_cell[1]],
473
535
  fill="",
474
536
  dash=dash,
475
- width=3,
537
+ width=2,
476
538
  outline=self.PAR.ops.resizing_line_fg if outline is None else outline,
477
- tags="ctrl",
539
+ tags="lift",
478
540
  )
479
541
  if delete_on_timer:
480
- self.after(1500, self.delete_ctrl_outlines)
542
+ self.after(1500, lambda: self.delete_ctrl_outlines(iid))
481
543
 
482
544
  def escape(self, event: tk.Misc | None) -> None:
483
545
  if self.find_window.open:
@@ -895,56 +957,6 @@ class MainTable(tk.Canvas):
895
957
  self.find_window.open = False
896
958
  self.focus_set()
897
959
 
898
- def create_ctrl_outline(
899
- self,
900
- x1: int,
901
- y1: int,
902
- x2: int,
903
- y2: int,
904
- fill: str,
905
- dash: tuple[int, int],
906
- width: int,
907
- outline: str,
908
- tags: str | tuple[str, ...],
909
- ) -> None:
910
- if self.hidd_ctrl_outline:
911
- t, sh = self.hidd_ctrl_outline.popitem()
912
- self.coords(t, x1, y1, x2, y2)
913
- if sh:
914
- self.itemconfig(t, fill=fill, dash=dash, width=width, outline=outline, tags=tags)
915
- else:
916
- self.itemconfig(
917
- t,
918
- fill=fill,
919
- dash=dash,
920
- width=width,
921
- outline=outline,
922
- tags=tags,
923
- state="normal",
924
- )
925
- self.lift(t)
926
- else:
927
- t = self.create_rectangle(
928
- x1,
929
- y1,
930
- x2,
931
- y2,
932
- fill=fill,
933
- dash=dash,
934
- width=width,
935
- outline=outline,
936
- tags=tags,
937
- )
938
- self.disp_ctrl_outline[t] = True
939
-
940
- def delete_ctrl_outlines(self) -> None:
941
- self.hidd_ctrl_outline.update(self.disp_ctrl_outline)
942
- self.disp_ctrl_outline = {}
943
- for t, sh in self.hidd_ctrl_outline.items():
944
- if sh:
945
- self.itemconfig(t, state="hidden")
946
- self.hidd_ctrl_outline[t] = False
947
-
948
960
  def get_ctrl_x_c_boxes(self) -> tuple[dict[tuple[int, int, int, int], str], int]:
949
961
  maxrows = 0
950
962
  if not self.selected:
@@ -1410,6 +1422,7 @@ class MainTable(tk.Canvas):
1410
1422
  try_binding(self.extra_end_ctrl_v_func, event_data, "end_ctrl_v")
1411
1423
  self.sheet_modified(event_data)
1412
1424
  self.PAR.emit_event("<<Paste>>", event_data)
1425
+ self.show_ctrl_outline("table", (selected_c, selected_r), (selboxc, selboxr), dash=())
1413
1426
  return event_data
1414
1427
 
1415
1428
  def delete_key(self, event: Any = None, validation: bool = True) -> None | EventDataDict:
@@ -1446,6 +1459,8 @@ class MainTable(tk.Canvas):
1446
1459
  try_binding(self.extra_end_delete_key_func, event_data, "end_delete")
1447
1460
  self.sheet_modified(event_data)
1448
1461
  self.PAR.emit_event("<<Delete>>", event_data)
1462
+ for r1, c1, r2, c2 in boxes:
1463
+ self.show_ctrl_outline(canvas="table", start_cell=(c1, r1), end_cell=(c2, r2))
1449
1464
  return event_data
1450
1465
 
1451
1466
  def event_data_set_cell(self, datarn: int, datacn: int, value: Any, event_data: EventDataDict) -> EventDataDict:
@@ -2910,6 +2925,27 @@ class MainTable(tk.Canvas):
2910
2925
  pass
2911
2926
  menu.add_command(**kwargs)
2912
2927
 
2928
+ def table_edit_cell_enabled(self) -> bool:
2929
+ return (
2930
+ self.rc_popup_menus_enabled
2931
+ and self.edit_cell_enabled
2932
+ and any(x in self.enabled_bindings_menu_entries for x in ("all", "edit_cell", "edit_bindings", "edit"))
2933
+ )
2934
+
2935
+ def index_edit_cell_enabled(self) -> bool:
2936
+ return (
2937
+ self.rc_popup_menus_enabled
2938
+ and self.RI.edit_cell_enabled
2939
+ and "edit_index" in self.enabled_bindings_menu_entries
2940
+ )
2941
+
2942
+ def header_edit_cell_enabled(self) -> bool:
2943
+ return (
2944
+ self.rc_popup_menus_enabled
2945
+ and self.CH.edit_cell_enabled
2946
+ and "edit_header" in self.enabled_bindings_menu_entries
2947
+ )
2948
+
2913
2949
  def create_rc_menus(self) -> None:
2914
2950
  if not self.rc_popup_menu:
2915
2951
  self.rc_popup_menu = tk.Menu(self, tearoff=0, background=self.PAR.ops.popup_menu_bg)
@@ -2927,37 +2963,31 @@ class MainTable(tk.Canvas):
2927
2963
  ):
2928
2964
  menu.delete(0, "end")
2929
2965
  mnkwgs = get_menu_kwargs(self.PAR.ops)
2930
- if (
2931
- self.rc_popup_menus_enabled
2932
- and self.CH.edit_cell_enabled
2933
- and "edit_header" in self.enabled_bindings_menu_entries
2934
- ):
2966
+ if self.header_edit_cell_enabled():
2935
2967
  self.menu_add_command(
2936
2968
  self.CH.ch_rc_popup_menu,
2937
2969
  label=self.PAR.ops.edit_header_label,
2938
2970
  command=lambda: self.CH.open_cell(event="rc"),
2971
+ image=self.PAR.ops.edit_header_image,
2972
+ compound=self.PAR.ops.edit_header_compound,
2939
2973
  **mnkwgs,
2940
2974
  )
2941
- if (
2942
- self.rc_popup_menus_enabled
2943
- and self.RI.edit_cell_enabled
2944
- and "edit_index" in self.enabled_bindings_menu_entries
2945
- ):
2975
+ if self.index_edit_cell_enabled():
2946
2976
  self.menu_add_command(
2947
2977
  self.RI.ri_rc_popup_menu,
2948
2978
  label=self.PAR.ops.edit_index_label,
2949
2979
  command=lambda: self.RI.open_cell(event="rc"),
2980
+ image=self.PAR.ops.edit_index_image,
2981
+ compound=self.PAR.ops.edit_index_compound,
2950
2982
  **mnkwgs,
2951
2983
  )
2952
- if (
2953
- self.rc_popup_menus_enabled
2954
- and self.edit_cell_enabled
2955
- and any(x in self.enabled_bindings_menu_entries for x in ("all", "edit_cell", "edit_bindings", "edit"))
2956
- ):
2984
+ if self.table_edit_cell_enabled():
2957
2985
  self.menu_add_command(
2958
2986
  self.rc_popup_menu,
2959
2987
  label=self.PAR.ops.edit_cell_label,
2960
2988
  command=lambda: self.open_cell(event="rc"),
2989
+ image=self.PAR.ops.edit_cell_image,
2990
+ compound=self.PAR.ops.edit_cell_compound,
2961
2991
  **mnkwgs,
2962
2992
  )
2963
2993
  if self.cut_enabled and any(
@@ -2968,6 +2998,8 @@ class MainTable(tk.Canvas):
2968
2998
  label=self.PAR.ops.cut_label,
2969
2999
  accelerator=self.PAR.ops.cut_accelerator,
2970
3000
  command=self.ctrl_x,
3001
+ image=self.PAR.ops.cut_image,
3002
+ compound=self.PAR.ops.cut_compound,
2971
3003
  **mnkwgs,
2972
3004
  )
2973
3005
  self.menu_add_command(
@@ -2975,6 +3007,8 @@ class MainTable(tk.Canvas):
2975
3007
  label=self.PAR.ops.cut_contents_label,
2976
3008
  accelerator=self.PAR.ops.cut_contents_accelerator,
2977
3009
  command=self.ctrl_x,
3010
+ image=self.PAR.ops.cut_contents_image,
3011
+ compound=self.PAR.ops.cut_contents_compound,
2978
3012
  **mnkwgs,
2979
3013
  )
2980
3014
  self.menu_add_command(
@@ -2982,6 +3016,8 @@ class MainTable(tk.Canvas):
2982
3016
  label=self.PAR.ops.cut_contents_label,
2983
3017
  accelerator=self.PAR.ops.cut_contents_accelerator,
2984
3018
  command=self.ctrl_x,
3019
+ image=self.PAR.ops.cut_contents_image,
3020
+ compound=self.PAR.ops.cut_contents_compound,
2985
3021
  **mnkwgs,
2986
3022
  )
2987
3023
  if self.copy_enabled and any(
@@ -2992,6 +3028,8 @@ class MainTable(tk.Canvas):
2992
3028
  label=self.PAR.ops.copy_label,
2993
3029
  accelerator=self.PAR.ops.copy_accelerator,
2994
3030
  command=self.ctrl_c,
3031
+ image=self.PAR.ops.copy_image,
3032
+ compound=self.PAR.ops.copy_compound,
2995
3033
  **mnkwgs,
2996
3034
  )
2997
3035
  self.menu_add_command(
@@ -2999,6 +3037,8 @@ class MainTable(tk.Canvas):
2999
3037
  label=self.PAR.ops.copy_contents_label,
3000
3038
  accelerator=self.PAR.ops.copy_contents_accelerator,
3001
3039
  command=self.ctrl_c,
3040
+ image=self.PAR.ops.copy_contents_image,
3041
+ compound=self.PAR.ops.copy_contents_compound,
3002
3042
  **mnkwgs,
3003
3043
  )
3004
3044
  self.menu_add_command(
@@ -3006,6 +3046,8 @@ class MainTable(tk.Canvas):
3006
3046
  label=self.PAR.ops.copy_contents_label,
3007
3047
  accelerator=self.PAR.ops.copy_contents_accelerator,
3008
3048
  command=self.ctrl_c,
3049
+ image=self.PAR.ops.copy_contents_image,
3050
+ compound=self.PAR.ops.copy_contents_compound,
3009
3051
  **mnkwgs,
3010
3052
  )
3011
3053
  if self.paste_enabled and any(
@@ -3016,6 +3058,8 @@ class MainTable(tk.Canvas):
3016
3058
  label=self.PAR.ops.paste_label,
3017
3059
  accelerator=self.PAR.ops.paste_accelerator,
3018
3060
  command=self.ctrl_v,
3061
+ image=self.PAR.ops.paste_image,
3062
+ compound=self.PAR.ops.paste_compound,
3019
3063
  **mnkwgs,
3020
3064
  )
3021
3065
  self.menu_add_command(
@@ -3023,6 +3067,8 @@ class MainTable(tk.Canvas):
3023
3067
  label=self.PAR.ops.paste_label,
3024
3068
  accelerator=self.PAR.ops.paste_accelerator,
3025
3069
  command=self.ctrl_v,
3070
+ image=self.PAR.ops.paste_image,
3071
+ compound=self.PAR.ops.paste_compound,
3026
3072
  **mnkwgs,
3027
3073
  )
3028
3074
  self.menu_add_command(
@@ -3030,6 +3076,8 @@ class MainTable(tk.Canvas):
3030
3076
  label=self.PAR.ops.paste_label,
3031
3077
  accelerator=self.PAR.ops.paste_accelerator,
3032
3078
  command=self.ctrl_v,
3079
+ image=self.PAR.ops.paste_image,
3080
+ compound=self.PAR.ops.paste_compound,
3033
3081
  **mnkwgs,
3034
3082
  )
3035
3083
  if self.PAR.ops.paste_can_expand_x or self.PAR.ops.paste_can_expand_y:
@@ -3038,6 +3086,8 @@ class MainTable(tk.Canvas):
3038
3086
  label=self.PAR.ops.paste_label,
3039
3087
  accelerator=self.PAR.ops.paste_accelerator,
3040
3088
  command=self.ctrl_v,
3089
+ image=self.PAR.ops.paste_image,
3090
+ compound=self.PAR.ops.paste_compound,
3041
3091
  **mnkwgs,
3042
3092
  )
3043
3093
  if self.delete_key_enabled and any(
@@ -3048,6 +3098,8 @@ class MainTable(tk.Canvas):
3048
3098
  label=self.PAR.ops.delete_label,
3049
3099
  accelerator=self.PAR.ops.delete_accelerator,
3050
3100
  command=self.delete_key,
3101
+ image=self.PAR.ops.delete_image,
3102
+ compound=self.PAR.ops.delete_compound,
3051
3103
  **mnkwgs,
3052
3104
  )
3053
3105
  self.menu_add_command(
@@ -3055,6 +3107,8 @@ class MainTable(tk.Canvas):
3055
3107
  label=self.PAR.ops.clear_contents_label,
3056
3108
  accelerator=self.PAR.ops.clear_contents_accelerator,
3057
3109
  command=self.delete_key,
3110
+ image=self.PAR.ops.clear_contents_image,
3111
+ compound=self.PAR.ops.clear_contents_compound,
3058
3112
  **mnkwgs,
3059
3113
  )
3060
3114
  self.menu_add_command(
@@ -3062,6 +3116,8 @@ class MainTable(tk.Canvas):
3062
3116
  label=self.PAR.ops.clear_contents_label,
3063
3117
  accelerator=self.PAR.ops.clear_contents_accelerator,
3064
3118
  command=self.delete_key,
3119
+ image=self.PAR.ops.clear_contents_image,
3120
+ compound=self.PAR.ops.clear_contents_compound,
3065
3121
  **mnkwgs,
3066
3122
  )
3067
3123
  if self.rc_delete_column_enabled:
@@ -3069,6 +3125,8 @@ class MainTable(tk.Canvas):
3069
3125
  self.CH.ch_rc_popup_menu,
3070
3126
  label=self.PAR.ops.delete_columns_label,
3071
3127
  command=self.delete_columns,
3128
+ image=self.PAR.ops.delete_columns_image,
3129
+ compound=self.PAR.ops.delete_columns_compound,
3072
3130
  **mnkwgs,
3073
3131
  )
3074
3132
  if self.rc_insert_column_enabled:
@@ -3076,18 +3134,24 @@ class MainTable(tk.Canvas):
3076
3134
  self.CH.ch_rc_popup_menu,
3077
3135
  label=self.PAR.ops.insert_columns_left_label,
3078
3136
  command=lambda: self.rc_add_columns("left"),
3137
+ image=self.PAR.ops.insert_columns_left_image,
3138
+ compound=self.PAR.ops.insert_columns_left_compound,
3079
3139
  **mnkwgs,
3080
3140
  )
3081
3141
  self.menu_add_command(
3082
3142
  self.CH.ch_rc_popup_menu,
3083
3143
  label=self.PAR.ops.insert_columns_right_label,
3084
3144
  command=lambda: self.rc_add_columns("right"),
3145
+ image=self.PAR.ops.insert_columns_right_image,
3146
+ compound=self.PAR.ops.insert_columns_right_compound,
3085
3147
  **mnkwgs,
3086
3148
  )
3087
3149
  self.menu_add_command(
3088
3150
  self.empty_rc_popup_menu,
3089
3151
  label=self.PAR.ops.insert_column_label,
3090
3152
  command=lambda: self.rc_add_columns("left"),
3153
+ image=self.PAR.ops.insert_column_image,
3154
+ compound=self.PAR.ops.insert_column_compound,
3091
3155
  **mnkwgs,
3092
3156
  )
3093
3157
  if self.rc_delete_row_enabled:
@@ -3095,6 +3159,8 @@ class MainTable(tk.Canvas):
3095
3159
  self.RI.ri_rc_popup_menu,
3096
3160
  label=self.PAR.ops.delete_rows_label,
3097
3161
  command=self.delete_rows,
3162
+ image=self.PAR.ops.delete_rows_image,
3163
+ compound=self.PAR.ops.delete_rows_compound,
3098
3164
  **mnkwgs,
3099
3165
  )
3100
3166
  if self.rc_insert_row_enabled:
@@ -3102,18 +3168,24 @@ class MainTable(tk.Canvas):
3102
3168
  self.RI.ri_rc_popup_menu,
3103
3169
  label=self.PAR.ops.insert_rows_above_label,
3104
3170
  command=lambda: self.rc_add_rows("above"),
3171
+ image=self.PAR.ops.insert_rows_above_image,
3172
+ compound=self.PAR.ops.insert_rows_above_compound,
3105
3173
  **mnkwgs,
3106
3174
  )
3107
3175
  self.menu_add_command(
3108
3176
  self.RI.ri_rc_popup_menu,
3109
3177
  label=self.PAR.ops.insert_rows_below_label,
3110
3178
  command=lambda: self.rc_add_rows("below"),
3179
+ image=self.PAR.ops.insert_rows_below_image,
3180
+ compound=self.PAR.ops.insert_rows_below_compound,
3111
3181
  **mnkwgs,
3112
3182
  )
3113
3183
  self.menu_add_command(
3114
3184
  self.empty_rc_popup_menu,
3115
3185
  label=self.PAR.ops.insert_row_label,
3116
3186
  command=lambda: self.rc_add_rows("below"),
3187
+ image=self.PAR.ops.insert_row_image,
3188
+ compound=self.PAR.ops.insert_row_compound,
3117
3189
  **mnkwgs,
3118
3190
  )
3119
3191
  if self.rc_sort_cells_enabled:
@@ -3122,6 +3194,8 @@ class MainTable(tk.Canvas):
3122
3194
  label=self.PAR.ops.sort_cells_label,
3123
3195
  accelerator=self.PAR.ops.sort_cells_accelerator,
3124
3196
  command=self.sort_boxes,
3197
+ image=self.PAR.ops.sort_cells_image,
3198
+ compound=self.PAR.ops.sort_cells_compound,
3125
3199
  **mnkwgs,
3126
3200
  )
3127
3201
  self.menu_add_command(
@@ -3129,6 +3203,8 @@ class MainTable(tk.Canvas):
3129
3203
  label=self.PAR.ops.sort_cells_reverse_label,
3130
3204
  accelerator=self.PAR.ops.sort_cells_reverse_accelerator,
3131
3205
  command=lambda: self.sort_boxes(reverse=True),
3206
+ image=self.PAR.ops.sort_cells_reverse_image,
3207
+ compound=self.PAR.ops.sort_cells_reverse_compound,
3132
3208
  **mnkwgs,
3133
3209
  )
3134
3210
  self.menu_add_command(
@@ -3136,6 +3212,8 @@ class MainTable(tk.Canvas):
3136
3212
  label=self.PAR.ops.sort_cells_x_label,
3137
3213
  accelerator=self.PAR.ops.sort_cells_x_accelerator,
3138
3214
  command=lambda: self.sort_boxes(row_wise=True),
3215
+ image=self.PAR.ops.sort_cells_x_image,
3216
+ compound=self.PAR.ops.sort_cells_x_compound,
3139
3217
  **mnkwgs,
3140
3218
  )
3141
3219
  self.menu_add_command(
@@ -3143,6 +3221,8 @@ class MainTable(tk.Canvas):
3143
3221
  label=self.PAR.ops.sort_cells_x_reverse_label,
3144
3222
  accelerator=self.PAR.ops.sort_cells_x_reverse_accelerator,
3145
3223
  command=lambda: self.sort_boxes(reverse=True, row_wise=True),
3224
+ image=self.PAR.ops.sort_cells_x_reverse_image,
3225
+ compound=self.PAR.ops.sort_cells_x_reverse_compound,
3146
3226
  **mnkwgs,
3147
3227
  )
3148
3228
  # row index sort rows cells
@@ -3152,6 +3232,8 @@ class MainTable(tk.Canvas):
3152
3232
  label=self.PAR.ops.sort_row_label,
3153
3233
  accelerator=self.PAR.ops.sort_row_accelerator,
3154
3234
  command=self.RI._sort_rows,
3235
+ image=self.PAR.ops.sort_row_image,
3236
+ compound=self.PAR.ops.sort_row_compound,
3155
3237
  **mnkwgs,
3156
3238
  )
3157
3239
  self.menu_add_command(
@@ -3159,6 +3241,8 @@ class MainTable(tk.Canvas):
3159
3241
  label=self.PAR.ops.sort_row_reverse_label,
3160
3242
  accelerator=self.PAR.ops.sort_row_reverse_accelerator,
3161
3243
  command=lambda: self.RI._sort_rows(reverse=True),
3244
+ image=self.PAR.ops.sort_row_reverse_image,
3245
+ compound=self.PAR.ops.sort_row_reverse_compound,
3162
3246
  **mnkwgs,
3163
3247
  )
3164
3248
  # header sort columns cells
@@ -3168,6 +3252,8 @@ class MainTable(tk.Canvas):
3168
3252
  label=self.PAR.ops.sort_column_label,
3169
3253
  accelerator=self.PAR.ops.sort_column_accelerator,
3170
3254
  command=self.CH._sort_columns,
3255
+ image=self.PAR.ops.sort_column_image,
3256
+ compound=self.PAR.ops.sort_column_compound,
3171
3257
  **mnkwgs,
3172
3258
  )
3173
3259
  self.menu_add_command(
@@ -3175,6 +3261,8 @@ class MainTable(tk.Canvas):
3175
3261
  label=self.PAR.ops.sort_column_reverse_label,
3176
3262
  accelerator=self.PAR.ops.sort_column_reverse_accelerator,
3177
3263
  command=lambda: self.CH._sort_columns(reverse=True),
3264
+ image=self.PAR.ops.sort_column_reverse_image,
3265
+ compound=self.PAR.ops.sort_column_reverse_compound,
3178
3266
  **mnkwgs,
3179
3267
  )
3180
3268
  # row index sort columns by row
@@ -3184,6 +3272,8 @@ class MainTable(tk.Canvas):
3184
3272
  label=self.PAR.ops.sort_columns_label,
3185
3273
  accelerator=self.PAR.ops.sort_columns_accelerator,
3186
3274
  command=self.RI._sort_columns_by_row,
3275
+ image=self.PAR.ops.sort_columns_image,
3276
+ compound=self.PAR.ops.sort_columns_compound,
3187
3277
  **mnkwgs,
3188
3278
  )
3189
3279
  self.menu_add_command(
@@ -3191,6 +3281,8 @@ class MainTable(tk.Canvas):
3191
3281
  label=self.PAR.ops.sort_columns_reverse_label,
3192
3282
  accelerator=self.PAR.ops.sort_columns_reverse_accelerator,
3193
3283
  command=lambda: self.RI._sort_columns_by_row(reverse=True),
3284
+ image=self.PAR.ops.sort_columns_reverse_image,
3285
+ compound=self.PAR.ops.sort_columns_reverse_compound,
3194
3286
  **mnkwgs,
3195
3287
  )
3196
3288
  # header sort rows by column
@@ -3200,6 +3292,8 @@ class MainTable(tk.Canvas):
3200
3292
  label=self.PAR.ops.sort_rows_label,
3201
3293
  accelerator=self.PAR.ops.sort_rows_accelerator,
3202
3294
  command=self.CH._sort_rows_by_column,
3295
+ image=self.PAR.ops.sort_rows_image,
3296
+ compound=self.PAR.ops.sort_rows_compound,
3203
3297
  **mnkwgs,
3204
3298
  )
3205
3299
  self.menu_add_command(
@@ -3207,36 +3301,46 @@ class MainTable(tk.Canvas):
3207
3301
  label=self.PAR.ops.sort_rows_reverse_label,
3208
3302
  accelerator=self.PAR.ops.sort_rows_reverse_accelerator,
3209
3303
  command=lambda: self.CH._sort_rows_by_column(reverse=True),
3304
+ image=self.PAR.ops.sort_rows_reverse_image,
3305
+ compound=self.PAR.ops.sort_rows_reverse_compound,
3210
3306
  **mnkwgs,
3211
3307
  )
3212
- for label, func in self.extra_table_rc_menu_funcs.items():
3213
- self.menu_add_command(
3308
+ if self.undo_enabled and any(
3309
+ x in self.enabled_bindings_menu_entries for x in ("all", "undo", "redo", "edit_bindings", "edit")
3310
+ ):
3311
+ for menu in (
3214
3312
  self.rc_popup_menu,
3215
- label=label,
3216
- command=func,
3217
- **mnkwgs,
3218
- )
3219
- for label, func in self.extra_index_rc_menu_funcs.items():
3220
- self.menu_add_command(
3221
3313
  self.RI.ri_rc_popup_menu,
3222
- label=label,
3223
- command=func,
3224
- **mnkwgs,
3225
- )
3226
- for label, func in self.extra_header_rc_menu_funcs.items():
3227
- self.menu_add_command(
3228
3314
  self.CH.ch_rc_popup_menu,
3229
- label=label,
3230
- command=func,
3231
- **mnkwgs,
3232
- )
3233
- for label, func in self.extra_empty_space_rc_menu_funcs.items():
3234
- self.menu_add_command(
3235
3315
  self.empty_rc_popup_menu,
3236
- label=label,
3237
- command=func,
3238
- **mnkwgs,
3239
- )
3316
+ ):
3317
+ self.menu_add_command(
3318
+ menu,
3319
+ label=self.PAR.ops.undo_label,
3320
+ accelerator=self.PAR.ops.undo_accelerator,
3321
+ command=self.undo,
3322
+ image=self.PAR.ops.undo_image,
3323
+ compound=self.PAR.ops.undo_compound,
3324
+ **mnkwgs,
3325
+ )
3326
+ self.menu_add_command(
3327
+ menu,
3328
+ label=self.PAR.ops.redo_label,
3329
+ accelerator=self.PAR.ops.redo_accelerator,
3330
+ command=self.redo,
3331
+ image=self.PAR.ops.redo_image,
3332
+ compound=self.PAR.ops.redo_compound,
3333
+ **mnkwgs,
3334
+ )
3335
+ # Added popup menu commands
3336
+ for label, kws in self.extra_table_rc_menu_funcs.items():
3337
+ self.menu_add_command(self.rc_popup_menu, label=label, **{**mnkwgs, **kws})
3338
+ for label, kws in self.extra_index_rc_menu_funcs.items():
3339
+ self.menu_add_command(self.RI.ri_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3340
+ for label, kws in self.extra_header_rc_menu_funcs.items():
3341
+ self.menu_add_command(self.CH.ch_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3342
+ for label, kws in self.extra_empty_space_rc_menu_funcs.items():
3343
+ self.menu_add_command(self.empty_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3240
3344
 
3241
3345
  def enable_bindings(self, bindings: Any, menu: bool = True) -> None:
3242
3346
  if not bindings:
@@ -3567,6 +3671,65 @@ class MainTable(tk.Canvas):
3567
3671
  def not_currently_resizing(self) -> bool:
3568
3672
  return all(v is None for v in (self.RI.rsz_h, self.RI.rsz_w, self.CH.rsz_h, self.CH.rsz_w))
3569
3673
 
3674
+ def is_readonly(self, datarn: int, datacn: int) -> bool:
3675
+ return (
3676
+ ((datarn, datacn) in self.cell_options and "readonly" in self.cell_options[(datarn, datacn)])
3677
+ or (datarn in self.row_options and "readonly" in self.row_options[datarn])
3678
+ or (datacn in self.col_options and "readonly" in self.col_options[datacn])
3679
+ )
3680
+
3681
+ def popup_menu_disable_edit_if_readonly(self, popup_menu: tk.Menu) -> None:
3682
+ # table
3683
+ if (
3684
+ self.selected
3685
+ and self.index_edit_cell_enabled()
3686
+ and menu_item_exists(popup_menu, self.PAR.ops.edit_cell_label)
3687
+ ):
3688
+ datarn, datacn = self.datarn(self.selected.row), self.datacn(self.selected.column)
3689
+ if self.is_readonly(datarn, datacn):
3690
+ popup_menu.entryconfig(self.PAR.ops.edit_cell_label, image="", state="disabled")
3691
+ else:
3692
+ popup_menu.entryconfig(self.PAR.ops.edit_cell_label, image=self.PAR.ops.edit_cell_image, state="normal")
3693
+ # index
3694
+ if (
3695
+ self.selected
3696
+ and self.index_edit_cell_enabled()
3697
+ and menu_item_exists(popup_menu, self.PAR.ops.edit_index_label)
3698
+ ):
3699
+ datarn = self.datarn(self.selected.row)
3700
+ if self.RI.is_readonly(datarn):
3701
+ popup_menu.entryconfig(self.PAR.ops.edit_index_label, image="", state="disabled")
3702
+ else:
3703
+ popup_menu.entryconfig(
3704
+ self.PAR.ops.edit_index_label, image=self.PAR.ops.edit_index_image, state="normal"
3705
+ )
3706
+ # header
3707
+ if (
3708
+ self.selected
3709
+ and self.header_edit_cell_enabled()
3710
+ and menu_item_exists(popup_menu, self.PAR.ops.edit_header_label)
3711
+ ):
3712
+ datacn = self.datacn(self.selected.column)
3713
+ if self.CH.is_readonly(datacn):
3714
+ popup_menu.entryconfig(self.PAR.ops.edit_header_label, image="", state="disabled")
3715
+ else:
3716
+ popup_menu.entryconfig(
3717
+ self.PAR.ops.edit_header_label, image=self.PAR.ops.edit_header_image, state="normal"
3718
+ )
3719
+
3720
+ def popup_menu_disable_undo_redo(self, popup_menu: tk.Menu) -> None:
3721
+ if not self.undo_enabled:
3722
+ return
3723
+ if menu_item_exists(popup_menu, self.PAR.ops.undo_label):
3724
+ if not self.undo_stack:
3725
+ popup_menu.entryconfig(self.PAR.ops.undo_label, image="", state="disabled")
3726
+ else:
3727
+ popup_menu.entryconfig(self.PAR.ops.undo_label, image=self.PAR.ops.undo_image, state="normal")
3728
+ if not self.redo_stack:
3729
+ popup_menu.entryconfig(self.PAR.ops.redo_label, image="", state="disabled")
3730
+ else:
3731
+ popup_menu.entryconfig(self.PAR.ops.redo_label, image=self.PAR.ops.redo_image, state="normal")
3732
+
3570
3733
  def rc(self, event: Any = None) -> None:
3571
3734
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
3572
3735
  self.focus_set()
@@ -3598,6 +3761,8 @@ class MainTable(tk.Canvas):
3598
3761
  popup_menu = self.empty_rc_popup_menu
3599
3762
  try_binding(self.extra_rc_func, event)
3600
3763
  if popup_menu:
3764
+ self.popup_menu_disable_edit_if_readonly(popup_menu)
3765
+ self.popup_menu_disable_undo_redo(popup_menu)
3601
3766
  popup_menu.tk_popup(event.x_root, event.y_root)
3602
3767
 
3603
3768
  def b1_press(self, event: Any = None) -> None:
@@ -4117,16 +4282,23 @@ class MainTable(tk.Canvas):
4117
4282
  (self.PAR.ops.table_font[0], self.PAR.ops.table_font[1] + 1, self.PAR.ops.table_font[2]),
4118
4283
  (self.PAR.ops.index_font[0], self.PAR.ops.index_font[1] + 1, self.PAR.ops.index_font[2]),
4119
4284
  (self.PAR.ops.header_font[0], self.PAR.ops.header_font[1] + 1, self.PAR.ops.header_font[2]),
4285
+ (self.PAR.ops.popup_menu_font[0], self.PAR.ops.popup_menu_font[1] + 1, self.PAR.ops.popup_menu_font[2]),
4120
4286
  "in",
4121
4287
  )
4122
4288
 
4123
4289
  def zoom_out(self, event: Any = None) -> None:
4124
- if self.PAR.ops.table_font[1] < 2 or self.PAR.ops.index_font[1] < 2 or self.PAR.ops.header_font[1] < 2:
4290
+ if (
4291
+ self.PAR.ops.table_font[1] < 2
4292
+ or self.PAR.ops.index_font[1] < 2
4293
+ or self.PAR.ops.header_font[1] < 2
4294
+ or self.PAR.ops.popup_menu_font[1] < 2
4295
+ ):
4125
4296
  return
4126
4297
  self.zoom_font(
4127
4298
  (self.PAR.ops.table_font[0], self.PAR.ops.table_font[1] - 1, self.PAR.ops.table_font[2]),
4128
4299
  (self.PAR.ops.index_font[0], self.PAR.ops.index_font[1] - 1, self.PAR.ops.index_font[2]),
4129
4300
  (self.PAR.ops.header_font[0], self.PAR.ops.header_font[1] - 1, self.PAR.ops.header_font[2]),
4301
+ (self.PAR.ops.popup_menu_font[0], self.PAR.ops.popup_menu_font[1] - 1, self.PAR.ops.popup_menu_font[2]),
4130
4302
  "out",
4131
4303
  )
4132
4304
 
@@ -4135,6 +4307,7 @@ class MainTable(tk.Canvas):
4135
4307
  table_font: FontTuple,
4136
4308
  index_font: FontTuple,
4137
4309
  header_font: FontTuple,
4310
+ popup_font: FontTuple,
4138
4311
  zoom: Literal["in", "out"],
4139
4312
  ) -> None:
4140
4313
  self.saved_column_widths = {}
@@ -4157,6 +4330,7 @@ class MainTable(tk.Canvas):
4157
4330
  self.set_table_font(table_font, row_heights=False)
4158
4331
  self.set_index_font(index_font, row_heights=False)
4159
4332
  self.set_header_font(header_font)
4333
+ self.PAR.ops.popup_menu_font = FontTuple(*popup_font)
4160
4334
  if self.PAR.ops.set_cell_sizes_on_zoom:
4161
4335
  self.set_all_cell_sizes_to_text()
4162
4336
  self.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
@@ -4176,6 +4350,7 @@ class MainTable(tk.Canvas):
4176
4350
  r_pc=r_pc,
4177
4351
  c_pc=c_pc,
4178
4352
  )
4353
+ self.create_rc_menus()
4179
4354
 
4180
4355
  def get_txt_w(self, txt: str, font: None | FontTuple = None) -> int:
4181
4356
  self.txt_measure_canvas.itemconfig(
@@ -4254,7 +4429,7 @@ class MainTable(tk.Canvas):
4254
4429
  not isinstance(newfont, tuple)
4255
4430
  or len(newfont) != 3
4256
4431
  or not isinstance(newfont[0], str)
4257
- or not isinstance(newfont[1], int)
4432
+ or not isinstance(newfont[1], (int, float))
4258
4433
  or not isinstance(newfont[2], str)
4259
4434
  ):
4260
4435
  raise ValueError(font_value_error)
@@ -4262,7 +4437,7 @@ class MainTable(tk.Canvas):
4262
4437
  def set_table_font(self, newfont: tuple | None = None, row_heights: bool = True) -> tuple[str, int, str]:
4263
4438
  if newfont:
4264
4439
  self.check_font(newfont)
4265
- self.PAR.ops.table_font = FontTuple(*newfont)
4440
+ self.PAR.ops.table_font = FontTuple(*(newfont[0], int(round(newfont[1])), newfont[2]))
4266
4441
  old_min_row_height = int(self.min_row_height)
4267
4442
  old_default_row_height = int(self.get_default_row_height())
4268
4443
  self.set_table_font_help()
@@ -4303,7 +4478,7 @@ class MainTable(tk.Canvas):
4303
4478
  def set_index_font(self, newfont: tuple | None = None, row_heights: bool = True) -> tuple[str, int, str]:
4304
4479
  if newfont:
4305
4480
  self.check_font(newfont)
4306
- self.PAR.ops.index_font = FontTuple(*newfont)
4481
+ self.PAR.ops.index_font = FontTuple(*(newfont[0], int(round(newfont[1])), newfont[2]))
4307
4482
  old_min_row_height = int(self.min_row_height)
4308
4483
  old_default_row_height = int(self.get_default_row_height())
4309
4484
  self.set_index_font_help()
@@ -4347,7 +4522,7 @@ class MainTable(tk.Canvas):
4347
4522
  def set_header_font(self, newfont: tuple | None = None) -> tuple[str, int, str]:
4348
4523
  if newfont:
4349
4524
  self.check_font(newfont)
4350
- self.PAR.ops.header_font = FontTuple(*newfont)
4525
+ self.PAR.ops.header_font = FontTuple(*(newfont[0], int(round(newfont[1])), newfont[2]))
4351
4526
  self.set_header_font_help()
4352
4527
  self.recreate_all_selection_boxes()
4353
4528
  return self.PAR.ops.header_font