tksheet 7.5.5__py3-none-any.whl → 7.5.8__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,7 +71,6 @@ from .functions import (
71
71
  is_last_cell,
72
72
  is_type_int,
73
73
  len_to_idx,
74
- menu_item_exists,
75
74
  mod_event_val,
76
75
  mod_span,
77
76
  move_elements_by_mapping_gen,
@@ -79,12 +78,16 @@ from .functions import (
79
78
  new_tk_event,
80
79
  next_cell,
81
80
  push_n,
81
+ recursive_bind,
82
82
  rounded_box_coords,
83
+ safe_copy,
83
84
  span_idxs_post_move,
84
85
  stored_event_dict,
85
86
  try_binding,
87
+ widget_descendants,
86
88
  wrap_text,
87
89
  )
90
+ from .menus import build_empty_rc_menu, build_header_rc_menu, build_index_rc_menu, build_table_rc_menu
88
91
  from .other_classes import (
89
92
  Box_nt,
90
93
  Box_st,
@@ -104,6 +107,7 @@ from .row_index import RowIndex
104
107
  from .sorting import sort_selection
105
108
  from .text_editor import TextEditor
106
109
  from .tksheet_types import Binding
110
+ from .tooltip import Tooltip
107
111
 
108
112
 
109
113
  class MainTable(tk.Canvas):
@@ -133,6 +137,18 @@ class MainTable(tk.Canvas):
133
137
  self.allow_auto_resize_rows = True
134
138
  self.span = self.PAR.span
135
139
  self.synced_scrolls = set()
140
+ self.tooltip = Tooltip(
141
+ **{
142
+ "parent": self,
143
+ "sheet_ops": self.PAR.ops,
144
+ "menu_kwargs": get_menu_kwargs(self.PAR.ops),
145
+ **get_bg_fg(self.PAR.ops),
146
+ "scrollbar_style": f"Sheet{self.PAR.unique_id}.Vertical.TScrollbar",
147
+ }
148
+ )
149
+ self.tooltip_widgets = widget_descendants(self.tooltip)
150
+ self.tooltip_coords, self.tooltip_after_id, self.tooltip_showing = None, None, False
151
+ recursive_bind(self.tooltip, "<Leave>", self.close_tooltip_save)
136
152
  self.dropdown = DropdownStorage()
137
153
  self.text_editor = TextEditorStorage()
138
154
  self.find_window = EditorStorageBase()
@@ -156,18 +172,20 @@ class MainTable(tk.Canvas):
156
172
  self.disp_text = {}
157
173
  self.disp_high = {}
158
174
  self.disp_grid = {}
175
+ self.disp_borders = set()
159
176
  self.disp_resize_lines = {}
160
177
  self.disp_dropdown = {}
161
178
  self.disp_checkbox = {}
162
- self.disp_boxes = set()
179
+ self.disp_corners = set()
163
180
  self.hidd_ctrl_outline = {}
164
181
  self.hidd_text = {}
165
182
  self.hidd_high = {}
166
183
  self.hidd_grid = {}
184
+ self.hidd_borders = set()
167
185
  self.hidd_resize_lines = {}
168
186
  self.hidd_dropdown = {}
169
187
  self.hidd_checkbox = {}
170
- self.hidd_boxes = set()
188
+ self.hidd_corners = set()
171
189
 
172
190
  self.selection_boxes = {}
173
191
  self.selected = ()
@@ -364,7 +382,6 @@ class MainTable(tk.Canvas):
364
382
  self.rc_popup_menu, self.empty_rc_popup_menu = None, None
365
383
  self.reset_col_positions()
366
384
  self.basic_bindings()
367
- self.create_rc_menus()
368
385
 
369
386
  def event_generate(self, *args, **kwargs) -> None:
370
387
  for arg in args:
@@ -638,19 +655,8 @@ class MainTable(tk.Canvas):
638
655
  if m:
639
656
  current = f"{self.get_cell_data(datarn, datacn, True)}"
640
657
  new = sub(escape(find), replacer(find, replace, current), current, flags=IGNORECASE)
641
- event_data = event_dict(
642
- name="end_edit_table",
643
- sheet=self.PAR.name,
644
- widget=self,
645
- cells_table={(datarn, datacn): self.get_cell_data(datarn, datacn)},
646
- key="replace_next",
647
- value=new,
648
- loc=Loc(sel.row, sel.column),
649
- row=sel.row,
650
- column=sel.column,
651
- boxes=self.get_boxes(),
652
- selected=self.selected,
653
- data={(datarn, datacn): new},
658
+ event_data = self.new_single_edit_event(
659
+ sel.row, sel.column, datarn, datacn, "replace_next", self.get_cell_data(datarn, datacn), new
654
660
  )
655
661
  value, event_data = self.single_edit_run_validation(datarn, datacn, event_data)
656
662
  if value is not None and (
@@ -994,6 +1000,24 @@ class MainTable(tk.Canvas):
994
1000
  sheet_state=self.copy_sheet_state() if state else None,
995
1001
  )
996
1002
 
1003
+ def new_single_edit_event(
1004
+ self, r: int, c: int, datarn: int, datacn: int, k: str, before_val: Any, after_val: Any
1005
+ ) -> EventDataDict:
1006
+ return event_dict(
1007
+ name="end_edit_table",
1008
+ sheet=self.PAR.name,
1009
+ widget=self,
1010
+ cells_table={(datarn, datacn): before_val},
1011
+ key=k,
1012
+ value=after_val,
1013
+ loc=Loc(r, c),
1014
+ row=r,
1015
+ column=c,
1016
+ boxes=self.get_boxes(),
1017
+ selected=self.selected,
1018
+ data={(datarn, datacn): after_val},
1019
+ )
1020
+
997
1021
  def ctrl_c(self, event=None) -> None | EventDataDict:
998
1022
  if not self.selected:
999
1023
  return
@@ -2957,392 +2981,6 @@ class MainTable(tk.Canvas):
2957
2981
  self.RI.ri_rc_popup_menu = tk.Menu(self.RI, tearoff=0, background=self.PAR.ops.popup_menu_bg)
2958
2982
  if not self.empty_rc_popup_menu:
2959
2983
  self.empty_rc_popup_menu = tk.Menu(self, tearoff=0, background=self.PAR.ops.popup_menu_bg)
2960
- for menu in (
2961
- self.rc_popup_menu,
2962
- self.CH.ch_rc_popup_menu,
2963
- self.RI.ri_rc_popup_menu,
2964
- self.empty_rc_popup_menu,
2965
- ):
2966
- menu.delete(0, "end")
2967
- mnkwgs = get_menu_kwargs(self.PAR.ops)
2968
- if self.header_edit_cell_enabled():
2969
- self.menu_add_command(
2970
- self.CH.ch_rc_popup_menu,
2971
- label=self.PAR.ops.edit_header_label,
2972
- command=lambda: self.CH.open_cell(event="rc"),
2973
- image=self.PAR.ops.edit_header_image,
2974
- compound=self.PAR.ops.edit_header_compound,
2975
- **mnkwgs,
2976
- )
2977
- if self.index_edit_cell_enabled():
2978
- self.menu_add_command(
2979
- self.RI.ri_rc_popup_menu,
2980
- label=self.PAR.ops.edit_index_label,
2981
- command=lambda: self.RI.open_cell(event="rc"),
2982
- image=self.PAR.ops.edit_index_image,
2983
- compound=self.PAR.ops.edit_index_compound,
2984
- **mnkwgs,
2985
- )
2986
- if self.table_edit_cell_enabled():
2987
- self.menu_add_command(
2988
- self.rc_popup_menu,
2989
- label=self.PAR.ops.edit_cell_label,
2990
- command=lambda: self.open_cell(event="rc"),
2991
- image=self.PAR.ops.edit_cell_image,
2992
- compound=self.PAR.ops.edit_cell_compound,
2993
- **mnkwgs,
2994
- )
2995
- if self.cut_enabled and any(
2996
- x in self.enabled_bindings_menu_entries for x in ("all", "cut", "edit_bindings", "edit")
2997
- ):
2998
- self.menu_add_command(
2999
- self.rc_popup_menu,
3000
- label=self.PAR.ops.cut_label,
3001
- accelerator=self.PAR.ops.cut_accelerator,
3002
- command=self.ctrl_x,
3003
- image=self.PAR.ops.cut_image,
3004
- compound=self.PAR.ops.cut_compound,
3005
- **mnkwgs,
3006
- )
3007
- self.menu_add_command(
3008
- self.CH.ch_rc_popup_menu,
3009
- label=self.PAR.ops.cut_contents_label,
3010
- accelerator=self.PAR.ops.cut_contents_accelerator,
3011
- command=self.ctrl_x,
3012
- image=self.PAR.ops.cut_contents_image,
3013
- compound=self.PAR.ops.cut_contents_compound,
3014
- **mnkwgs,
3015
- )
3016
- self.menu_add_command(
3017
- self.RI.ri_rc_popup_menu,
3018
- label=self.PAR.ops.cut_contents_label,
3019
- accelerator=self.PAR.ops.cut_contents_accelerator,
3020
- command=self.ctrl_x,
3021
- image=self.PAR.ops.cut_contents_image,
3022
- compound=self.PAR.ops.cut_contents_compound,
3023
- **mnkwgs,
3024
- )
3025
- if self.copy_enabled and any(
3026
- x in self.enabled_bindings_menu_entries for x in ("all", "copy", "edit_bindings", "edit")
3027
- ):
3028
- self.menu_add_command(
3029
- self.rc_popup_menu,
3030
- label=self.PAR.ops.copy_label,
3031
- accelerator=self.PAR.ops.copy_accelerator,
3032
- command=self.ctrl_c,
3033
- image=self.PAR.ops.copy_image,
3034
- compound=self.PAR.ops.copy_compound,
3035
- **mnkwgs,
3036
- )
3037
- self.menu_add_command(
3038
- self.CH.ch_rc_popup_menu,
3039
- label=self.PAR.ops.copy_contents_label,
3040
- accelerator=self.PAR.ops.copy_contents_accelerator,
3041
- command=self.ctrl_c,
3042
- image=self.PAR.ops.copy_contents_image,
3043
- compound=self.PAR.ops.copy_contents_compound,
3044
- **mnkwgs,
3045
- )
3046
- self.menu_add_command(
3047
- self.RI.ri_rc_popup_menu,
3048
- label=self.PAR.ops.copy_contents_label,
3049
- accelerator=self.PAR.ops.copy_contents_accelerator,
3050
- command=self.ctrl_c,
3051
- image=self.PAR.ops.copy_contents_image,
3052
- compound=self.PAR.ops.copy_contents_compound,
3053
- **mnkwgs,
3054
- )
3055
- if self.paste_enabled and any(
3056
- x in self.enabled_bindings_menu_entries for x in ("all", "paste", "edit_bindings", "edit")
3057
- ):
3058
- self.menu_add_command(
3059
- self.rc_popup_menu,
3060
- label=self.PAR.ops.paste_label,
3061
- accelerator=self.PAR.ops.paste_accelerator,
3062
- command=self.ctrl_v,
3063
- image=self.PAR.ops.paste_image,
3064
- compound=self.PAR.ops.paste_compound,
3065
- **mnkwgs,
3066
- )
3067
- self.menu_add_command(
3068
- self.CH.ch_rc_popup_menu,
3069
- label=self.PAR.ops.paste_label,
3070
- accelerator=self.PAR.ops.paste_accelerator,
3071
- command=self.ctrl_v,
3072
- image=self.PAR.ops.paste_image,
3073
- compound=self.PAR.ops.paste_compound,
3074
- **mnkwgs,
3075
- )
3076
- self.menu_add_command(
3077
- self.RI.ri_rc_popup_menu,
3078
- label=self.PAR.ops.paste_label,
3079
- accelerator=self.PAR.ops.paste_accelerator,
3080
- command=self.ctrl_v,
3081
- image=self.PAR.ops.paste_image,
3082
- compound=self.PAR.ops.paste_compound,
3083
- **mnkwgs,
3084
- )
3085
- if self.PAR.ops.paste_can_expand_x or self.PAR.ops.paste_can_expand_y:
3086
- self.menu_add_command(
3087
- self.empty_rc_popup_menu,
3088
- label=self.PAR.ops.paste_label,
3089
- accelerator=self.PAR.ops.paste_accelerator,
3090
- command=self.ctrl_v,
3091
- image=self.PAR.ops.paste_image,
3092
- compound=self.PAR.ops.paste_compound,
3093
- **mnkwgs,
3094
- )
3095
- if self.delete_key_enabled and any(
3096
- x in self.enabled_bindings_menu_entries for x in ("all", "paste", "edit_bindings", "edit")
3097
- ):
3098
- self.menu_add_command(
3099
- self.rc_popup_menu,
3100
- label=self.PAR.ops.delete_label,
3101
- accelerator=self.PAR.ops.delete_accelerator,
3102
- command=self.delete_key,
3103
- image=self.PAR.ops.delete_image,
3104
- compound=self.PAR.ops.delete_compound,
3105
- **mnkwgs,
3106
- )
3107
- self.menu_add_command(
3108
- self.CH.ch_rc_popup_menu,
3109
- label=self.PAR.ops.clear_contents_label,
3110
- accelerator=self.PAR.ops.clear_contents_accelerator,
3111
- command=self.delete_key,
3112
- image=self.PAR.ops.clear_contents_image,
3113
- compound=self.PAR.ops.clear_contents_compound,
3114
- **mnkwgs,
3115
- )
3116
- self.menu_add_command(
3117
- self.RI.ri_rc_popup_menu,
3118
- label=self.PAR.ops.clear_contents_label,
3119
- accelerator=self.PAR.ops.clear_contents_accelerator,
3120
- command=self.delete_key,
3121
- image=self.PAR.ops.clear_contents_image,
3122
- compound=self.PAR.ops.clear_contents_compound,
3123
- **mnkwgs,
3124
- )
3125
- if self.rc_delete_column_enabled:
3126
- self.menu_add_command(
3127
- self.CH.ch_rc_popup_menu,
3128
- label=self.PAR.ops.delete_columns_label,
3129
- command=self.delete_columns,
3130
- image=self.PAR.ops.delete_columns_image,
3131
- compound=self.PAR.ops.delete_columns_compound,
3132
- **mnkwgs,
3133
- )
3134
- if self.rc_insert_column_enabled:
3135
- self.menu_add_command(
3136
- self.CH.ch_rc_popup_menu,
3137
- label=self.PAR.ops.insert_columns_left_label,
3138
- command=lambda: self.rc_add_columns("left"),
3139
- image=self.PAR.ops.insert_columns_left_image,
3140
- compound=self.PAR.ops.insert_columns_left_compound,
3141
- **mnkwgs,
3142
- )
3143
- self.menu_add_command(
3144
- self.CH.ch_rc_popup_menu,
3145
- label=self.PAR.ops.insert_columns_right_label,
3146
- command=lambda: self.rc_add_columns("right"),
3147
- image=self.PAR.ops.insert_columns_right_image,
3148
- compound=self.PAR.ops.insert_columns_right_compound,
3149
- **mnkwgs,
3150
- )
3151
- self.menu_add_command(
3152
- self.empty_rc_popup_menu,
3153
- label=self.PAR.ops.insert_column_label,
3154
- command=lambda: self.rc_add_columns("left"),
3155
- image=self.PAR.ops.insert_column_image,
3156
- compound=self.PAR.ops.insert_column_compound,
3157
- **mnkwgs,
3158
- )
3159
- if self.rc_delete_row_enabled:
3160
- self.menu_add_command(
3161
- self.RI.ri_rc_popup_menu,
3162
- label=self.PAR.ops.delete_rows_label,
3163
- command=self.delete_rows,
3164
- image=self.PAR.ops.delete_rows_image,
3165
- compound=self.PAR.ops.delete_rows_compound,
3166
- **mnkwgs,
3167
- )
3168
- if self.rc_insert_row_enabled:
3169
- self.menu_add_command(
3170
- self.RI.ri_rc_popup_menu,
3171
- label=self.PAR.ops.insert_rows_above_label,
3172
- command=lambda: self.rc_add_rows("above"),
3173
- image=self.PAR.ops.insert_rows_above_image,
3174
- compound=self.PAR.ops.insert_rows_above_compound,
3175
- **mnkwgs,
3176
- )
3177
- self.menu_add_command(
3178
- self.RI.ri_rc_popup_menu,
3179
- label=self.PAR.ops.insert_rows_below_label,
3180
- command=lambda: self.rc_add_rows("below"),
3181
- image=self.PAR.ops.insert_rows_below_image,
3182
- compound=self.PAR.ops.insert_rows_below_compound,
3183
- **mnkwgs,
3184
- )
3185
- self.menu_add_command(
3186
- self.empty_rc_popup_menu,
3187
- label=self.PAR.ops.insert_row_label,
3188
- command=lambda: self.rc_add_rows("below"),
3189
- image=self.PAR.ops.insert_row_image,
3190
- compound=self.PAR.ops.insert_row_compound,
3191
- **mnkwgs,
3192
- )
3193
- if self.rc_sort_cells_enabled:
3194
- self.menu_add_command(
3195
- self.rc_popup_menu,
3196
- label=self.PAR.ops.sort_cells_label,
3197
- accelerator=self.PAR.ops.sort_cells_accelerator,
3198
- command=self.sort_boxes,
3199
- image=self.PAR.ops.sort_cells_image,
3200
- compound=self.PAR.ops.sort_cells_compound,
3201
- **mnkwgs,
3202
- )
3203
- self.menu_add_command(
3204
- self.rc_popup_menu,
3205
- label=self.PAR.ops.sort_cells_reverse_label,
3206
- accelerator=self.PAR.ops.sort_cells_reverse_accelerator,
3207
- command=lambda: self.sort_boxes(reverse=True),
3208
- image=self.PAR.ops.sort_cells_reverse_image,
3209
- compound=self.PAR.ops.sort_cells_reverse_compound,
3210
- **mnkwgs,
3211
- )
3212
- self.menu_add_command(
3213
- self.rc_popup_menu,
3214
- label=self.PAR.ops.sort_cells_x_label,
3215
- accelerator=self.PAR.ops.sort_cells_x_accelerator,
3216
- command=lambda: self.sort_boxes(row_wise=True),
3217
- image=self.PAR.ops.sort_cells_x_image,
3218
- compound=self.PAR.ops.sort_cells_x_compound,
3219
- **mnkwgs,
3220
- )
3221
- self.menu_add_command(
3222
- self.rc_popup_menu,
3223
- label=self.PAR.ops.sort_cells_x_reverse_label,
3224
- accelerator=self.PAR.ops.sort_cells_x_reverse_accelerator,
3225
- command=lambda: self.sort_boxes(reverse=True, row_wise=True),
3226
- image=self.PAR.ops.sort_cells_x_reverse_image,
3227
- compound=self.PAR.ops.sort_cells_x_reverse_compound,
3228
- **mnkwgs,
3229
- )
3230
- # row index sort rows cells
3231
- if self.rc_sort_row_enabled:
3232
- self.menu_add_command(
3233
- self.RI.ri_rc_popup_menu,
3234
- label=self.PAR.ops.sort_row_label,
3235
- accelerator=self.PAR.ops.sort_row_accelerator,
3236
- command=self.RI._sort_rows,
3237
- image=self.PAR.ops.sort_row_image,
3238
- compound=self.PAR.ops.sort_row_compound,
3239
- **mnkwgs,
3240
- )
3241
- self.menu_add_command(
3242
- self.RI.ri_rc_popup_menu,
3243
- label=self.PAR.ops.sort_row_reverse_label,
3244
- accelerator=self.PAR.ops.sort_row_reverse_accelerator,
3245
- command=lambda: self.RI._sort_rows(reverse=True),
3246
- image=self.PAR.ops.sort_row_reverse_image,
3247
- compound=self.PAR.ops.sort_row_reverse_compound,
3248
- **mnkwgs,
3249
- )
3250
- # header sort columns cells
3251
- if self.rc_sort_column_enabled:
3252
- self.menu_add_command(
3253
- self.CH.ch_rc_popup_menu,
3254
- label=self.PAR.ops.sort_column_label,
3255
- accelerator=self.PAR.ops.sort_column_accelerator,
3256
- command=self.CH._sort_columns,
3257
- image=self.PAR.ops.sort_column_image,
3258
- compound=self.PAR.ops.sort_column_compound,
3259
- **mnkwgs,
3260
- )
3261
- self.menu_add_command(
3262
- self.CH.ch_rc_popup_menu,
3263
- label=self.PAR.ops.sort_column_reverse_label,
3264
- accelerator=self.PAR.ops.sort_column_reverse_accelerator,
3265
- command=lambda: self.CH._sort_columns(reverse=True),
3266
- image=self.PAR.ops.sort_column_reverse_image,
3267
- compound=self.PAR.ops.sort_column_reverse_compound,
3268
- **mnkwgs,
3269
- )
3270
- # row index sort columns by row
3271
- if self.rc_sort_columns_enabled:
3272
- self.menu_add_command(
3273
- self.RI.ri_rc_popup_menu,
3274
- label=self.PAR.ops.sort_columns_label,
3275
- accelerator=self.PAR.ops.sort_columns_accelerator,
3276
- command=self.RI._sort_columns_by_row,
3277
- image=self.PAR.ops.sort_columns_image,
3278
- compound=self.PAR.ops.sort_columns_compound,
3279
- **mnkwgs,
3280
- )
3281
- self.menu_add_command(
3282
- self.RI.ri_rc_popup_menu,
3283
- label=self.PAR.ops.sort_columns_reverse_label,
3284
- accelerator=self.PAR.ops.sort_columns_reverse_accelerator,
3285
- command=lambda: self.RI._sort_columns_by_row(reverse=True),
3286
- image=self.PAR.ops.sort_columns_reverse_image,
3287
- compound=self.PAR.ops.sort_columns_reverse_compound,
3288
- **mnkwgs,
3289
- )
3290
- # header sort rows by column
3291
- if self.rc_sort_rows_enabled:
3292
- self.menu_add_command(
3293
- self.CH.ch_rc_popup_menu,
3294
- label=self.PAR.ops.sort_rows_label,
3295
- accelerator=self.PAR.ops.sort_rows_accelerator,
3296
- command=self.CH._sort_rows_by_column,
3297
- image=self.PAR.ops.sort_rows_image,
3298
- compound=self.PAR.ops.sort_rows_compound,
3299
- **mnkwgs,
3300
- )
3301
- self.menu_add_command(
3302
- self.CH.ch_rc_popup_menu,
3303
- label=self.PAR.ops.sort_rows_reverse_label,
3304
- accelerator=self.PAR.ops.sort_rows_reverse_accelerator,
3305
- command=lambda: self.CH._sort_rows_by_column(reverse=True),
3306
- image=self.PAR.ops.sort_rows_reverse_image,
3307
- compound=self.PAR.ops.sort_rows_reverse_compound,
3308
- **mnkwgs,
3309
- )
3310
- if self.undo_enabled and any(
3311
- x in self.enabled_bindings_menu_entries for x in ("all", "undo", "redo", "edit_bindings", "edit")
3312
- ):
3313
- for menu in (
3314
- self.rc_popup_menu,
3315
- self.RI.ri_rc_popup_menu,
3316
- self.CH.ch_rc_popup_menu,
3317
- self.empty_rc_popup_menu,
3318
- ):
3319
- self.menu_add_command(
3320
- menu,
3321
- label=self.PAR.ops.undo_label,
3322
- accelerator=self.PAR.ops.undo_accelerator,
3323
- command=self.undo,
3324
- image=self.PAR.ops.undo_image,
3325
- compound=self.PAR.ops.undo_compound,
3326
- **mnkwgs,
3327
- )
3328
- self.menu_add_command(
3329
- menu,
3330
- label=self.PAR.ops.redo_label,
3331
- accelerator=self.PAR.ops.redo_accelerator,
3332
- command=self.redo,
3333
- image=self.PAR.ops.redo_image,
3334
- compound=self.PAR.ops.redo_compound,
3335
- **mnkwgs,
3336
- )
3337
- # Added popup menu commands
3338
- for label, kws in self.extra_table_rc_menu_funcs.items():
3339
- self.menu_add_command(self.rc_popup_menu, label=label, **{**mnkwgs, **kws})
3340
- for label, kws in self.extra_index_rc_menu_funcs.items():
3341
- self.menu_add_command(self.RI.ri_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3342
- for label, kws in self.extra_header_rc_menu_funcs.items():
3343
- self.menu_add_command(self.CH.ch_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3344
- for label, kws in self.extra_empty_space_rc_menu_funcs.items():
3345
- self.menu_add_command(self.empty_rc_popup_menu, label=label, **{**mnkwgs, **kws})
3346
2984
 
3347
2985
  def enable_bindings(self, bindings: Any, menu: bool = True) -> None:
3348
2986
  if not bindings:
@@ -3356,7 +2994,6 @@ class MainTable(tk.Canvas):
3356
2994
  self._enable_binding(binding.lower(), menu)
3357
2995
  elif isinstance(bindings, str):
3358
2996
  self._enable_binding(bindings.lower(), menu)
3359
- self.create_rc_menus()
3360
2997
 
3361
2998
  def disable_bindings(self, bindings: Any) -> None:
3362
2999
  if not bindings:
@@ -3370,7 +3007,6 @@ class MainTable(tk.Canvas):
3370
3007
  self._disable_binding(binding.lower())
3371
3008
  elif isinstance(bindings, str):
3372
3009
  self._disable_binding(bindings)
3373
- self.create_rc_menus()
3374
3010
 
3375
3011
  def _enable_binding(self, binding: Binding, menu: bool = True) -> None:
3376
3012
  if binding == "enable_all":
@@ -3680,58 +3316,6 @@ class MainTable(tk.Canvas):
3680
3316
  or (datacn in self.col_options and "readonly" in self.col_options[datacn])
3681
3317
  )
3682
3318
 
3683
- def popup_menu_disable_edit_if_readonly(self, popup_menu: tk.Menu) -> None:
3684
- # table
3685
- if (
3686
- self.selected
3687
- and self.index_edit_cell_enabled()
3688
- and menu_item_exists(popup_menu, self.PAR.ops.edit_cell_label)
3689
- ):
3690
- datarn, datacn = self.datarn(self.selected.row), self.datacn(self.selected.column)
3691
- if self.is_readonly(datarn, datacn):
3692
- popup_menu.entryconfig(self.PAR.ops.edit_cell_label, image="", state="disabled")
3693
- else:
3694
- popup_menu.entryconfig(self.PAR.ops.edit_cell_label, image=self.PAR.ops.edit_cell_image, state="normal")
3695
- # index
3696
- if (
3697
- self.selected
3698
- and self.index_edit_cell_enabled()
3699
- and menu_item_exists(popup_menu, self.PAR.ops.edit_index_label)
3700
- ):
3701
- datarn = self.datarn(self.selected.row)
3702
- if self.RI.is_readonly(datarn):
3703
- popup_menu.entryconfig(self.PAR.ops.edit_index_label, image="", state="disabled")
3704
- else:
3705
- popup_menu.entryconfig(
3706
- self.PAR.ops.edit_index_label, image=self.PAR.ops.edit_index_image, state="normal"
3707
- )
3708
- # header
3709
- if (
3710
- self.selected
3711
- and self.header_edit_cell_enabled()
3712
- and menu_item_exists(popup_menu, self.PAR.ops.edit_header_label)
3713
- ):
3714
- datacn = self.datacn(self.selected.column)
3715
- if self.CH.is_readonly(datacn):
3716
- popup_menu.entryconfig(self.PAR.ops.edit_header_label, image="", state="disabled")
3717
- else:
3718
- popup_menu.entryconfig(
3719
- self.PAR.ops.edit_header_label, image=self.PAR.ops.edit_header_image, state="normal"
3720
- )
3721
-
3722
- def popup_menu_disable_undo_redo(self, popup_menu: tk.Menu) -> None:
3723
- if not self.undo_enabled:
3724
- return
3725
- if menu_item_exists(popup_menu, self.PAR.ops.undo_label):
3726
- if not self.undo_stack:
3727
- popup_menu.entryconfig(self.PAR.ops.undo_label, image="", state="disabled")
3728
- else:
3729
- popup_menu.entryconfig(self.PAR.ops.undo_label, image=self.PAR.ops.undo_image, state="normal")
3730
- if not self.redo_stack:
3731
- popup_menu.entryconfig(self.PAR.ops.redo_label, image="", state="disabled")
3732
- else:
3733
- popup_menu.entryconfig(self.PAR.ops.redo_label, image=self.PAR.ops.redo_image, state="normal")
3734
-
3735
3319
  def rc(self, event: Any = None) -> None:
3736
3320
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
3737
3321
  self.focus_set()
@@ -3743,12 +3327,15 @@ class MainTable(tk.Canvas):
3743
3327
  if self.col_selected(c):
3744
3328
  if self.rc_popup_menus_enabled:
3745
3329
  popup_menu = self.CH.ch_rc_popup_menu
3330
+ build_header_rc_menu(self, popup_menu, c)
3746
3331
  elif self.row_selected(r):
3747
3332
  if self.rc_popup_menus_enabled:
3748
3333
  popup_menu = self.RI.ri_rc_popup_menu
3334
+ build_index_rc_menu(self, popup_menu, r)
3749
3335
  elif self.cell_selected(r, c):
3750
3336
  if self.rc_popup_menus_enabled:
3751
3337
  popup_menu = self.rc_popup_menu
3338
+ build_table_rc_menu(self, popup_menu, r, c)
3752
3339
  else:
3753
3340
  if self.rc_select_enabled:
3754
3341
  if self.single_selection_enabled:
@@ -3757,14 +3344,14 @@ class MainTable(tk.Canvas):
3757
3344
  self.toggle_select_cell(r, c, redraw=True)
3758
3345
  if self.rc_popup_menus_enabled:
3759
3346
  popup_menu = self.rc_popup_menu
3347
+ build_table_rc_menu(self, popup_menu, r, c)
3760
3348
  else:
3761
3349
  self.deselect("all")
3762
3350
  if self.rc_popup_menus_enabled:
3763
3351
  popup_menu = self.empty_rc_popup_menu
3352
+ build_empty_rc_menu(self, popup_menu)
3764
3353
  try_binding(self.extra_rc_func, event)
3765
3354
  if popup_menu:
3766
- self.popup_menu_disable_edit_if_readonly(popup_menu)
3767
- self.popup_menu_disable_undo_redo(popup_menu)
3768
3355
  popup_menu.tk_popup(event.x_root, event.y_root)
3769
3356
 
3770
3357
  def b1_press(self, event: Any = None) -> None:
@@ -4352,7 +3939,6 @@ class MainTable(tk.Canvas):
4352
3939
  r_pc=r_pc,
4353
3940
  c_pc=c_pc,
4354
3941
  )
4355
- self.create_rc_menus()
4356
3942
 
4357
3943
  def get_txt_w(self, txt: str, font: None | FontTuple = None) -> int:
4358
3944
  self.txt_measure_canvas.itemconfig(
@@ -4752,7 +4338,9 @@ class MainTable(tk.Canvas):
4752
4338
  added_w_space = 1 if slim else 7
4753
4339
  for datacn in itercols:
4754
4340
  w = min_column_width if width is None else width
4755
- w = hw if (hw := self.CH.get_cell_dimensions(datacn)[0]) > w else min_column_width
4341
+ hw = self.CH.get_cell_dimensions(datacn)[0]
4342
+ if hw > w:
4343
+ w = hw
4756
4344
  for datarn in iterrows:
4757
4345
  if txt := self.cell_str(datarn, datacn, get_displayed=True):
4758
4346
  qconf(qtxtm, text=txt, font=qfont)
@@ -5589,11 +5177,11 @@ class MainTable(tk.Canvas):
5589
5177
  if isinstance(self._row_index, list):
5590
5178
  tree = self.PAR.ops.treeview
5591
5179
  for datarn in range(data_ins_row, data_ins_row + rows):
5592
- rows_dict[datarn] = [self.get_value_for_empty_cell(datarn, c, c_ops=False) for c in range(rng)]
5180
+ rows_dict[datarn] = [self.get_value_for_empty_cell(datarn, c, c_ops=True) for c in range(rng)]
5593
5181
  index_dict[datarn] = self.RI.get_value_for_empty_cell(data_ins_row if tree else datarn, r_ops=False)
5594
5182
  else:
5595
5183
  for datarn in range(data_ins_row, data_ins_row + rows):
5596
- rows_dict[datarn] = [self.get_value_for_empty_cell(datarn, c, c_ops=False) for c in range(rng)]
5184
+ rows_dict[datarn] = [self.get_value_for_empty_cell(datarn, c, c_ops=True) for c in range(rng)]
5597
5185
  else:
5598
5186
  if isinstance(self._row_index, list) and row_index:
5599
5187
  for datarn, row in enumerate(rows, data_ins_row):
@@ -5801,21 +5389,23 @@ class MainTable(tk.Canvas):
5801
5389
  else:
5802
5390
  if data_indexes:
5803
5391
  data_rows = rows
5804
- disp_rows = data_to_displayed_idxs(data_rows, self.displayed_rows)
5392
+ # dont create disp_rows twice when using treeview mode
5393
+ disp_rows = [] if self.PAR.ops.treeview else data_to_displayed_idxs(data_rows, self.displayed_rows)
5805
5394
  else:
5806
5395
  data_rows = [self.displayed_rows[r] for r in rows]
5807
5396
  disp_rows = rows
5808
5397
  if self.PAR.ops.treeview:
5809
- data_rows = sorted(
5810
- chain(
5811
- data_rows,
5812
- (
5813
- self.RI.rns[did]
5814
- for r in data_rows
5815
- for did in self.RI.get_iid_descendants(self._row_index[r].iid)
5816
- ),
5817
- )
5818
- )
5398
+ # remove any included descendants &
5399
+ # add all item descendants back in for safety,
5400
+ # update disp rows to del afterwards
5401
+ iids = {self._row_index[r].iid for r in data_rows}
5402
+ all_iids = set()
5403
+ for iid in iids:
5404
+ if not any(ancestor in iids for ancestor in self.RI.get_iid_ancestors(iid)):
5405
+ all_iids.add(iid)
5406
+ all_iids.update(self.RI.get_iid_descendants(iid))
5407
+ data_rows = sorted(map(self.RI.rns.__getitem__, all_iids))
5408
+ disp_rows = data_to_displayed_idxs(data_rows, self.displayed_rows)
5819
5409
  event_data = self.delete_rows_displayed(
5820
5410
  disp_rows,
5821
5411
  event_data,
@@ -6120,9 +5710,9 @@ class MainTable(tk.Canvas):
6120
5710
  kwargs = alternate_color
6121
5711
 
6122
5712
  if kwargs:
6123
- fill = kwargs[0]
6124
- if fill and not fill.startswith("#"):
6125
- fill = color_map[fill]
5713
+ high_bg = kwargs[0]
5714
+ if high_bg and not high_bg.startswith("#"):
5715
+ high_bg = color_map[high_bg]
6126
5716
 
6127
5717
  # cell is a single currently selected cell box
6128
5718
  # not highlighted
@@ -6137,12 +5727,24 @@ class MainTable(tk.Canvas):
6137
5727
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
6138
5728
  else kwargs[1]
6139
5729
  )
6140
- if fill:
6141
- fill = (
6142
- f"#{int((int(fill[1:3], 16) + sel_cells_bg[0]) / 2):02X}"
6143
- + f"{int((int(fill[3:5], 16) + sel_cells_bg[1]) / 2):02X}"
6144
- + f"{int((int(fill[5:], 16) + sel_cells_bg[2]) / 2):02X}"
6145
- )
5730
+ redrawn = self.redraw_highlight(
5731
+ x1=fc + 1,
5732
+ y1=fr + 1,
5733
+ x2=sc,
5734
+ y2=sr,
5735
+ fill=(
5736
+ self.PAR.ops.table_selected_cells_bg
5737
+ if high_bg is None
5738
+ else (
5739
+ f"#{int((int(high_bg[1:3], 16) + sel_cells_bg[0]) / 2):02X}"
5740
+ + f"{int((int(high_bg[3:5], 16) + sel_cells_bg[1]) / 2):02X}"
5741
+ + f"{int((int(high_bg[5:], 16) + sel_cells_bg[2]) / 2):02X}"
5742
+ )
5743
+ ),
5744
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5745
+ can_width=None,
5746
+ pc=None,
5747
+ )
6146
5748
 
6147
5749
  # cell is highlighted and row selected
6148
5750
  elif "rows" in selections and r in selections["rows"]:
@@ -6151,12 +5753,24 @@ class MainTable(tk.Canvas):
6151
5753
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
6152
5754
  else kwargs[1]
6153
5755
  )
6154
- if fill:
6155
- fill = (
6156
- f"#{int((int(fill[1:3], 16) + sel_rows_bg[0]) / 2):02X}"
6157
- + f"{int((int(fill[3:5], 16) + sel_rows_bg[1]) / 2):02X}"
6158
- + f"{int((int(fill[5:], 16) + sel_rows_bg[2]) / 2):02X}"
6159
- )
5756
+ redrawn = self.redraw_highlight(
5757
+ x1=fc + 1,
5758
+ y1=fr + 1,
5759
+ x2=sc,
5760
+ y2=sr,
5761
+ fill=(
5762
+ self.PAR.ops.table_selected_rows_bg
5763
+ if high_bg is None
5764
+ else (
5765
+ f"#{int((int(high_bg[1:3], 16) + sel_rows_bg[0]) / 2):02X}"
5766
+ + f"{int((int(high_bg[3:5], 16) + sel_rows_bg[1]) / 2):02X}"
5767
+ + f"{int((int(high_bg[5:], 16) + sel_rows_bg[2]) / 2):02X}"
5768
+ )
5769
+ ),
5770
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5771
+ can_width=None,
5772
+ pc=None,
5773
+ )
6160
5774
 
6161
5775
  # cell is highlighted and column selected
6162
5776
  elif "columns" in selections and c in selections["columns"]:
@@ -6165,43 +5779,55 @@ class MainTable(tk.Canvas):
6165
5779
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
6166
5780
  else kwargs[1]
6167
5781
  )
6168
- if fill:
6169
- fill = (
6170
- f"#{int((int(fill[1:3], 16) + sel_cols_bg[0]) / 2):02X}"
6171
- + f"{int((int(fill[3:5], 16) + sel_cols_bg[1]) / 2):02X}"
6172
- + f"{int((int(fill[5:], 16) + sel_cols_bg[2]) / 2):02X}"
6173
- )
5782
+ redrawn = self.redraw_highlight(
5783
+ x1=fc + 1,
5784
+ y1=fr + 1,
5785
+ x2=sc,
5786
+ y2=sr,
5787
+ fill=(
5788
+ self.PAR.ops.table_selected_columns_bg
5789
+ if high_bg is None
5790
+ else (
5791
+ f"#{int((int(high_bg[1:3], 16) + sel_cols_bg[0]) / 2):02X}"
5792
+ + f"{int((int(high_bg[3:5], 16) + sel_cols_bg[1]) / 2):02X}"
5793
+ + f"{int((int(high_bg[5:], 16) + sel_cols_bg[2]) / 2):02X}"
5794
+ )
5795
+ ),
5796
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5797
+ can_width=None,
5798
+ pc=None,
5799
+ )
6174
5800
 
6175
- # cell is just highlighted
5801
+ # cell is just highlighted (no selection)
6176
5802
  else:
6177
5803
  txtfg = self.PAR.ops.table_fg if kwargs[1] is None else kwargs[1]
6178
-
6179
- if fill:
6180
- if not isinstance(kwargs, ProgressBar):
6181
- redrawn = self.redraw_highlight(
6182
- x1=fc + 1,
6183
- y1=fr + 1,
6184
- x2=sc,
6185
- y2=sr,
6186
- fill=fill,
6187
- outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
6188
- can_width=can_width if (len(kwargs) > 2 and kwargs[2]) else None,
6189
- pc=None,
6190
- )
6191
- else:
6192
- if kwargs.del_when_done and kwargs.percent >= 100:
6193
- del self.progress_bars[(datarn, datacn)]
6194
- else:
5804
+ if high_bg: # Only draw if fill exists
5805
+ if not isinstance(kwargs, ProgressBar):
6195
5806
  redrawn = self.redraw_highlight(
6196
5807
  x1=fc + 1,
6197
5808
  y1=fr + 1,
6198
5809
  x2=sc,
6199
5810
  y2=sr,
6200
- fill=fill,
5811
+ fill=high_bg,
6201
5812
  outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
6202
- can_width=None,
6203
- pc=kwargs.percent,
5813
+ can_width=can_width if (len(kwargs) > 2 and kwargs[2]) else None,
5814
+ pc=None,
6204
5815
  )
5816
+ else:
5817
+ if kwargs.del_when_done and kwargs.percent >= 100:
5818
+ del self.progress_bars[(datarn, datacn)]
5819
+ else:
5820
+ redrawn = self.redraw_highlight(
5821
+ x1=fc + 1,
5822
+ y1=fr + 1,
5823
+ x2=sc,
5824
+ y2=sr,
5825
+ fill=high_bg,
5826
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5827
+ can_width=None,
5828
+ pc=kwargs.percent,
5829
+ )
5830
+
6205
5831
  elif not kwargs:
6206
5832
  if "cells" in selections and (r, c) in selections["cells"]:
6207
5833
  txtfg = self.PAR.ops.table_selected_cells_fg
@@ -6454,6 +6080,17 @@ class MainTable(tk.Canvas):
6454
6080
  self.char_widths[self.table_font][c] = wd
6455
6081
  return wd
6456
6082
 
6083
+ def redraw_corner(self, x: float, y: float) -> None:
6084
+ if self.hidd_corners:
6085
+ iid = self.hidd_corners.pop()
6086
+ self.coords(iid, x - 10, y, x, y, x, y + 10)
6087
+ self.itemconfig(iid, fill=self.PAR.ops.table_grid_fg, state="normal")
6088
+ self.disp_corners.add(iid)
6089
+ else:
6090
+ self.disp_corners.add(
6091
+ self.create_polygon(x - 10, y, x, y, x, y + 10, fill=self.PAR.ops.table_grid_fg, tags="lift")
6092
+ )
6093
+
6457
6094
  def redraw_grid_and_text(
6458
6095
  self,
6459
6096
  last_row_line_pos: float,
@@ -6488,6 +6125,8 @@ class MainTable(tk.Canvas):
6488
6125
  self.disp_dropdown = {}
6489
6126
  self.hidd_checkbox.update(self.disp_checkbox)
6490
6127
  self.disp_checkbox = {}
6128
+ self.hidd_corners.update(self.disp_corners)
6129
+ self.disp_corners = set()
6491
6130
  points = []
6492
6131
  # manage horizontal grid lines
6493
6132
  if self.PAR.ops.show_horizontal_grid and row_pos_exists:
@@ -6560,10 +6199,10 @@ class MainTable(tk.Canvas):
6560
6199
  text_start_col=text_start_col,
6561
6200
  text_end_col=text_end_col,
6562
6201
  )
6202
+ note_corners = self.PAR.ops.note_corners
6563
6203
 
6564
6204
  # This is a little messy but
6565
6205
  # we try to avoid any function use to maximise performance
6566
-
6567
6206
  for r in range(text_start_row, text_end_row):
6568
6207
  rtopgridln = self.row_positions[r]
6569
6208
  rbotgridln = self.row_positions[r + 1]
@@ -6720,10 +6359,21 @@ class MainTable(tk.Canvas):
6720
6359
  elif align[-1] == "n":
6721
6360
  draw_x = cleftgridln + (crightgridln - cleftgridln) / 2
6722
6361
 
6362
+ if (
6363
+ note_corners
6364
+ and max_width > 5
6365
+ and (
6366
+ (loc in self.cell_options and "note" in self.cell_options[(datarn, datacn)])
6367
+ or (datarn in self.row_options and "note" in self.row_options[datarn])
6368
+ or (datacn in self.col_options and "note" in self.col_options[datacn])
6369
+ )
6370
+ ):
6371
+ self.redraw_corner(crightgridln, rtopgridln)
6372
+
6723
6373
  # redraw text
6724
6374
 
6725
6375
  text = cells[loc]
6726
- if not text or (align[-1] == "w" and draw_x > scrollpos_right) or cleftgridln + 5 > scrollpos_right:
6376
+ if (align[-1] == "w" and draw_x > scrollpos_right) or cleftgridln + 5 > scrollpos_right:
6727
6377
  continue
6728
6378
  if allow_overflow and not kws:
6729
6379
  if align[-1] == "w":
@@ -6748,14 +6398,33 @@ class MainTable(tk.Canvas):
6748
6398
  iid, showing = self.hidd_text.popitem()
6749
6399
  self.coords(iid, draw_x, draw_y)
6750
6400
  if showing:
6751
- self.itemconfig(iid, text="\n".join(gen_lines), fill=fill, font=font, anchor=align)
6401
+ self.itemconfig(
6402
+ iid,
6403
+ text="\n".join(gen_lines),
6404
+ fill=fill,
6405
+ font=font,
6406
+ anchor=align,
6407
+ tags=("lift", "t", f"{r}_{c}"),
6408
+ )
6752
6409
  else:
6753
6410
  self.itemconfig(
6754
- iid, text="\n".join(gen_lines), fill=fill, font=font, anchor=align, state="normal"
6411
+ iid,
6412
+ text="\n".join(gen_lines),
6413
+ fill=fill,
6414
+ font=font,
6415
+ anchor=align,
6416
+ state="normal",
6417
+ tags=("lift", "t", f"{r}_{c}"),
6755
6418
  )
6756
6419
  else:
6757
6420
  iid = self.create_text(
6758
- draw_x, draw_y, text="\n".join(gen_lines), fill=fill, font=font, anchor=align, tag="lift"
6421
+ draw_x,
6422
+ draw_y,
6423
+ text="\n".join(gen_lines),
6424
+ fill=fill,
6425
+ font=font,
6426
+ anchor=align,
6427
+ tags=("lift", "t", f"{r}_{c}"),
6759
6428
  )
6760
6429
  self.disp_text[iid] = True
6761
6430
 
@@ -6765,12 +6434,33 @@ class MainTable(tk.Canvas):
6765
6434
  iid, showing = self.hidd_text.popitem()
6766
6435
  self.coords(iid, draw_x, draw_y)
6767
6436
  if showing:
6768
- self.itemconfig(iid, text=t, fill=fill, font=font, anchor=align)
6437
+ self.itemconfig(
6438
+ iid,
6439
+ text=t,
6440
+ fill=fill,
6441
+ font=font,
6442
+ anchor=align,
6443
+ tags=("lift", "t", f"{r}_{c}"),
6444
+ )
6769
6445
  else:
6770
- self.itemconfig(iid, text=t, fill=fill, font=font, anchor=align, state="normal")
6446
+ self.itemconfig(
6447
+ iid,
6448
+ text=t,
6449
+ fill=fill,
6450
+ font=font,
6451
+ anchor=align,
6452
+ state="normal",
6453
+ tags=("lift", "t", f"{r}_{c}"),
6454
+ )
6771
6455
  else:
6772
6456
  iid = self.create_text(
6773
- draw_x, draw_y, text=t, fill=fill, font=font, anchor=align, tag="lift"
6457
+ draw_x,
6458
+ draw_y,
6459
+ text=t,
6460
+ fill=fill,
6461
+ font=font,
6462
+ anchor=align,
6463
+ tags=("lift", "t", f"{r}_{c}"),
6774
6464
  )
6775
6465
  self.disp_text[iid] = True
6776
6466
  draw_y += self.table_txt_height
@@ -6785,6 +6475,8 @@ class MainTable(tk.Canvas):
6785
6475
  if showing:
6786
6476
  self.itemconfig(iid, state="hidden")
6787
6477
  dct[iid] = False
6478
+ for iid in self.hidd_corners:
6479
+ self.itemconfig(iid, state="hidden")
6788
6480
  if self.PAR.ops.show_selected_cells_border:
6789
6481
  for _, box in self.selection_boxes.items():
6790
6482
  if box.bd_iid:
@@ -6792,6 +6484,115 @@ class MainTable(tk.Canvas):
6792
6484
  if self.selected:
6793
6485
  self.tag_raise(self.selected.iid)
6794
6486
  self.lift("lift")
6487
+ self.tag_bind("t", "<Enter>", self.enter_text)
6488
+ self.tag_bind("t", "<Leave>", self.leave_text)
6489
+
6490
+ def enter_text(self, event: tk.Event | None = None) -> None:
6491
+ can_x, can_y = self.canvasx(event.x), self.canvasy(event.y)
6492
+ for i in self.find_overlapping(can_x - 1, can_y - 1, can_x + 1, can_y + 1):
6493
+ try:
6494
+ if (coords := self.gettags(i)[2]) == self.tooltip_coords:
6495
+ return
6496
+ self.tooltip_coords = coords
6497
+ self.tooltip_last_x, self.tooltip_last_y = self.winfo_pointerx(), self.winfo_pointery()
6498
+ self.start_tooltip_timer()
6499
+ return
6500
+ except Exception:
6501
+ continue
6502
+
6503
+ def leave_text(self, event: tk.Event | None = None) -> None:
6504
+ if self.tooltip_after_id is not None:
6505
+ self.after_cancel(self.tooltip_after_id)
6506
+ self.tooltip_after_id = None
6507
+ if self.tooltip_showing:
6508
+ if self.winfo_containing(self.winfo_pointerx(), self.winfo_pointery()) not in self.tooltip_widgets:
6509
+ self.close_tooltip_save()
6510
+ else:
6511
+ self.tooltip_coords = None
6512
+
6513
+ def start_tooltip_timer(self) -> None:
6514
+ self.tooltip_after_id = self.after(1000, self.check_and_show_tooltip)
6515
+
6516
+ def check_and_show_tooltip(self, event: tk.Event | None = None) -> None:
6517
+ current_x, current_y = self.winfo_pointerx(), self.winfo_pointery()
6518
+ if current_x < 0 or current_y < 0:
6519
+ return
6520
+ if abs(current_x - self.tooltip_last_x) <= 1 and abs(current_y - self.tooltip_last_y) <= 1:
6521
+ self.show_tooltip()
6522
+ else:
6523
+ self.tooltip_last_x, self.tooltip_last_y = current_x, current_y
6524
+ self.tooltip_after_id = self.after(400, self.check_and_show_tooltip)
6525
+
6526
+ def hide_tooltip(self) -> None:
6527
+ self.tooltip.withdraw()
6528
+ self.tooltip_showing, self.tooltip_coords = False, None
6529
+
6530
+ def show_tooltip(self) -> None:
6531
+ if self.text_editor.open or self.dropdown.open:
6532
+ return
6533
+ coords = self.tooltip_coords.split("_")
6534
+ r, c = int(coords[0]), int(coords[1])
6535
+ datarn, datacn = self.datarn(r), self.datacn(c)
6536
+ kws = self.get_cell_kwargs(datarn, datacn, key="note")
6537
+ if not self.PAR.ops.tooltips and not kws and not self.PAR.ops.user_can_create_notes:
6538
+ return
6539
+ cell_readonly = self.get_cell_kwargs(datarn, datacn, "readonly") or not self.table_edit_cell_enabled()
6540
+ if kws:
6541
+ note = kws["note"]
6542
+ note_readonly = kws["readonly"]
6543
+ elif self.PAR.ops.user_can_create_notes:
6544
+ note = ""
6545
+ note_readonly = bool(cell_readonly)
6546
+ else:
6547
+ note = None
6548
+ note_readonly = True
6549
+ note_only = not self.PAR.ops.tooltips and isinstance(note, str)
6550
+ self.tooltip.reset(
6551
+ **{
6552
+ "text": f"{self.get_cell_data(datarn, datacn, none_to_empty_str=True)}",
6553
+ "cell_readonly": cell_readonly,
6554
+ "note": note,
6555
+ "note_readonly": note_readonly,
6556
+ "row": r,
6557
+ "col": c,
6558
+ "menu_kwargs": get_menu_kwargs(self.PAR.ops),
6559
+ **get_bg_fg(self.PAR.ops),
6560
+ "user_can_create_notes": self.PAR.ops.user_can_create_notes,
6561
+ "note_only": note_only,
6562
+ "width": self.PAR.ops.tooltip_width,
6563
+ "height": self.PAR.ops.tooltip_height,
6564
+ }
6565
+ )
6566
+ self.tooltip.set_position(self.tooltip_last_x - 4, self.tooltip_last_y - 4)
6567
+ self.tooltip_showing = True
6568
+
6569
+ def close_tooltip_save(self, event: tk.Event | None = None) -> None:
6570
+ widget = self.winfo_containing(self.winfo_pointerx(), self.winfo_pointery())
6571
+ if any(widget == tw for tw in self.tooltip_widgets):
6572
+ try:
6573
+ if self.tooltip.notebook.index("current") == 0:
6574
+ self.tooltip.content_text.focus_set()
6575
+ else:
6576
+ self.tooltip.note_text.focus_set()
6577
+ except Exception:
6578
+ self.tooltip.content_text.focus_set()
6579
+ return
6580
+ if not self.tooltip.cell_readonly:
6581
+ r, c, cell, note = self.tooltip.get()
6582
+ datarn, datacn = self.datarn(r), self.datacn(c)
6583
+ event_data = self.new_single_edit_event(
6584
+ r, c, datarn, datacn, "??", self.get_cell_data(datarn, datacn), cell
6585
+ )
6586
+ value, event_data = self.single_edit_run_validation(datarn, datacn, event_data)
6587
+ if value is not None and (
6588
+ self.set_cell_data_undo(r=r, c=c, datarn=datarn, datacn=datacn, value=value, redraw=False)
6589
+ ):
6590
+ try_binding(self.extra_end_edit_cell_func, event_data)
6591
+ if not self.tooltip.note_readonly:
6592
+ self.PAR.note(datarn, datacn, note=note if note else None, readonly=False)
6593
+ self.hide_tooltip()
6594
+ self.refresh()
6595
+ self.focus_set()
6795
6596
 
6796
6597
  def main_table_redraw_grid_and_text(
6797
6598
  self,
@@ -7019,15 +6820,14 @@ class MainTable(tk.Canvas):
7019
6820
  x2 = self.col_positions[c + 1] if index_exists(self.col_positions, c + 1) else self.col_positions[c] + 1
7020
6821
  y2 = self.row_positions[r + 1] if index_exists(self.row_positions, r + 1) else self.row_positions[r] + 1
7021
6822
  self.hide_selected()
7022
- iid = self.display_box(
6823
+ iid = self.display_border(
7023
6824
  x1,
7024
6825
  y1,
7025
6826
  x2,
7026
6827
  y2,
7027
- fill="",
7028
- outline=outline if self.PAR.ops.show_selected_cells_border else "",
6828
+ fill=outline if self.PAR.ops.show_selected_cells_border else "",
7029
6829
  state="normal",
7030
- tags="selected",
6830
+ tags=("selected", "lift"),
7031
6831
  width=2,
7032
6832
  )
7033
6833
  self.selected = Selected(
@@ -7040,14 +6840,13 @@ class MainTable(tk.Canvas):
7040
6840
  )
7041
6841
  return iid
7042
6842
 
7043
- def display_box(
6843
+ def display_border(
7044
6844
  self,
7045
6845
  x1: int,
7046
6846
  y1: int,
7047
6847
  x2: int,
7048
6848
  y2: int,
7049
6849
  fill: str,
7050
- outline: str,
7051
6850
  state: str,
7052
6851
  tags: str | tuple[str],
7053
6852
  width: int,
@@ -7062,30 +6861,29 @@ class MainTable(tk.Canvas):
7062
6861
  radius=radius,
7063
6862
  )
7064
6863
  if isinstance(iid, int):
7065
- self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags, width=width)
7066
- self.coords(iid, coords)
6864
+ self.itemconfig(iid, fill=fill, state=state, tags=tags, width=width)
6865
+ self.coords(iid, *coords)
7067
6866
  else:
7068
- if self.hidd_boxes:
7069
- iid = self.hidd_boxes.pop()
7070
- self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags, width=width)
7071
- self.coords(iid, coords)
6867
+ if self.hidd_borders:
6868
+ iid = self.hidd_borders.pop()
6869
+ self.itemconfig(iid, fill=fill, state=state, tags=tags, width=width)
6870
+ self.coords(iid, *coords)
7072
6871
  else:
7073
- iid = self.create_polygon(
7074
- coords,
6872
+ iid = self.create_line(
6873
+ *coords,
7075
6874
  fill=fill,
7076
- outline=outline,
7077
6875
  state=state,
7078
6876
  tags=tags,
7079
6877
  width=width,
7080
6878
  smooth=True,
7081
6879
  )
7082
- self.disp_boxes.add(iid)
6880
+ self.disp_borders.add(iid)
7083
6881
  return iid
7084
6882
 
7085
- def hide_box(self, item: int | None) -> None:
6883
+ def hide_border(self, item: int | None) -> None:
7086
6884
  if isinstance(item, int):
7087
- self.disp_boxes.discard(item)
7088
- self.hidd_boxes.add(item)
6885
+ self.disp_borders.discard(item)
6886
+ self.hidd_borders.add(item)
7089
6887
  self.itemconfig(item, state="hidden")
7090
6888
 
7091
6889
  def hide_box_fill(self, item: int | None) -> None:
@@ -7098,7 +6896,7 @@ class MainTable(tk.Canvas):
7098
6896
  return False
7099
6897
  box = self.selection_boxes.pop(item)
7100
6898
  self.hide_box_fill(box.fill_iid)
7101
- self.hide_box(box.bd_iid)
6899
+ self.hide_border(box.bd_iid)
7102
6900
  if self.selected.fill_iid == item:
7103
6901
  self.hide_selected()
7104
6902
  self.set_current_to_last()
@@ -7112,7 +6910,7 @@ class MainTable(tk.Canvas):
7112
6910
 
7113
6911
  def hide_selected(self) -> None:
7114
6912
  if self.selected:
7115
- self.hide_box(self.selected.iid)
6913
+ self.hide_border(self.selected.iid)
7116
6914
  self.selected = ()
7117
6915
 
7118
6916
  def get_selection_fill(self) -> int:
@@ -7150,39 +6948,20 @@ class MainTable(tk.Canvas):
7150
6948
  mt_border_col = self.PAR.ops.table_selected_columns_border_fg
7151
6949
  if self.selection_boxes:
7152
6950
  next(reversed(self.selection_boxes.values())).state = "normal"
7153
- x1, y1, x2, y2 = self.box_coords_x_canvas_coords(r1, c1, r2, c2, type_)
6951
+ x1, y1, x2, y2 = self.box_coords_x_canvas_coords(r1, c1, r2, c2)
7154
6952
  fill_iid = self.get_selection_fill()
7155
6953
  bd_iid = None
7156
- # fill might not display if canvas is wider than 32k pixels
7157
- if self.PAR.ops.selected_rows_to_end_of_window and type_ == "rows":
7158
- bd_iid = self.display_box(
7159
- x1,
7160
- y1,
7161
- x2,
7162
- y2,
7163
- fill=self.PAR.ops.table_selected_rows_bg,
7164
- outline=""
7165
- if self.PAR.name == "!SheetDropdown"
7166
- else mt_border_col
7167
- if self.PAR.ops.show_selected_cells_border
7168
- else "",
7169
- state="normal",
7170
- tags=f"{type_}bd",
7171
- width=1,
7172
- )
7173
- self.tag_lower(bd_iid)
7174
- elif self.PAR.ops.show_selected_cells_border and (
6954
+ if self.PAR.ops.show_selected_cells_border and (
7175
6955
  ext
7176
6956
  or self.ctrl_b1_pressed
7177
6957
  or (self.being_drawn_item is None and self.RI.being_drawn_item is None and self.CH.being_drawn_item is None)
7178
6958
  ):
7179
- bd_iid = self.display_box(
6959
+ bd_iid = self.display_border(
7180
6960
  x1,
7181
6961
  y1,
7182
- x2,
6962
+ self.canvasx(self.winfo_width()) if self.PAR.name == "!SheetDropdown" else x2,
7183
6963
  y2,
7184
- fill="",
7185
- outline=mt_border_col,
6964
+ fill=mt_border_col,
7186
6965
  state="normal",
7187
6966
  tags=f"{type_}bd",
7188
6967
  width=1,
@@ -7209,22 +6988,8 @@ class MainTable(tk.Canvas):
7209
6988
  self.run_selection_binding(type_)
7210
6989
  return fill_iid
7211
6990
 
7212
- def box_coords_x_canvas_coords(
7213
- self,
7214
- r1: int,
7215
- c1: int,
7216
- r2: int,
7217
- c2: int,
7218
- type_: Literal["cells", "rows", "columns"],
7219
- ) -> tuple[float, float, float, float]:
7220
- x1 = self.col_positions[c1]
7221
- y1 = self.row_positions[r1]
7222
- y2 = self.row_positions[r2]
7223
- if type_ == "rows" and self.PAR.ops.selected_rows_to_end_of_window:
7224
- x2 = self.canvasx(self.winfo_width())
7225
- else:
7226
- x2 = self.col_positions[c2]
7227
- return x1, y1, x2, y2
6991
+ def box_coords_x_canvas_coords(self, r1: int, c1: int, r2: int, c2: int) -> tuple[float, float, float, float]:
6992
+ return self.col_positions[c1], self.row_positions[r1], self.col_positions[c2], self.row_positions[r2]
7228
6993
 
7229
6994
  def recreate_selection_box(
7230
6995
  self,
@@ -7253,17 +7018,16 @@ class MainTable(tk.Canvas):
7253
7018
  state = "normal"
7254
7019
  if self.selected.fill_iid == fill_iid:
7255
7020
  self.selected = self.selected._replace(box=Box_nt(r1, c1, r2, c2))
7256
- x1, y1, x2, y2 = self.box_coords_x_canvas_coords(r1, c1, r2, c2, type_)
7021
+ x1, y1, x2, y2 = self.box_coords_x_canvas_coords(r1, c1, r2, c2)
7257
7022
  self.selection_boxes[fill_iid].state = state
7258
7023
  if bd_iid := self.selection_boxes[fill_iid].bd_iid:
7259
7024
  if self.PAR.ops.show_selected_cells_border:
7260
- self.display_box(
7025
+ self.display_border(
7261
7026
  x1,
7262
7027
  y1,
7263
7028
  x2,
7264
7029
  y2,
7265
- fill="",
7266
- outline=mt_border_col,
7030
+ fill=mt_border_col,
7267
7031
  state="normal",
7268
7032
  tags=f"{type_}bd",
7269
7033
  width=1,
@@ -7271,7 +7035,7 @@ class MainTable(tk.Canvas):
7271
7035
  )
7272
7036
  self.tag_raise(bd_iid)
7273
7037
  else:
7274
- self.hide_box(bd_iid)
7038
+ self.hide_border(bd_iid)
7275
7039
  if run_binding:
7276
7040
  self.run_selection_binding(type_)
7277
7041
  return fill_iid
@@ -7727,19 +7491,8 @@ class MainTable(tk.Canvas):
7727
7491
  value = self.text_editor.get()
7728
7492
  r, c = self.text_editor.coords
7729
7493
  datarn, datacn = self.datarn(r), self.datacn(c)
7730
- event_data = event_dict(
7731
- name="end_edit_table",
7732
- sheet=self.PAR.name,
7733
- widget=self,
7734
- cells_table={(datarn, datacn): self.get_cell_data(datarn, datacn)},
7735
- key=event.keysym,
7736
- value=value,
7737
- loc=Loc(r, c),
7738
- row=r,
7739
- column=c,
7740
- boxes=self.get_boxes(),
7741
- selected=self.selected,
7742
- data={(datarn, datacn): value},
7494
+ event_data = self.new_single_edit_event(
7495
+ r, c, datarn, datacn, event.keysym, self.get_cell_data(datarn, datacn), value
7743
7496
  )
7744
7497
  value, event_data = self.single_edit_run_validation(datarn, datacn, event_data)
7745
7498
  edited = False
@@ -8034,19 +7787,8 @@ class MainTable(tk.Canvas):
8034
7787
  datacn = self.datacn(c)
8035
7788
  datarn = self.datarn(r)
8036
7789
  kwargs = self.get_cell_kwargs(datarn, datacn, key="dropdown")
8037
- event_data = event_dict(
8038
- name="end_edit_table",
8039
- sheet=self.PAR.name,
8040
- widget=self,
8041
- cells_table={(datarn, datacn): self.get_cell_data(datarn, datacn)},
8042
- key="??",
8043
- value=selection,
8044
- loc=Loc(r, c),
8045
- row=r,
8046
- column=c,
8047
- boxes=self.get_boxes(),
8048
- selected=self.selected,
8049
- data={(datarn, datacn): selection},
7790
+ event_data = self.new_single_edit_event(
7791
+ r, c, datarn, datacn, "??", self.get_cell_data(datarn, datacn), selection
8050
7792
  )
8051
7793
  try_binding(kwargs["select_function"], event_data)
8052
7794
  selection, event_data = self.single_edit_run_validation(datarn, datacn, event_data)
@@ -8118,20 +7860,7 @@ class MainTable(tk.Canvas):
8118
7860
  cell_resize=False,
8119
7861
  check_input_valid=False,
8120
7862
  )
8121
- event_data = event_dict(
8122
- name="end_edit_table",
8123
- sheet=self.PAR.name,
8124
- widget=self,
8125
- cells_table={(datarn, datacn): pre_edit_value},
8126
- key="??",
8127
- value=value,
8128
- loc=Loc(r, c),
8129
- row=r,
8130
- column=c,
8131
- boxes=self.get_boxes(),
8132
- selected=self.selected,
8133
- data={(datarn, datacn): value},
8134
- )
7863
+ event_data = self.new_single_edit_event(r, c, datarn, datacn, "??", pre_edit_value, value)
8135
7864
  if kwargs["check_function"] is not None:
8136
7865
  kwargs["check_function"](event_data)
8137
7866
  try_binding(self.extra_end_edit_cell_func, event_data)
@@ -8227,20 +7956,22 @@ class MainTable(tk.Canvas):
8227
7956
  ):
8228
7957
  return False
8229
7958
  elif (
8230
- (
8231
- kwargs := self.get_cell_kwargs(
8232
- datarn,
8233
- datacn,
8234
- key="dropdown",
8235
- cell=r_ops and c_ops,
8236
- row=r_ops,
8237
- column=c_ops,
8238
- )
7959
+ kwargs := self.get_cell_kwargs(
7960
+ datarn,
7961
+ datacn,
7962
+ key="dropdown",
7963
+ cell=r_ops and c_ops,
7964
+ row=r_ops,
7965
+ column=c_ops,
8239
7966
  )
8240
- and kwargs["validate_input"]
8241
- and kwargs["values"]
8242
- ):
8243
- return kwargs["values"][0]
7967
+ ) and kwargs["validate_input"]:
7968
+ if kwargs["default_value"] is None:
7969
+ if kwargs["values"]:
7970
+ return safe_copy(kwargs["values"][0])
7971
+ else:
7972
+ return self.format_value(datarn, datacn, "")
7973
+ else:
7974
+ return safe_copy(kwargs["default_value"])
8244
7975
  else:
8245
7976
  return self.format_value(datarn, datacn, "")
8246
7977