tksheet 7.4.24__py3-none-any.whl → 7.5.0__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,
@@ -456,28 +457,84 @@ class MainTable(tk.Canvas):
456
457
  self.tagged_rows = {}
457
458
  self.tagged_columns = {}
458
459
 
460
+ def create_ctrl_outline(
461
+ self,
462
+ x1: int,
463
+ y1: int,
464
+ x2: int,
465
+ y2: int,
466
+ fill: str,
467
+ dash: tuple[int, int],
468
+ width: int,
469
+ outline: str,
470
+ tags: str | tuple[str, ...],
471
+ ) -> int:
472
+ if self.hidd_ctrl_outline:
473
+ t, sh = self.hidd_ctrl_outline.popitem()
474
+ self.coords(t, x1, y1, x2, y2)
475
+ if sh:
476
+ self.itemconfig(t, fill=fill, dash=dash, width=width, outline=outline, tags=tags)
477
+ else:
478
+ self.itemconfig(
479
+ t,
480
+ fill=fill,
481
+ dash=dash,
482
+ width=width,
483
+ outline=outline,
484
+ tags=tags,
485
+ state="normal",
486
+ )
487
+ else:
488
+ t = self.create_rectangle(
489
+ x1,
490
+ y1,
491
+ x2,
492
+ y2,
493
+ fill=fill,
494
+ dash=dash,
495
+ width=width,
496
+ outline=outline,
497
+ tags=tags,
498
+ )
499
+ self.lift(t)
500
+ self.disp_ctrl_outline[t] = True
501
+ return t
502
+
503
+ def delete_ctrl_outlines(self, iid: int | None = None) -> None:
504
+ if isinstance(iid, int) and iid in self.disp_ctrl_outline:
505
+ self.hidd_ctrl_outline[iid] = self.disp_ctrl_outline.pop(iid)
506
+ self.itemconfig(iid, state="hidden")
507
+ self.hidd_ctrl_outline[iid] = False
508
+ else:
509
+ self.hidd_ctrl_outline.update(self.disp_ctrl_outline)
510
+ self.disp_ctrl_outline = {}
511
+ for t, sh in self.hidd_ctrl_outline.items():
512
+ if sh:
513
+ self.itemconfig(t, state="hidden")
514
+ self.hidd_ctrl_outline[t] = False
515
+
459
516
  def show_ctrl_outline(
460
517
  self,
461
518
  canvas: Literal["table"] = "table",
462
519
  start_cell: tuple[int, int] = (0, 0),
463
520
  end_cell: tuple[int, int] = (0, 0),
464
- dash: tuple[int, int] = (20, 20),
521
+ dash: tuple[int, int] = (15, 15),
465
522
  outline: str | None = None,
466
523
  delete_on_timer: bool = True,
467
524
  ) -> None:
468
- self.create_ctrl_outline(
525
+ iid = self.create_ctrl_outline(
469
526
  self.col_positions[start_cell[0]] + 1,
470
527
  self.row_positions[start_cell[1]] + 1,
471
- self.col_positions[end_cell[0]] - 1,
472
- self.row_positions[end_cell[1]] - 1,
528
+ self.col_positions[end_cell[0]],
529
+ self.row_positions[end_cell[1]],
473
530
  fill="",
474
531
  dash=dash,
475
- width=3,
532
+ width=2,
476
533
  outline=self.PAR.ops.resizing_line_fg if outline is None else outline,
477
- tags="ctrl",
534
+ tags="lift",
478
535
  )
479
536
  if delete_on_timer:
480
- self.after(1500, self.delete_ctrl_outlines)
537
+ self.after(1500, lambda: self.delete_ctrl_outlines(iid))
481
538
 
482
539
  def escape(self, event: tk.Misc | None) -> None:
483
540
  if self.find_window.open:
@@ -895,56 +952,6 @@ class MainTable(tk.Canvas):
895
952
  self.find_window.open = False
896
953
  self.focus_set()
897
954
 
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
955
  def get_ctrl_x_c_boxes(self) -> tuple[dict[tuple[int, int, int, int], str], int]:
949
956
  maxrows = 0
950
957
  if not self.selected:
@@ -1410,6 +1417,7 @@ class MainTable(tk.Canvas):
1410
1417
  try_binding(self.extra_end_ctrl_v_func, event_data, "end_ctrl_v")
1411
1418
  self.sheet_modified(event_data)
1412
1419
  self.PAR.emit_event("<<Paste>>", event_data)
1420
+ self.show_ctrl_outline("table", (selected_c, selected_r), (selboxc, selboxr), dash=())
1413
1421
  return event_data
1414
1422
 
1415
1423
  def delete_key(self, event: Any = None, validation: bool = True) -> None | EventDataDict:
@@ -1446,6 +1454,8 @@ class MainTable(tk.Canvas):
1446
1454
  try_binding(self.extra_end_delete_key_func, event_data, "end_delete")
1447
1455
  self.sheet_modified(event_data)
1448
1456
  self.PAR.emit_event("<<Delete>>", event_data)
1457
+ for r1, c1, r2, c2 in boxes:
1458
+ self.show_ctrl_outline(canvas="table", start_cell=(c1, r1), end_cell=(c2, r2))
1449
1459
  return event_data
1450
1460
 
1451
1461
  def event_data_set_cell(self, datarn: int, datacn: int, value: Any, event_data: EventDataDict) -> EventDataDict:
@@ -2910,6 +2920,27 @@ class MainTable(tk.Canvas):
2910
2920
  pass
2911
2921
  menu.add_command(**kwargs)
2912
2922
 
2923
+ def table_edit_cell_enabled(self) -> bool:
2924
+ return (
2925
+ self.rc_popup_menus_enabled
2926
+ and self.edit_cell_enabled
2927
+ and any(x in self.enabled_bindings_menu_entries for x in ("all", "edit_cell", "edit_bindings", "edit"))
2928
+ )
2929
+
2930
+ def index_edit_cell_enabled(self) -> bool:
2931
+ return (
2932
+ self.rc_popup_menus_enabled
2933
+ and self.RI.edit_cell_enabled
2934
+ and "edit_index" in self.enabled_bindings_menu_entries
2935
+ )
2936
+
2937
+ def header_edit_cell_enabled(self) -> bool:
2938
+ return (
2939
+ self.rc_popup_menus_enabled
2940
+ and self.CH.edit_cell_enabled
2941
+ and "edit_header" in self.enabled_bindings_menu_entries
2942
+ )
2943
+
2913
2944
  def create_rc_menus(self) -> None:
2914
2945
  if not self.rc_popup_menu:
2915
2946
  self.rc_popup_menu = tk.Menu(self, tearoff=0, background=self.PAR.ops.popup_menu_bg)
@@ -2927,37 +2958,31 @@ class MainTable(tk.Canvas):
2927
2958
  ):
2928
2959
  menu.delete(0, "end")
2929
2960
  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
- ):
2961
+ if self.header_edit_cell_enabled():
2935
2962
  self.menu_add_command(
2936
2963
  self.CH.ch_rc_popup_menu,
2937
2964
  label=self.PAR.ops.edit_header_label,
2938
2965
  command=lambda: self.CH.open_cell(event="rc"),
2966
+ image=self.PAR.ops.edit_header_image,
2967
+ compound=self.PAR.ops.edit_header_compound,
2939
2968
  **mnkwgs,
2940
2969
  )
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
- ):
2970
+ if self.index_edit_cell_enabled():
2946
2971
  self.menu_add_command(
2947
2972
  self.RI.ri_rc_popup_menu,
2948
2973
  label=self.PAR.ops.edit_index_label,
2949
2974
  command=lambda: self.RI.open_cell(event="rc"),
2975
+ image=self.PAR.ops.edit_index_image,
2976
+ compound=self.PAR.ops.edit_index_compound,
2950
2977
  **mnkwgs,
2951
2978
  )
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
- ):
2979
+ if self.table_edit_cell_enabled():
2957
2980
  self.menu_add_command(
2958
2981
  self.rc_popup_menu,
2959
2982
  label=self.PAR.ops.edit_cell_label,
2960
2983
  command=lambda: self.open_cell(event="rc"),
2984
+ image=self.PAR.ops.edit_cell_image,
2985
+ compound=self.PAR.ops.edit_cell_compound,
2961
2986
  **mnkwgs,
2962
2987
  )
2963
2988
  if self.cut_enabled and any(
@@ -2968,6 +2993,8 @@ class MainTable(tk.Canvas):
2968
2993
  label=self.PAR.ops.cut_label,
2969
2994
  accelerator=self.PAR.ops.cut_accelerator,
2970
2995
  command=self.ctrl_x,
2996
+ image=self.PAR.ops.cut_image,
2997
+ compound=self.PAR.ops.cut_compound,
2971
2998
  **mnkwgs,
2972
2999
  )
2973
3000
  self.menu_add_command(
@@ -2975,6 +3002,8 @@ class MainTable(tk.Canvas):
2975
3002
  label=self.PAR.ops.cut_contents_label,
2976
3003
  accelerator=self.PAR.ops.cut_contents_accelerator,
2977
3004
  command=self.ctrl_x,
3005
+ image=self.PAR.ops.cut_contents_image,
3006
+ compound=self.PAR.ops.cut_contents_compound,
2978
3007
  **mnkwgs,
2979
3008
  )
2980
3009
  self.menu_add_command(
@@ -2982,6 +3011,8 @@ class MainTable(tk.Canvas):
2982
3011
  label=self.PAR.ops.cut_contents_label,
2983
3012
  accelerator=self.PAR.ops.cut_contents_accelerator,
2984
3013
  command=self.ctrl_x,
3014
+ image=self.PAR.ops.cut_contents_image,
3015
+ compound=self.PAR.ops.cut_contents_compound,
2985
3016
  **mnkwgs,
2986
3017
  )
2987
3018
  if self.copy_enabled and any(
@@ -2992,6 +3023,8 @@ class MainTable(tk.Canvas):
2992
3023
  label=self.PAR.ops.copy_label,
2993
3024
  accelerator=self.PAR.ops.copy_accelerator,
2994
3025
  command=self.ctrl_c,
3026
+ image=self.PAR.ops.copy_image,
3027
+ compound=self.PAR.ops.copy_compound,
2995
3028
  **mnkwgs,
2996
3029
  )
2997
3030
  self.menu_add_command(
@@ -2999,6 +3032,8 @@ class MainTable(tk.Canvas):
2999
3032
  label=self.PAR.ops.copy_contents_label,
3000
3033
  accelerator=self.PAR.ops.copy_contents_accelerator,
3001
3034
  command=self.ctrl_c,
3035
+ image=self.PAR.ops.copy_contents_image,
3036
+ compound=self.PAR.ops.copy_contents_compound,
3002
3037
  **mnkwgs,
3003
3038
  )
3004
3039
  self.menu_add_command(
@@ -3006,6 +3041,8 @@ class MainTable(tk.Canvas):
3006
3041
  label=self.PAR.ops.copy_contents_label,
3007
3042
  accelerator=self.PAR.ops.copy_contents_accelerator,
3008
3043
  command=self.ctrl_c,
3044
+ image=self.PAR.ops.copy_contents_image,
3045
+ compound=self.PAR.ops.copy_contents_compound,
3009
3046
  **mnkwgs,
3010
3047
  )
3011
3048
  if self.paste_enabled and any(
@@ -3016,6 +3053,8 @@ class MainTable(tk.Canvas):
3016
3053
  label=self.PAR.ops.paste_label,
3017
3054
  accelerator=self.PAR.ops.paste_accelerator,
3018
3055
  command=self.ctrl_v,
3056
+ image=self.PAR.ops.paste_image,
3057
+ compound=self.PAR.ops.paste_compound,
3019
3058
  **mnkwgs,
3020
3059
  )
3021
3060
  self.menu_add_command(
@@ -3023,6 +3062,8 @@ class MainTable(tk.Canvas):
3023
3062
  label=self.PAR.ops.paste_label,
3024
3063
  accelerator=self.PAR.ops.paste_accelerator,
3025
3064
  command=self.ctrl_v,
3065
+ image=self.PAR.ops.paste_image,
3066
+ compound=self.PAR.ops.paste_compound,
3026
3067
  **mnkwgs,
3027
3068
  )
3028
3069
  self.menu_add_command(
@@ -3030,6 +3071,8 @@ class MainTable(tk.Canvas):
3030
3071
  label=self.PAR.ops.paste_label,
3031
3072
  accelerator=self.PAR.ops.paste_accelerator,
3032
3073
  command=self.ctrl_v,
3074
+ image=self.PAR.ops.paste_image,
3075
+ compound=self.PAR.ops.paste_compound,
3033
3076
  **mnkwgs,
3034
3077
  )
3035
3078
  if self.PAR.ops.paste_can_expand_x or self.PAR.ops.paste_can_expand_y:
@@ -3038,6 +3081,8 @@ class MainTable(tk.Canvas):
3038
3081
  label=self.PAR.ops.paste_label,
3039
3082
  accelerator=self.PAR.ops.paste_accelerator,
3040
3083
  command=self.ctrl_v,
3084
+ image=self.PAR.ops.paste_image,
3085
+ compound=self.PAR.ops.paste_compound,
3041
3086
  **mnkwgs,
3042
3087
  )
3043
3088
  if self.delete_key_enabled and any(
@@ -3048,6 +3093,8 @@ class MainTable(tk.Canvas):
3048
3093
  label=self.PAR.ops.delete_label,
3049
3094
  accelerator=self.PAR.ops.delete_accelerator,
3050
3095
  command=self.delete_key,
3096
+ image=self.PAR.ops.delete_image,
3097
+ compound=self.PAR.ops.delete_compound,
3051
3098
  **mnkwgs,
3052
3099
  )
3053
3100
  self.menu_add_command(
@@ -3055,6 +3102,8 @@ class MainTable(tk.Canvas):
3055
3102
  label=self.PAR.ops.clear_contents_label,
3056
3103
  accelerator=self.PAR.ops.clear_contents_accelerator,
3057
3104
  command=self.delete_key,
3105
+ image=self.PAR.ops.clear_contents_image,
3106
+ compound=self.PAR.ops.clear_contents_compound,
3058
3107
  **mnkwgs,
3059
3108
  )
3060
3109
  self.menu_add_command(
@@ -3062,6 +3111,8 @@ class MainTable(tk.Canvas):
3062
3111
  label=self.PAR.ops.clear_contents_label,
3063
3112
  accelerator=self.PAR.ops.clear_contents_accelerator,
3064
3113
  command=self.delete_key,
3114
+ image=self.PAR.ops.clear_contents_image,
3115
+ compound=self.PAR.ops.clear_contents_compound,
3065
3116
  **mnkwgs,
3066
3117
  )
3067
3118
  if self.rc_delete_column_enabled:
@@ -3069,6 +3120,8 @@ class MainTable(tk.Canvas):
3069
3120
  self.CH.ch_rc_popup_menu,
3070
3121
  label=self.PAR.ops.delete_columns_label,
3071
3122
  command=self.delete_columns,
3123
+ image=self.PAR.ops.delete_columns_image,
3124
+ compound=self.PAR.ops.delete_columns_compound,
3072
3125
  **mnkwgs,
3073
3126
  )
3074
3127
  if self.rc_insert_column_enabled:
@@ -3076,18 +3129,24 @@ class MainTable(tk.Canvas):
3076
3129
  self.CH.ch_rc_popup_menu,
3077
3130
  label=self.PAR.ops.insert_columns_left_label,
3078
3131
  command=lambda: self.rc_add_columns("left"),
3132
+ image=self.PAR.ops.insert_columns_left_image,
3133
+ compound=self.PAR.ops.insert_columns_left_compound,
3079
3134
  **mnkwgs,
3080
3135
  )
3081
3136
  self.menu_add_command(
3082
3137
  self.CH.ch_rc_popup_menu,
3083
3138
  label=self.PAR.ops.insert_columns_right_label,
3084
3139
  command=lambda: self.rc_add_columns("right"),
3140
+ image=self.PAR.ops.insert_columns_right_image,
3141
+ compound=self.PAR.ops.insert_columns_right_compound,
3085
3142
  **mnkwgs,
3086
3143
  )
3087
3144
  self.menu_add_command(
3088
3145
  self.empty_rc_popup_menu,
3089
3146
  label=self.PAR.ops.insert_column_label,
3090
3147
  command=lambda: self.rc_add_columns("left"),
3148
+ image=self.PAR.ops.insert_column_image,
3149
+ compound=self.PAR.ops.insert_column_compound,
3091
3150
  **mnkwgs,
3092
3151
  )
3093
3152
  if self.rc_delete_row_enabled:
@@ -3095,6 +3154,8 @@ class MainTable(tk.Canvas):
3095
3154
  self.RI.ri_rc_popup_menu,
3096
3155
  label=self.PAR.ops.delete_rows_label,
3097
3156
  command=self.delete_rows,
3157
+ image=self.PAR.ops.delete_rows_image,
3158
+ compound=self.PAR.ops.delete_rows_compound,
3098
3159
  **mnkwgs,
3099
3160
  )
3100
3161
  if self.rc_insert_row_enabled:
@@ -3102,18 +3163,24 @@ class MainTable(tk.Canvas):
3102
3163
  self.RI.ri_rc_popup_menu,
3103
3164
  label=self.PAR.ops.insert_rows_above_label,
3104
3165
  command=lambda: self.rc_add_rows("above"),
3166
+ image=self.PAR.ops.insert_rows_above_image,
3167
+ compound=self.PAR.ops.insert_rows_above_compound,
3105
3168
  **mnkwgs,
3106
3169
  )
3107
3170
  self.menu_add_command(
3108
3171
  self.RI.ri_rc_popup_menu,
3109
3172
  label=self.PAR.ops.insert_rows_below_label,
3110
3173
  command=lambda: self.rc_add_rows("below"),
3174
+ image=self.PAR.ops.insert_rows_below_image,
3175
+ compound=self.PAR.ops.insert_rows_below_compound,
3111
3176
  **mnkwgs,
3112
3177
  )
3113
3178
  self.menu_add_command(
3114
3179
  self.empty_rc_popup_menu,
3115
3180
  label=self.PAR.ops.insert_row_label,
3116
3181
  command=lambda: self.rc_add_rows("below"),
3182
+ image=self.PAR.ops.insert_row_image,
3183
+ compound=self.PAR.ops.insert_row_compound,
3117
3184
  **mnkwgs,
3118
3185
  )
3119
3186
  if self.rc_sort_cells_enabled:
@@ -3122,6 +3189,8 @@ class MainTable(tk.Canvas):
3122
3189
  label=self.PAR.ops.sort_cells_label,
3123
3190
  accelerator=self.PAR.ops.sort_cells_accelerator,
3124
3191
  command=self.sort_boxes,
3192
+ image=self.PAR.ops.sort_cells_image,
3193
+ compound=self.PAR.ops.sort_cells_compound,
3125
3194
  **mnkwgs,
3126
3195
  )
3127
3196
  self.menu_add_command(
@@ -3129,6 +3198,8 @@ class MainTable(tk.Canvas):
3129
3198
  label=self.PAR.ops.sort_cells_reverse_label,
3130
3199
  accelerator=self.PAR.ops.sort_cells_reverse_accelerator,
3131
3200
  command=lambda: self.sort_boxes(reverse=True),
3201
+ image=self.PAR.ops.sort_cells_reverse_image,
3202
+ compound=self.PAR.ops.sort_cells_reverse_compound,
3132
3203
  **mnkwgs,
3133
3204
  )
3134
3205
  self.menu_add_command(
@@ -3136,6 +3207,8 @@ class MainTable(tk.Canvas):
3136
3207
  label=self.PAR.ops.sort_cells_x_label,
3137
3208
  accelerator=self.PAR.ops.sort_cells_x_accelerator,
3138
3209
  command=lambda: self.sort_boxes(row_wise=True),
3210
+ image=self.PAR.ops.sort_cells_x_image,
3211
+ compound=self.PAR.ops.sort_cells_x_compound,
3139
3212
  **mnkwgs,
3140
3213
  )
3141
3214
  self.menu_add_command(
@@ -3143,6 +3216,8 @@ class MainTable(tk.Canvas):
3143
3216
  label=self.PAR.ops.sort_cells_x_reverse_label,
3144
3217
  accelerator=self.PAR.ops.sort_cells_x_reverse_accelerator,
3145
3218
  command=lambda: self.sort_boxes(reverse=True, row_wise=True),
3219
+ image=self.PAR.ops.sort_cells_x_reverse_image,
3220
+ compound=self.PAR.ops.sort_cells_x_reverse_compound,
3146
3221
  **mnkwgs,
3147
3222
  )
3148
3223
  # row index sort rows cells
@@ -3152,6 +3227,8 @@ class MainTable(tk.Canvas):
3152
3227
  label=self.PAR.ops.sort_row_label,
3153
3228
  accelerator=self.PAR.ops.sort_row_accelerator,
3154
3229
  command=self.RI._sort_rows,
3230
+ image=self.PAR.ops.sort_row_image,
3231
+ compound=self.PAR.ops.sort_row_compound,
3155
3232
  **mnkwgs,
3156
3233
  )
3157
3234
  self.menu_add_command(
@@ -3159,6 +3236,8 @@ class MainTable(tk.Canvas):
3159
3236
  label=self.PAR.ops.sort_row_reverse_label,
3160
3237
  accelerator=self.PAR.ops.sort_row_reverse_accelerator,
3161
3238
  command=lambda: self.RI._sort_rows(reverse=True),
3239
+ image=self.PAR.ops.sort_row_reverse_image,
3240
+ compound=self.PAR.ops.sort_row_reverse_compound,
3162
3241
  **mnkwgs,
3163
3242
  )
3164
3243
  # header sort columns cells
@@ -3168,6 +3247,8 @@ class MainTable(tk.Canvas):
3168
3247
  label=self.PAR.ops.sort_column_label,
3169
3248
  accelerator=self.PAR.ops.sort_column_accelerator,
3170
3249
  command=self.CH._sort_columns,
3250
+ image=self.PAR.ops.sort_column_image,
3251
+ compound=self.PAR.ops.sort_column_compound,
3171
3252
  **mnkwgs,
3172
3253
  )
3173
3254
  self.menu_add_command(
@@ -3175,6 +3256,8 @@ class MainTable(tk.Canvas):
3175
3256
  label=self.PAR.ops.sort_column_reverse_label,
3176
3257
  accelerator=self.PAR.ops.sort_column_reverse_accelerator,
3177
3258
  command=lambda: self.CH._sort_columns(reverse=True),
3259
+ image=self.PAR.ops.sort_column_reverse_image,
3260
+ compound=self.PAR.ops.sort_column_reverse_compound,
3178
3261
  **mnkwgs,
3179
3262
  )
3180
3263
  # row index sort columns by row
@@ -3184,6 +3267,8 @@ class MainTable(tk.Canvas):
3184
3267
  label=self.PAR.ops.sort_columns_label,
3185
3268
  accelerator=self.PAR.ops.sort_columns_accelerator,
3186
3269
  command=self.RI._sort_columns_by_row,
3270
+ image=self.PAR.ops.sort_columns_image,
3271
+ compound=self.PAR.ops.sort_columns_compound,
3187
3272
  **mnkwgs,
3188
3273
  )
3189
3274
  self.menu_add_command(
@@ -3191,6 +3276,8 @@ class MainTable(tk.Canvas):
3191
3276
  label=self.PAR.ops.sort_columns_reverse_label,
3192
3277
  accelerator=self.PAR.ops.sort_columns_reverse_accelerator,
3193
3278
  command=lambda: self.RI._sort_columns_by_row(reverse=True),
3279
+ image=self.PAR.ops.sort_columns_reverse_image,
3280
+ compound=self.PAR.ops.sort_columns_reverse_compound,
3194
3281
  **mnkwgs,
3195
3282
  )
3196
3283
  # header sort rows by column
@@ -3200,6 +3287,8 @@ class MainTable(tk.Canvas):
3200
3287
  label=self.PAR.ops.sort_rows_label,
3201
3288
  accelerator=self.PAR.ops.sort_rows_accelerator,
3202
3289
  command=self.CH._sort_rows_by_column,
3290
+ image=self.PAR.ops.sort_rows_image,
3291
+ compound=self.PAR.ops.sort_rows_compound,
3203
3292
  **mnkwgs,
3204
3293
  )
3205
3294
  self.menu_add_command(
@@ -3207,36 +3296,46 @@ class MainTable(tk.Canvas):
3207
3296
  label=self.PAR.ops.sort_rows_reverse_label,
3208
3297
  accelerator=self.PAR.ops.sort_rows_reverse_accelerator,
3209
3298
  command=lambda: self.CH._sort_rows_by_column(reverse=True),
3299
+ image=self.PAR.ops.sort_rows_reverse_image,
3300
+ compound=self.PAR.ops.sort_rows_reverse_compound,
3210
3301
  **mnkwgs,
3211
3302
  )
3212
- for label, func in self.extra_table_rc_menu_funcs.items():
3213
- self.menu_add_command(
3303
+ if self.undo_enabled and any(
3304
+ x in self.enabled_bindings_menu_entries for x in ("all", "undo", "redo", "edit_bindings", "edit")
3305
+ ):
3306
+ for menu in (
3214
3307
  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
3308
  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
3309
  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
3310
  self.empty_rc_popup_menu,
3236
- label=label,
3237
- command=func,
3238
- **mnkwgs,
3239
- )
3311
+ ):
3312
+ self.menu_add_command(
3313
+ menu,
3314
+ label=self.PAR.ops.undo_label,
3315
+ accelerator=self.PAR.ops.undo_accelerator,
3316
+ command=self.undo,
3317
+ image=self.PAR.ops.undo_image,
3318
+ compound=self.PAR.ops.undo_compound,
3319
+ **mnkwgs,
3320
+ )
3321
+ self.menu_add_command(
3322
+ menu,
3323
+ label=self.PAR.ops.redo_label,
3324
+ accelerator=self.PAR.ops.redo_accelerator,
3325
+ command=self.redo,
3326
+ image=self.PAR.ops.redo_image,
3327
+ compound=self.PAR.ops.redo_compound,
3328
+ **mnkwgs,
3329
+ )
3330
+ # Added popup menu commands
3331
+ for label, kws in self.extra_table_rc_menu_funcs.items():
3332
+ self.menu_add_command(self.rc_popup_menu, label=label, **{**mnkwgs, **kws})
3333
+ for label, kws in self.extra_index_rc_menu_funcs.items():
3334
+ self.menu_add_command(self.RI.ri_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3335
+ for label, kws in self.extra_header_rc_menu_funcs.items():
3336
+ self.menu_add_command(self.CH.ch_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3337
+ for label, kws in self.extra_empty_space_rc_menu_funcs.items():
3338
+ self.menu_add_command(self.empty_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3240
3339
 
3241
3340
  def enable_bindings(self, bindings: Any, menu: bool = True) -> None:
3242
3341
  if not bindings:
@@ -3567,6 +3666,65 @@ class MainTable(tk.Canvas):
3567
3666
  def not_currently_resizing(self) -> bool:
3568
3667
  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
3668
 
3669
+ def is_readonly(self, datarn: int, datacn: int) -> bool:
3670
+ return (
3671
+ ((datarn, datacn) in self.cell_options and "readonly" in self.cell_options[(datarn, datacn)])
3672
+ or (datarn in self.row_options and "readonly" in self.row_options[datarn])
3673
+ or (datacn in self.col_options and "readonly" in self.col_options[datacn])
3674
+ )
3675
+
3676
+ def popup_menu_disable_edit_if_readonly(self, popup_menu: tk.Menu) -> None:
3677
+ # table
3678
+ if (
3679
+ self.selected
3680
+ and self.index_edit_cell_enabled()
3681
+ and menu_item_exists(popup_menu, self.PAR.ops.edit_cell_label)
3682
+ ):
3683
+ datarn, datacn = self.datarn(self.selected.row), self.datacn(self.selected.column)
3684
+ if self.is_readonly(datarn, datacn):
3685
+ popup_menu.entryconfig(self.PAR.ops.edit_cell_label, image="", state="disabled")
3686
+ else:
3687
+ popup_menu.entryconfig(self.PAR.ops.edit_cell_label, image=self.PAR.ops.edit_cell_image, state="normal")
3688
+ # index
3689
+ if (
3690
+ self.selected
3691
+ and self.index_edit_cell_enabled()
3692
+ and menu_item_exists(popup_menu, self.PAR.ops.edit_index_label)
3693
+ ):
3694
+ datarn = self.datarn(self.selected.row)
3695
+ if self.RI.is_readonly(datarn):
3696
+ popup_menu.entryconfig(self.PAR.ops.edit_index_label, image="", state="disabled")
3697
+ else:
3698
+ popup_menu.entryconfig(
3699
+ self.PAR.ops.edit_index_label, image=self.PAR.ops.edit_index_image, state="normal"
3700
+ )
3701
+ # header
3702
+ if (
3703
+ self.selected
3704
+ and self.header_edit_cell_enabled()
3705
+ and menu_item_exists(popup_menu, self.PAR.ops.edit_header_label)
3706
+ ):
3707
+ datacn = self.datacn(self.selected.column)
3708
+ if self.CH.is_readonly(datacn):
3709
+ popup_menu.entryconfig(self.PAR.ops.edit_header_label, image="", state="disabled")
3710
+ else:
3711
+ popup_menu.entryconfig(
3712
+ self.PAR.ops.edit_header_label, image=self.PAR.ops.edit_header_image, state="normal"
3713
+ )
3714
+
3715
+ def popup_menu_disable_undo_redo(self, popup_menu: tk.Menu) -> None:
3716
+ if not self.undo_enabled:
3717
+ return
3718
+ if menu_item_exists(popup_menu, self.PAR.ops.undo_label):
3719
+ if not self.undo_stack:
3720
+ popup_menu.entryconfig(self.PAR.ops.undo_label, image="", state="disabled")
3721
+ else:
3722
+ popup_menu.entryconfig(self.PAR.ops.undo_label, image=self.PAR.ops.undo_image, state="normal")
3723
+ if not self.redo_stack:
3724
+ popup_menu.entryconfig(self.PAR.ops.redo_label, image="", state="disabled")
3725
+ else:
3726
+ popup_menu.entryconfig(self.PAR.ops.redo_label, image=self.PAR.ops.redo_image, state="normal")
3727
+
3570
3728
  def rc(self, event: Any = None) -> None:
3571
3729
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
3572
3730
  self.focus_set()
@@ -3598,6 +3756,8 @@ class MainTable(tk.Canvas):
3598
3756
  popup_menu = self.empty_rc_popup_menu
3599
3757
  try_binding(self.extra_rc_func, event)
3600
3758
  if popup_menu:
3759
+ self.popup_menu_disable_edit_if_readonly(popup_menu)
3760
+ self.popup_menu_disable_undo_redo(popup_menu)
3601
3761
  popup_menu.tk_popup(event.x_root, event.y_root)
3602
3762
 
3603
3763
  def b1_press(self, event: Any = None) -> None:
tksheet/row_index.py CHANGED
@@ -160,6 +160,9 @@ class RowIndex(tk.Canvas):
160
160
  self.MT.recreate_all_selection_boxes()
161
161
  self.current_width = new_width
162
162
 
163
+ def is_readonly(self, datarn: int) -> bool:
164
+ return datarn in self.cell_options and "readonly" in self.cell_options[datarn]
165
+
163
166
  def rc(self, event: Any) -> None:
164
167
  self.mouseclick_outside_editor_or_dropdown_all_canvases(inside=True)
165
168
  self.focus_set()
@@ -185,6 +188,8 @@ class RowIndex(tk.Canvas):
185
188
  try_binding(self.extra_rc_func, event)
186
189
  if popup_menu is not None:
187
190
  self.popup_menu_loc = r
191
+ self.MT.popup_menu_disable_edit_if_readonly(popup_menu)
192
+ self.MT.popup_menu_disable_undo_redo(popup_menu)
188
193
  popup_menu.tk_popup(event.x_root, event.y_root)
189
194
 
190
195
  def ctrl_b1_press(self, event: Any) -> None: