tksheet 7.4.23__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:
@@ -1796,6 +1806,9 @@ class MainTable(tk.Canvas):
1796
1806
  disp_new_idxs=disp_new_idxs,
1797
1807
  maxidx=maxidx,
1798
1808
  event_data=event_data,
1809
+ # undo_modification is the old saved stuff
1810
+ # event_data is the new event
1811
+ # node change only comes from Sheet.move()
1799
1812
  undo_modification=undo_modification,
1800
1813
  node_change=node_change,
1801
1814
  )
@@ -2020,8 +2033,9 @@ class MainTable(tk.Canvas):
2020
2033
  self.PAR.emit_event("<<Redo>>", event_data)
2021
2034
  return event_data
2022
2035
 
2023
- def sheet_modified(self, event_data: EventDataDict, purge_redo: bool = True) -> None:
2024
- self.PAR.emit_event("<<SheetModified>>", event_data)
2036
+ def sheet_modified(self, event_data: EventDataDict, purge_redo: bool = True, emit_event: bool = True) -> None:
2037
+ if emit_event:
2038
+ self.PAR.emit_event("<<SheetModified>>", event_data)
2025
2039
  if purge_redo:
2026
2040
  self.purge_redo_stack()
2027
2041
 
@@ -2906,6 +2920,27 @@ class MainTable(tk.Canvas):
2906
2920
  pass
2907
2921
  menu.add_command(**kwargs)
2908
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
+
2909
2944
  def create_rc_menus(self) -> None:
2910
2945
  if not self.rc_popup_menu:
2911
2946
  self.rc_popup_menu = tk.Menu(self, tearoff=0, background=self.PAR.ops.popup_menu_bg)
@@ -2923,37 +2958,31 @@ class MainTable(tk.Canvas):
2923
2958
  ):
2924
2959
  menu.delete(0, "end")
2925
2960
  mnkwgs = get_menu_kwargs(self.PAR.ops)
2926
- if (
2927
- self.rc_popup_menus_enabled
2928
- and self.CH.edit_cell_enabled
2929
- and "edit_header" in self.enabled_bindings_menu_entries
2930
- ):
2961
+ if self.header_edit_cell_enabled():
2931
2962
  self.menu_add_command(
2932
2963
  self.CH.ch_rc_popup_menu,
2933
2964
  label=self.PAR.ops.edit_header_label,
2934
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,
2935
2968
  **mnkwgs,
2936
2969
  )
2937
- if (
2938
- self.rc_popup_menus_enabled
2939
- and self.RI.edit_cell_enabled
2940
- and "edit_index" in self.enabled_bindings_menu_entries
2941
- ):
2970
+ if self.index_edit_cell_enabled():
2942
2971
  self.menu_add_command(
2943
2972
  self.RI.ri_rc_popup_menu,
2944
2973
  label=self.PAR.ops.edit_index_label,
2945
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,
2946
2977
  **mnkwgs,
2947
2978
  )
2948
- if (
2949
- self.rc_popup_menus_enabled
2950
- and self.edit_cell_enabled
2951
- and any(x in self.enabled_bindings_menu_entries for x in ("all", "edit_cell", "edit_bindings", "edit"))
2952
- ):
2979
+ if self.table_edit_cell_enabled():
2953
2980
  self.menu_add_command(
2954
2981
  self.rc_popup_menu,
2955
2982
  label=self.PAR.ops.edit_cell_label,
2956
2983
  command=lambda: self.open_cell(event="rc"),
2984
+ image=self.PAR.ops.edit_cell_image,
2985
+ compound=self.PAR.ops.edit_cell_compound,
2957
2986
  **mnkwgs,
2958
2987
  )
2959
2988
  if self.cut_enabled and any(
@@ -2964,6 +2993,8 @@ class MainTable(tk.Canvas):
2964
2993
  label=self.PAR.ops.cut_label,
2965
2994
  accelerator=self.PAR.ops.cut_accelerator,
2966
2995
  command=self.ctrl_x,
2996
+ image=self.PAR.ops.cut_image,
2997
+ compound=self.PAR.ops.cut_compound,
2967
2998
  **mnkwgs,
2968
2999
  )
2969
3000
  self.menu_add_command(
@@ -2971,6 +3002,8 @@ class MainTable(tk.Canvas):
2971
3002
  label=self.PAR.ops.cut_contents_label,
2972
3003
  accelerator=self.PAR.ops.cut_contents_accelerator,
2973
3004
  command=self.ctrl_x,
3005
+ image=self.PAR.ops.cut_contents_image,
3006
+ compound=self.PAR.ops.cut_contents_compound,
2974
3007
  **mnkwgs,
2975
3008
  )
2976
3009
  self.menu_add_command(
@@ -2978,6 +3011,8 @@ class MainTable(tk.Canvas):
2978
3011
  label=self.PAR.ops.cut_contents_label,
2979
3012
  accelerator=self.PAR.ops.cut_contents_accelerator,
2980
3013
  command=self.ctrl_x,
3014
+ image=self.PAR.ops.cut_contents_image,
3015
+ compound=self.PAR.ops.cut_contents_compound,
2981
3016
  **mnkwgs,
2982
3017
  )
2983
3018
  if self.copy_enabled and any(
@@ -2988,6 +3023,8 @@ class MainTable(tk.Canvas):
2988
3023
  label=self.PAR.ops.copy_label,
2989
3024
  accelerator=self.PAR.ops.copy_accelerator,
2990
3025
  command=self.ctrl_c,
3026
+ image=self.PAR.ops.copy_image,
3027
+ compound=self.PAR.ops.copy_compound,
2991
3028
  **mnkwgs,
2992
3029
  )
2993
3030
  self.menu_add_command(
@@ -2995,6 +3032,8 @@ class MainTable(tk.Canvas):
2995
3032
  label=self.PAR.ops.copy_contents_label,
2996
3033
  accelerator=self.PAR.ops.copy_contents_accelerator,
2997
3034
  command=self.ctrl_c,
3035
+ image=self.PAR.ops.copy_contents_image,
3036
+ compound=self.PAR.ops.copy_contents_compound,
2998
3037
  **mnkwgs,
2999
3038
  )
3000
3039
  self.menu_add_command(
@@ -3002,6 +3041,8 @@ class MainTable(tk.Canvas):
3002
3041
  label=self.PAR.ops.copy_contents_label,
3003
3042
  accelerator=self.PAR.ops.copy_contents_accelerator,
3004
3043
  command=self.ctrl_c,
3044
+ image=self.PAR.ops.copy_contents_image,
3045
+ compound=self.PAR.ops.copy_contents_compound,
3005
3046
  **mnkwgs,
3006
3047
  )
3007
3048
  if self.paste_enabled and any(
@@ -3012,6 +3053,8 @@ class MainTable(tk.Canvas):
3012
3053
  label=self.PAR.ops.paste_label,
3013
3054
  accelerator=self.PAR.ops.paste_accelerator,
3014
3055
  command=self.ctrl_v,
3056
+ image=self.PAR.ops.paste_image,
3057
+ compound=self.PAR.ops.paste_compound,
3015
3058
  **mnkwgs,
3016
3059
  )
3017
3060
  self.menu_add_command(
@@ -3019,6 +3062,8 @@ class MainTable(tk.Canvas):
3019
3062
  label=self.PAR.ops.paste_label,
3020
3063
  accelerator=self.PAR.ops.paste_accelerator,
3021
3064
  command=self.ctrl_v,
3065
+ image=self.PAR.ops.paste_image,
3066
+ compound=self.PAR.ops.paste_compound,
3022
3067
  **mnkwgs,
3023
3068
  )
3024
3069
  self.menu_add_command(
@@ -3026,6 +3071,8 @@ class MainTable(tk.Canvas):
3026
3071
  label=self.PAR.ops.paste_label,
3027
3072
  accelerator=self.PAR.ops.paste_accelerator,
3028
3073
  command=self.ctrl_v,
3074
+ image=self.PAR.ops.paste_image,
3075
+ compound=self.PAR.ops.paste_compound,
3029
3076
  **mnkwgs,
3030
3077
  )
3031
3078
  if self.PAR.ops.paste_can_expand_x or self.PAR.ops.paste_can_expand_y:
@@ -3034,6 +3081,8 @@ class MainTable(tk.Canvas):
3034
3081
  label=self.PAR.ops.paste_label,
3035
3082
  accelerator=self.PAR.ops.paste_accelerator,
3036
3083
  command=self.ctrl_v,
3084
+ image=self.PAR.ops.paste_image,
3085
+ compound=self.PAR.ops.paste_compound,
3037
3086
  **mnkwgs,
3038
3087
  )
3039
3088
  if self.delete_key_enabled and any(
@@ -3044,6 +3093,8 @@ class MainTable(tk.Canvas):
3044
3093
  label=self.PAR.ops.delete_label,
3045
3094
  accelerator=self.PAR.ops.delete_accelerator,
3046
3095
  command=self.delete_key,
3096
+ image=self.PAR.ops.delete_image,
3097
+ compound=self.PAR.ops.delete_compound,
3047
3098
  **mnkwgs,
3048
3099
  )
3049
3100
  self.menu_add_command(
@@ -3051,6 +3102,8 @@ class MainTable(tk.Canvas):
3051
3102
  label=self.PAR.ops.clear_contents_label,
3052
3103
  accelerator=self.PAR.ops.clear_contents_accelerator,
3053
3104
  command=self.delete_key,
3105
+ image=self.PAR.ops.clear_contents_image,
3106
+ compound=self.PAR.ops.clear_contents_compound,
3054
3107
  **mnkwgs,
3055
3108
  )
3056
3109
  self.menu_add_command(
@@ -3058,6 +3111,8 @@ class MainTable(tk.Canvas):
3058
3111
  label=self.PAR.ops.clear_contents_label,
3059
3112
  accelerator=self.PAR.ops.clear_contents_accelerator,
3060
3113
  command=self.delete_key,
3114
+ image=self.PAR.ops.clear_contents_image,
3115
+ compound=self.PAR.ops.clear_contents_compound,
3061
3116
  **mnkwgs,
3062
3117
  )
3063
3118
  if self.rc_delete_column_enabled:
@@ -3065,6 +3120,8 @@ class MainTable(tk.Canvas):
3065
3120
  self.CH.ch_rc_popup_menu,
3066
3121
  label=self.PAR.ops.delete_columns_label,
3067
3122
  command=self.delete_columns,
3123
+ image=self.PAR.ops.delete_columns_image,
3124
+ compound=self.PAR.ops.delete_columns_compound,
3068
3125
  **mnkwgs,
3069
3126
  )
3070
3127
  if self.rc_insert_column_enabled:
@@ -3072,18 +3129,24 @@ class MainTable(tk.Canvas):
3072
3129
  self.CH.ch_rc_popup_menu,
3073
3130
  label=self.PAR.ops.insert_columns_left_label,
3074
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,
3075
3134
  **mnkwgs,
3076
3135
  )
3077
3136
  self.menu_add_command(
3078
3137
  self.CH.ch_rc_popup_menu,
3079
3138
  label=self.PAR.ops.insert_columns_right_label,
3080
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,
3081
3142
  **mnkwgs,
3082
3143
  )
3083
3144
  self.menu_add_command(
3084
3145
  self.empty_rc_popup_menu,
3085
3146
  label=self.PAR.ops.insert_column_label,
3086
3147
  command=lambda: self.rc_add_columns("left"),
3148
+ image=self.PAR.ops.insert_column_image,
3149
+ compound=self.PAR.ops.insert_column_compound,
3087
3150
  **mnkwgs,
3088
3151
  )
3089
3152
  if self.rc_delete_row_enabled:
@@ -3091,6 +3154,8 @@ class MainTable(tk.Canvas):
3091
3154
  self.RI.ri_rc_popup_menu,
3092
3155
  label=self.PAR.ops.delete_rows_label,
3093
3156
  command=self.delete_rows,
3157
+ image=self.PAR.ops.delete_rows_image,
3158
+ compound=self.PAR.ops.delete_rows_compound,
3094
3159
  **mnkwgs,
3095
3160
  )
3096
3161
  if self.rc_insert_row_enabled:
@@ -3098,18 +3163,24 @@ class MainTable(tk.Canvas):
3098
3163
  self.RI.ri_rc_popup_menu,
3099
3164
  label=self.PAR.ops.insert_rows_above_label,
3100
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,
3101
3168
  **mnkwgs,
3102
3169
  )
3103
3170
  self.menu_add_command(
3104
3171
  self.RI.ri_rc_popup_menu,
3105
3172
  label=self.PAR.ops.insert_rows_below_label,
3106
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,
3107
3176
  **mnkwgs,
3108
3177
  )
3109
3178
  self.menu_add_command(
3110
3179
  self.empty_rc_popup_menu,
3111
3180
  label=self.PAR.ops.insert_row_label,
3112
3181
  command=lambda: self.rc_add_rows("below"),
3182
+ image=self.PAR.ops.insert_row_image,
3183
+ compound=self.PAR.ops.insert_row_compound,
3113
3184
  **mnkwgs,
3114
3185
  )
3115
3186
  if self.rc_sort_cells_enabled:
@@ -3118,6 +3189,8 @@ class MainTable(tk.Canvas):
3118
3189
  label=self.PAR.ops.sort_cells_label,
3119
3190
  accelerator=self.PAR.ops.sort_cells_accelerator,
3120
3191
  command=self.sort_boxes,
3192
+ image=self.PAR.ops.sort_cells_image,
3193
+ compound=self.PAR.ops.sort_cells_compound,
3121
3194
  **mnkwgs,
3122
3195
  )
3123
3196
  self.menu_add_command(
@@ -3125,6 +3198,8 @@ class MainTable(tk.Canvas):
3125
3198
  label=self.PAR.ops.sort_cells_reverse_label,
3126
3199
  accelerator=self.PAR.ops.sort_cells_reverse_accelerator,
3127
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,
3128
3203
  **mnkwgs,
3129
3204
  )
3130
3205
  self.menu_add_command(
@@ -3132,6 +3207,8 @@ class MainTable(tk.Canvas):
3132
3207
  label=self.PAR.ops.sort_cells_x_label,
3133
3208
  accelerator=self.PAR.ops.sort_cells_x_accelerator,
3134
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,
3135
3212
  **mnkwgs,
3136
3213
  )
3137
3214
  self.menu_add_command(
@@ -3139,6 +3216,8 @@ class MainTable(tk.Canvas):
3139
3216
  label=self.PAR.ops.sort_cells_x_reverse_label,
3140
3217
  accelerator=self.PAR.ops.sort_cells_x_reverse_accelerator,
3141
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,
3142
3221
  **mnkwgs,
3143
3222
  )
3144
3223
  # row index sort rows cells
@@ -3148,6 +3227,8 @@ class MainTable(tk.Canvas):
3148
3227
  label=self.PAR.ops.sort_row_label,
3149
3228
  accelerator=self.PAR.ops.sort_row_accelerator,
3150
3229
  command=self.RI._sort_rows,
3230
+ image=self.PAR.ops.sort_row_image,
3231
+ compound=self.PAR.ops.sort_row_compound,
3151
3232
  **mnkwgs,
3152
3233
  )
3153
3234
  self.menu_add_command(
@@ -3155,6 +3236,8 @@ class MainTable(tk.Canvas):
3155
3236
  label=self.PAR.ops.sort_row_reverse_label,
3156
3237
  accelerator=self.PAR.ops.sort_row_reverse_accelerator,
3157
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,
3158
3241
  **mnkwgs,
3159
3242
  )
3160
3243
  # header sort columns cells
@@ -3164,6 +3247,8 @@ class MainTable(tk.Canvas):
3164
3247
  label=self.PAR.ops.sort_column_label,
3165
3248
  accelerator=self.PAR.ops.sort_column_accelerator,
3166
3249
  command=self.CH._sort_columns,
3250
+ image=self.PAR.ops.sort_column_image,
3251
+ compound=self.PAR.ops.sort_column_compound,
3167
3252
  **mnkwgs,
3168
3253
  )
3169
3254
  self.menu_add_command(
@@ -3171,6 +3256,8 @@ class MainTable(tk.Canvas):
3171
3256
  label=self.PAR.ops.sort_column_reverse_label,
3172
3257
  accelerator=self.PAR.ops.sort_column_reverse_accelerator,
3173
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,
3174
3261
  **mnkwgs,
3175
3262
  )
3176
3263
  # row index sort columns by row
@@ -3180,6 +3267,8 @@ class MainTable(tk.Canvas):
3180
3267
  label=self.PAR.ops.sort_columns_label,
3181
3268
  accelerator=self.PAR.ops.sort_columns_accelerator,
3182
3269
  command=self.RI._sort_columns_by_row,
3270
+ image=self.PAR.ops.sort_columns_image,
3271
+ compound=self.PAR.ops.sort_columns_compound,
3183
3272
  **mnkwgs,
3184
3273
  )
3185
3274
  self.menu_add_command(
@@ -3187,6 +3276,8 @@ class MainTable(tk.Canvas):
3187
3276
  label=self.PAR.ops.sort_columns_reverse_label,
3188
3277
  accelerator=self.PAR.ops.sort_columns_reverse_accelerator,
3189
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,
3190
3281
  **mnkwgs,
3191
3282
  )
3192
3283
  # header sort rows by column
@@ -3196,6 +3287,8 @@ class MainTable(tk.Canvas):
3196
3287
  label=self.PAR.ops.sort_rows_label,
3197
3288
  accelerator=self.PAR.ops.sort_rows_accelerator,
3198
3289
  command=self.CH._sort_rows_by_column,
3290
+ image=self.PAR.ops.sort_rows_image,
3291
+ compound=self.PAR.ops.sort_rows_compound,
3199
3292
  **mnkwgs,
3200
3293
  )
3201
3294
  self.menu_add_command(
@@ -3203,36 +3296,46 @@ class MainTable(tk.Canvas):
3203
3296
  label=self.PAR.ops.sort_rows_reverse_label,
3204
3297
  accelerator=self.PAR.ops.sort_rows_reverse_accelerator,
3205
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,
3206
3301
  **mnkwgs,
3207
3302
  )
3208
- for label, func in self.extra_table_rc_menu_funcs.items():
3209
- 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 (
3210
3307
  self.rc_popup_menu,
3211
- label=label,
3212
- command=func,
3213
- **mnkwgs,
3214
- )
3215
- for label, func in self.extra_index_rc_menu_funcs.items():
3216
- self.menu_add_command(
3217
3308
  self.RI.ri_rc_popup_menu,
3218
- label=label,
3219
- command=func,
3220
- **mnkwgs,
3221
- )
3222
- for label, func in self.extra_header_rc_menu_funcs.items():
3223
- self.menu_add_command(
3224
3309
  self.CH.ch_rc_popup_menu,
3225
- label=label,
3226
- command=func,
3227
- **mnkwgs,
3228
- )
3229
- for label, func in self.extra_empty_space_rc_menu_funcs.items():
3230
- self.menu_add_command(
3231
3310
  self.empty_rc_popup_menu,
3232
- label=label,
3233
- command=func,
3234
- **mnkwgs,
3235
- )
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})
3236
3339
 
3237
3340
  def enable_bindings(self, bindings: Any, menu: bool = True) -> None:
3238
3341
  if not bindings:
@@ -3563,6 +3666,65 @@ class MainTable(tk.Canvas):
3563
3666
  def not_currently_resizing(self) -> bool:
3564
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))
3565
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
+
3566
3728
  def rc(self, event: Any = None) -> None:
3567
3729
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
3568
3730
  self.focus_set()
@@ -3594,6 +3756,8 @@ class MainTable(tk.Canvas):
3594
3756
  popup_menu = self.empty_rc_popup_menu
3595
3757
  try_binding(self.extra_rc_func, event)
3596
3758
  if popup_menu:
3759
+ self.popup_menu_disable_edit_if_readonly(popup_menu)
3760
+ self.popup_menu_disable_undo_redo(popup_menu)
3597
3761
  popup_menu.tk_popup(event.x_root, event.y_root)
3598
3762
 
3599
3763
  def b1_press(self, event: Any = None) -> None:
@@ -7603,9 +7767,30 @@ class MainTable(tk.Canvas):
7603
7767
  return
7604
7768
  if numcols == 1 and numrows == 1:
7605
7769
  if direction == "right":
7606
- self.select_right(r, c)
7770
+ new_r, new_c = cell_right_within_box(
7771
+ r,
7772
+ c,
7773
+ 0,
7774
+ 0,
7775
+ len(self.row_positions) - 1,
7776
+ len(self.col_positions) - 1,
7777
+ len(self.row_positions) - 1,
7778
+ len(self.col_positions) - 1,
7779
+ )
7607
7780
  elif direction == "down":
7608
- self.select_down(r, c)
7781
+ new_r, new_c = cell_down_within_box(
7782
+ r,
7783
+ c,
7784
+ 0,
7785
+ 0,
7786
+ len(self.row_positions) - 1,
7787
+ len(self.col_positions) - 1,
7788
+ len(self.row_positions) - 1,
7789
+ len(self.col_positions) - 1,
7790
+ )
7791
+ if direction in ("right", "down"):
7792
+ self.select_cell(new_r, new_c)
7793
+ self.see(new_r, new_c)
7609
7794
  else:
7610
7795
  if direction == "right":
7611
7796
  new_r, new_c = cell_right_within_box(r, c, r1, c1, r2, c2, numrows, numcols)
@@ -7631,28 +7816,34 @@ class MainTable(tk.Canvas):
7631
7816
  value = None
7632
7817
  return value, event_data
7633
7818
 
7634
- def select_right(self, r: int, c: int) -> None:
7635
- self.select_cell(r, c + 1 if c < len(self.col_positions) - 2 else c)
7636
- self.see(
7637
- r,
7638
- c + 1 if c < len(self.col_positions) - 2 else c,
7639
- bottom_right_corner=True,
7640
- )
7641
-
7642
- def select_down(self, r: int, c: int) -> None:
7643
- self.select_cell(r + 1 if r < len(self.row_positions) - 2 else r, c)
7644
- self.see(r + 1 if r < len(self.row_positions) - 2 else r, c)
7645
-
7646
7819
  def tab_key(self, event: Any = None) -> str:
7647
- if not self.selected:
7648
- return
7649
- r, c = self.selected.row, self.selected.column
7650
- r1, c1, r2, c2 = self.selection_boxes[self.selected.fill_iid].coords
7651
- numcols = c2 - c1
7652
- numrows = r2 - r1
7820
+ if self.selected:
7821
+ r, c = self.selected.row, self.selected.column
7822
+ r1, c1, r2, c2 = self.selection_boxes[self.selected.fill_iid].coords
7823
+ numcols = c2 - c1
7824
+ numrows = r2 - r1
7825
+ else:
7826
+ if (
7827
+ self.row_positions == [0]
7828
+ or self.col_positions == [0]
7829
+ or not self.row_positions
7830
+ or not self.col_positions
7831
+ ):
7832
+ return
7833
+ r, c = len(self.row_positions) - 2, len(self.col_positions) - 2
7834
+ r1, c1, r2, c2 = 0, 0, len(self.row_positions) - 1, len(self.col_positions) - 1
7835
+ numcols, numrows = 1, 1
7653
7836
  if numcols == 1 and numrows == 1:
7654
- new_r = r
7655
- new_c = c + 1 if c < len(self.col_positions) - 2 else c
7837
+ new_r, new_c = cell_right_within_box(
7838
+ r,
7839
+ c,
7840
+ 0,
7841
+ 0,
7842
+ len(self.row_positions) - 1,
7843
+ len(self.col_positions) - 1,
7844
+ len(self.row_positions) - 1,
7845
+ len(self.col_positions) - 1,
7846
+ )
7656
7847
  self.select_cell(new_r, new_c)
7657
7848
  else:
7658
7849
  new_r, new_c = cell_right_within_box(r, c, r1, c1, r2, c2, numrows, numcols)