tksheet 7.5.4__py3-none-any.whl → 7.5.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
tksheet/main_table.py CHANGED
@@ -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):
@@ -6120,9 +5708,9 @@ class MainTable(tk.Canvas):
6120
5708
  kwargs = alternate_color
6121
5709
 
6122
5710
  if kwargs:
6123
- fill = kwargs[0]
6124
- if fill and not fill.startswith("#"):
6125
- fill = color_map[fill]
5711
+ high_bg = kwargs[0]
5712
+ if high_bg and not high_bg.startswith("#"):
5713
+ high_bg = color_map[high_bg]
6126
5714
 
6127
5715
  # cell is a single currently selected cell box
6128
5716
  # not highlighted
@@ -6137,12 +5725,24 @@ class MainTable(tk.Canvas):
6137
5725
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
6138
5726
  else kwargs[1]
6139
5727
  )
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
- )
5728
+ redrawn = self.redraw_highlight(
5729
+ x1=fc + 1,
5730
+ y1=fr + 1,
5731
+ x2=sc,
5732
+ y2=sr,
5733
+ fill=(
5734
+ self.PAR.ops.table_selected_cells_bg
5735
+ if high_bg is None
5736
+ else (
5737
+ f"#{int((int(high_bg[1:3], 16) + sel_cells_bg[0]) / 2):02X}"
5738
+ + f"{int((int(high_bg[3:5], 16) + sel_cells_bg[1]) / 2):02X}"
5739
+ + f"{int((int(high_bg[5:], 16) + sel_cells_bg[2]) / 2):02X}"
5740
+ )
5741
+ ),
5742
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5743
+ can_width=None,
5744
+ pc=None,
5745
+ )
6146
5746
 
6147
5747
  # cell is highlighted and row selected
6148
5748
  elif "rows" in selections and r in selections["rows"]:
@@ -6151,12 +5751,24 @@ class MainTable(tk.Canvas):
6151
5751
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
6152
5752
  else kwargs[1]
6153
5753
  )
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
- )
5754
+ redrawn = self.redraw_highlight(
5755
+ x1=fc + 1,
5756
+ y1=fr + 1,
5757
+ x2=sc,
5758
+ y2=sr,
5759
+ fill=(
5760
+ self.PAR.ops.table_selected_rows_bg
5761
+ if high_bg is None
5762
+ else (
5763
+ f"#{int((int(high_bg[1:3], 16) + sel_rows_bg[0]) / 2):02X}"
5764
+ + f"{int((int(high_bg[3:5], 16) + sel_rows_bg[1]) / 2):02X}"
5765
+ + f"{int((int(high_bg[5:], 16) + sel_rows_bg[2]) / 2):02X}"
5766
+ )
5767
+ ),
5768
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5769
+ can_width=None,
5770
+ pc=None,
5771
+ )
6160
5772
 
6161
5773
  # cell is highlighted and column selected
6162
5774
  elif "columns" in selections and c in selections["columns"]:
@@ -6165,43 +5777,55 @@ class MainTable(tk.Canvas):
6165
5777
  if kwargs[1] is None or self.PAR.ops.display_selected_fg_over_highlights
6166
5778
  else kwargs[1]
6167
5779
  )
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
- )
5780
+ redrawn = self.redraw_highlight(
5781
+ x1=fc + 1,
5782
+ y1=fr + 1,
5783
+ x2=sc,
5784
+ y2=sr,
5785
+ fill=(
5786
+ self.PAR.ops.table_selected_columns_bg
5787
+ if high_bg is None
5788
+ else (
5789
+ f"#{int((int(high_bg[1:3], 16) + sel_cols_bg[0]) / 2):02X}"
5790
+ + f"{int((int(high_bg[3:5], 16) + sel_cols_bg[1]) / 2):02X}"
5791
+ + f"{int((int(high_bg[5:], 16) + sel_cols_bg[2]) / 2):02X}"
5792
+ )
5793
+ ),
5794
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5795
+ can_width=None,
5796
+ pc=None,
5797
+ )
6174
5798
 
6175
- # cell is just highlighted
5799
+ # cell is just highlighted (no selection)
6176
5800
  else:
6177
5801
  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:
5802
+ if high_bg: # Only draw if fill exists
5803
+ if not isinstance(kwargs, ProgressBar):
6195
5804
  redrawn = self.redraw_highlight(
6196
5805
  x1=fc + 1,
6197
5806
  y1=fr + 1,
6198
5807
  x2=sc,
6199
5808
  y2=sr,
6200
- fill=fill,
5809
+ fill=high_bg,
6201
5810
  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,
5811
+ can_width=can_width if (len(kwargs) > 2 and kwargs[2]) else None,
5812
+ pc=None,
6204
5813
  )
5814
+ else:
5815
+ if kwargs.del_when_done and kwargs.percent >= 100:
5816
+ del self.progress_bars[(datarn, datacn)]
5817
+ else:
5818
+ redrawn = self.redraw_highlight(
5819
+ x1=fc + 1,
5820
+ y1=fr + 1,
5821
+ x2=sc,
5822
+ y2=sr,
5823
+ fill=high_bg,
5824
+ outline=self.PAR.ops.table_fg if has_dd and self.PAR.ops.show_dropdown_borders else "",
5825
+ can_width=None,
5826
+ pc=kwargs.percent,
5827
+ )
5828
+
6205
5829
  elif not kwargs:
6206
5830
  if "cells" in selections and (r, c) in selections["cells"]:
6207
5831
  txtfg = self.PAR.ops.table_selected_cells_fg
@@ -6454,6 +6078,17 @@ class MainTable(tk.Canvas):
6454
6078
  self.char_widths[self.table_font][c] = wd
6455
6079
  return wd
6456
6080
 
6081
+ def redraw_corner(self, x: float, y: float) -> None:
6082
+ if self.hidd_corners:
6083
+ iid = self.hidd_corners.pop()
6084
+ self.coords(iid, x - 10, y, x, y, x, y + 10)
6085
+ self.itemconfig(iid, fill=self.PAR.ops.table_grid_fg, state="normal")
6086
+ self.disp_corners.add(iid)
6087
+ else:
6088
+ self.disp_corners.add(
6089
+ self.create_polygon(x - 10, y, x, y, x, y + 10, fill=self.PAR.ops.table_grid_fg, tags="lift")
6090
+ )
6091
+
6457
6092
  def redraw_grid_and_text(
6458
6093
  self,
6459
6094
  last_row_line_pos: float,
@@ -6488,6 +6123,8 @@ class MainTable(tk.Canvas):
6488
6123
  self.disp_dropdown = {}
6489
6124
  self.hidd_checkbox.update(self.disp_checkbox)
6490
6125
  self.disp_checkbox = {}
6126
+ self.hidd_corners.update(self.disp_corners)
6127
+ self.disp_corners = set()
6491
6128
  points = []
6492
6129
  # manage horizontal grid lines
6493
6130
  if self.PAR.ops.show_horizontal_grid and row_pos_exists:
@@ -6560,10 +6197,10 @@ class MainTable(tk.Canvas):
6560
6197
  text_start_col=text_start_col,
6561
6198
  text_end_col=text_end_col,
6562
6199
  )
6200
+ note_corners = self.PAR.ops.note_corners
6563
6201
 
6564
6202
  # This is a little messy but
6565
6203
  # we try to avoid any function use to maximise performance
6566
-
6567
6204
  for r in range(text_start_row, text_end_row):
6568
6205
  rtopgridln = self.row_positions[r]
6569
6206
  rbotgridln = self.row_positions[r + 1]
@@ -6720,10 +6357,21 @@ class MainTable(tk.Canvas):
6720
6357
  elif align[-1] == "n":
6721
6358
  draw_x = cleftgridln + (crightgridln - cleftgridln) / 2
6722
6359
 
6360
+ if (
6361
+ note_corners
6362
+ and max_width > 5
6363
+ and (
6364
+ (loc in self.cell_options and "note" in self.cell_options[(datarn, datacn)])
6365
+ or (datarn in self.row_options and "note" in self.row_options[datarn])
6366
+ or (datacn in self.col_options and "note" in self.col_options[datacn])
6367
+ )
6368
+ ):
6369
+ self.redraw_corner(crightgridln, rtopgridln)
6370
+
6723
6371
  # redraw text
6724
6372
 
6725
6373
  text = cells[loc]
6726
- if not text or (align[-1] == "w" and draw_x > scrollpos_right) or cleftgridln + 5 > scrollpos_right:
6374
+ if (align[-1] == "w" and draw_x > scrollpos_right) or cleftgridln + 5 > scrollpos_right:
6727
6375
  continue
6728
6376
  if allow_overflow and not kws:
6729
6377
  if align[-1] == "w":
@@ -6748,14 +6396,33 @@ class MainTable(tk.Canvas):
6748
6396
  iid, showing = self.hidd_text.popitem()
6749
6397
  self.coords(iid, draw_x, draw_y)
6750
6398
  if showing:
6751
- self.itemconfig(iid, text="\n".join(gen_lines), fill=fill, font=font, anchor=align)
6399
+ self.itemconfig(
6400
+ iid,
6401
+ text="\n".join(gen_lines),
6402
+ fill=fill,
6403
+ font=font,
6404
+ anchor=align,
6405
+ tags=("lift", "t", f"{r}_{c}"),
6406
+ )
6752
6407
  else:
6753
6408
  self.itemconfig(
6754
- iid, text="\n".join(gen_lines), fill=fill, font=font, anchor=align, state="normal"
6409
+ iid,
6410
+ text="\n".join(gen_lines),
6411
+ fill=fill,
6412
+ font=font,
6413
+ anchor=align,
6414
+ state="normal",
6415
+ tags=("lift", "t", f"{r}_{c}"),
6755
6416
  )
6756
6417
  else:
6757
6418
  iid = self.create_text(
6758
- draw_x, draw_y, text="\n".join(gen_lines), fill=fill, font=font, anchor=align, tag="lift"
6419
+ draw_x,
6420
+ draw_y,
6421
+ text="\n".join(gen_lines),
6422
+ fill=fill,
6423
+ font=font,
6424
+ anchor=align,
6425
+ tags=("lift", "t", f"{r}_{c}"),
6759
6426
  )
6760
6427
  self.disp_text[iid] = True
6761
6428
 
@@ -6765,12 +6432,33 @@ class MainTable(tk.Canvas):
6765
6432
  iid, showing = self.hidd_text.popitem()
6766
6433
  self.coords(iid, draw_x, draw_y)
6767
6434
  if showing:
6768
- self.itemconfig(iid, text=t, fill=fill, font=font, anchor=align)
6435
+ self.itemconfig(
6436
+ iid,
6437
+ text=t,
6438
+ fill=fill,
6439
+ font=font,
6440
+ anchor=align,
6441
+ tags=("lift", "t", f"{r}_{c}"),
6442
+ )
6769
6443
  else:
6770
- self.itemconfig(iid, text=t, fill=fill, font=font, anchor=align, state="normal")
6444
+ self.itemconfig(
6445
+ iid,
6446
+ text=t,
6447
+ fill=fill,
6448
+ font=font,
6449
+ anchor=align,
6450
+ state="normal",
6451
+ tags=("lift", "t", f"{r}_{c}"),
6452
+ )
6771
6453
  else:
6772
6454
  iid = self.create_text(
6773
- draw_x, draw_y, text=t, fill=fill, font=font, anchor=align, tag="lift"
6455
+ draw_x,
6456
+ draw_y,
6457
+ text=t,
6458
+ fill=fill,
6459
+ font=font,
6460
+ anchor=align,
6461
+ tags=("lift", "t", f"{r}_{c}"),
6774
6462
  )
6775
6463
  self.disp_text[iid] = True
6776
6464
  draw_y += self.table_txt_height
@@ -6785,6 +6473,8 @@ class MainTable(tk.Canvas):
6785
6473
  if showing:
6786
6474
  self.itemconfig(iid, state="hidden")
6787
6475
  dct[iid] = False
6476
+ for iid in self.hidd_corners:
6477
+ self.itemconfig(iid, state="hidden")
6788
6478
  if self.PAR.ops.show_selected_cells_border:
6789
6479
  for _, box in self.selection_boxes.items():
6790
6480
  if box.bd_iid:
@@ -6792,6 +6482,115 @@ class MainTable(tk.Canvas):
6792
6482
  if self.selected:
6793
6483
  self.tag_raise(self.selected.iid)
6794
6484
  self.lift("lift")
6485
+ self.tag_bind("t", "<Enter>", self.enter_text)
6486
+ self.tag_bind("t", "<Leave>", self.leave_text)
6487
+
6488
+ def enter_text(self, event: tk.Event | None = None) -> None:
6489
+ can_x, can_y = self.canvasx(event.x), self.canvasy(event.y)
6490
+ for i in self.find_overlapping(can_x - 1, can_y - 1, can_x + 1, can_y + 1):
6491
+ try:
6492
+ if (coords := self.gettags(i)[2]) == self.tooltip_coords:
6493
+ return
6494
+ self.tooltip_coords = coords
6495
+ self.tooltip_last_x, self.tooltip_last_y = self.winfo_pointerx(), self.winfo_pointery()
6496
+ self.start_tooltip_timer()
6497
+ return
6498
+ except Exception:
6499
+ continue
6500
+
6501
+ def leave_text(self, event: tk.Event | None = None) -> None:
6502
+ if self.tooltip_after_id is not None:
6503
+ self.after_cancel(self.tooltip_after_id)
6504
+ self.tooltip_after_id = None
6505
+ if self.tooltip_showing:
6506
+ if self.winfo_containing(self.winfo_pointerx(), self.winfo_pointery()) not in self.tooltip_widgets:
6507
+ self.close_tooltip_save()
6508
+ else:
6509
+ self.tooltip_coords = None
6510
+
6511
+ def start_tooltip_timer(self) -> None:
6512
+ self.tooltip_after_id = self.after(1000, self.check_and_show_tooltip)
6513
+
6514
+ def check_and_show_tooltip(self, event: tk.Event | None = None) -> None:
6515
+ current_x, current_y = self.winfo_pointerx(), self.winfo_pointery()
6516
+ if current_x < 0 or current_y < 0:
6517
+ return
6518
+ if abs(current_x - self.tooltip_last_x) <= 1 and abs(current_y - self.tooltip_last_y) <= 1:
6519
+ self.show_tooltip()
6520
+ else:
6521
+ self.tooltip_last_x, self.tooltip_last_y = current_x, current_y
6522
+ self.tooltip_after_id = self.after(400, self.check_and_show_tooltip)
6523
+
6524
+ def hide_tooltip(self) -> None:
6525
+ self.tooltip.withdraw()
6526
+ self.tooltip_showing, self.tooltip_coords = False, None
6527
+
6528
+ def show_tooltip(self) -> None:
6529
+ if self.text_editor.open or self.dropdown.open:
6530
+ return
6531
+ coords = self.tooltip_coords.split("_")
6532
+ r, c = int(coords[0]), int(coords[1])
6533
+ datarn, datacn = self.datarn(r), self.datacn(c)
6534
+ kws = self.get_cell_kwargs(datarn, datacn, key="note")
6535
+ if not self.PAR.ops.tooltips and not kws and not self.PAR.ops.user_can_create_notes:
6536
+ return
6537
+ cell_readonly = self.get_cell_kwargs(datarn, datacn, "readonly") or not self.table_edit_cell_enabled()
6538
+ if kws:
6539
+ note = kws["note"]
6540
+ note_readonly = kws["readonly"]
6541
+ elif self.PAR.ops.user_can_create_notes:
6542
+ note = ""
6543
+ note_readonly = bool(cell_readonly)
6544
+ else:
6545
+ note = None
6546
+ note_readonly = True
6547
+ note_only = not self.PAR.ops.tooltips and isinstance(note, str)
6548
+ self.tooltip.reset(
6549
+ **{
6550
+ "text": f"{self.get_cell_data(datarn, datacn, none_to_empty_str=True)}",
6551
+ "cell_readonly": cell_readonly,
6552
+ "note": note,
6553
+ "note_readonly": note_readonly,
6554
+ "row": r,
6555
+ "col": c,
6556
+ "menu_kwargs": get_menu_kwargs(self.PAR.ops),
6557
+ **get_bg_fg(self.PAR.ops),
6558
+ "user_can_create_notes": self.PAR.ops.user_can_create_notes,
6559
+ "note_only": note_only,
6560
+ "width": self.PAR.ops.tooltip_width,
6561
+ "height": self.PAR.ops.tooltip_height,
6562
+ }
6563
+ )
6564
+ self.tooltip.set_position(self.tooltip_last_x - 4, self.tooltip_last_y - 4)
6565
+ self.tooltip_showing = True
6566
+
6567
+ def close_tooltip_save(self, event: tk.Event | None = None) -> None:
6568
+ widget = self.winfo_containing(self.winfo_pointerx(), self.winfo_pointery())
6569
+ if any(widget == tw for tw in self.tooltip_widgets):
6570
+ try:
6571
+ if self.tooltip.notebook.index("current") == 0:
6572
+ self.tooltip.content_text.focus_set()
6573
+ else:
6574
+ self.tooltip.note_text.focus_set()
6575
+ except Exception:
6576
+ self.tooltip.content_text.focus_set()
6577
+ return
6578
+ if not self.tooltip.cell_readonly:
6579
+ r, c, cell, note = self.tooltip.get()
6580
+ datarn, datacn = self.datarn(r), self.datacn(c)
6581
+ event_data = self.new_single_edit_event(
6582
+ r, c, datarn, datacn, "??", self.get_cell_data(datarn, datacn), cell
6583
+ )
6584
+ value, event_data = self.single_edit_run_validation(datarn, datacn, event_data)
6585
+ if value is not None and (
6586
+ self.set_cell_data_undo(r=r, c=c, datarn=datarn, datacn=datacn, value=value, redraw=False)
6587
+ ):
6588
+ try_binding(self.extra_end_edit_cell_func, event_data)
6589
+ if not self.tooltip.note_readonly:
6590
+ self.PAR.note(datarn, datacn, note=note if note else None, readonly=False)
6591
+ self.hide_tooltip()
6592
+ self.refresh()
6593
+ self.focus_set()
6795
6594
 
6796
6595
  def main_table_redraw_grid_and_text(
6797
6596
  self,
@@ -7019,13 +6818,12 @@ class MainTable(tk.Canvas):
7019
6818
  x2 = self.col_positions[c + 1] if index_exists(self.col_positions, c + 1) else self.col_positions[c] + 1
7020
6819
  y2 = self.row_positions[r + 1] if index_exists(self.row_positions, r + 1) else self.row_positions[r] + 1
7021
6820
  self.hide_selected()
7022
- iid = self.display_box(
6821
+ iid = self.display_border(
7023
6822
  x1,
7024
6823
  y1,
7025
6824
  x2,
7026
6825
  y2,
7027
- fill="",
7028
- outline=outline if self.PAR.ops.show_selected_cells_border else "",
6826
+ fill=outline if self.PAR.ops.show_selected_cells_border else "",
7029
6827
  state="normal",
7030
6828
  tags="selected",
7031
6829
  width=2,
@@ -7040,14 +6838,13 @@ class MainTable(tk.Canvas):
7040
6838
  )
7041
6839
  return iid
7042
6840
 
7043
- def display_box(
6841
+ def display_border(
7044
6842
  self,
7045
6843
  x1: int,
7046
6844
  y1: int,
7047
6845
  x2: int,
7048
6846
  y2: int,
7049
6847
  fill: str,
7050
- outline: str,
7051
6848
  state: str,
7052
6849
  tags: str | tuple[str],
7053
6850
  width: int,
@@ -7062,30 +6859,29 @@ class MainTable(tk.Canvas):
7062
6859
  radius=radius,
7063
6860
  )
7064
6861
  if isinstance(iid, int):
7065
- self.itemconfig(iid, fill=fill, outline=outline, state=state, tags=tags, width=width)
7066
- self.coords(iid, coords)
6862
+ self.itemconfig(iid, fill=fill, state=state, tags=tags, width=width)
6863
+ self.coords(iid, *coords)
7067
6864
  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)
6865
+ if self.hidd_borders:
6866
+ iid = self.hidd_borders.pop()
6867
+ self.itemconfig(iid, fill=fill, state=state, tags=tags, width=width)
6868
+ self.coords(iid, *coords)
7072
6869
  else:
7073
- iid = self.create_polygon(
7074
- coords,
6870
+ iid = self.create_line(
6871
+ *coords,
7075
6872
  fill=fill,
7076
- outline=outline,
7077
6873
  state=state,
7078
6874
  tags=tags,
7079
6875
  width=width,
7080
6876
  smooth=True,
7081
6877
  )
7082
- self.disp_boxes.add(iid)
6878
+ self.disp_borders.add(iid)
7083
6879
  return iid
7084
6880
 
7085
- def hide_box(self, item: int | None) -> None:
6881
+ def hide_border(self, item: int | None) -> None:
7086
6882
  if isinstance(item, int):
7087
- self.disp_boxes.discard(item)
7088
- self.hidd_boxes.add(item)
6883
+ self.disp_borders.discard(item)
6884
+ self.hidd_borders.add(item)
7089
6885
  self.itemconfig(item, state="hidden")
7090
6886
 
7091
6887
  def hide_box_fill(self, item: int | None) -> None:
@@ -7098,7 +6894,7 @@ class MainTable(tk.Canvas):
7098
6894
  return False
7099
6895
  box = self.selection_boxes.pop(item)
7100
6896
  self.hide_box_fill(box.fill_iid)
7101
- self.hide_box(box.bd_iid)
6897
+ self.hide_border(box.bd_iid)
7102
6898
  if self.selected.fill_iid == item:
7103
6899
  self.hide_selected()
7104
6900
  self.set_current_to_last()
@@ -7112,7 +6908,7 @@ class MainTable(tk.Canvas):
7112
6908
 
7113
6909
  def hide_selected(self) -> None:
7114
6910
  if self.selected:
7115
- self.hide_box(self.selected.iid)
6911
+ self.hide_border(self.selected.iid)
7116
6912
  self.selected = ()
7117
6913
 
7118
6914
  def get_selection_fill(self) -> int:
@@ -7150,39 +6946,20 @@ class MainTable(tk.Canvas):
7150
6946
  mt_border_col = self.PAR.ops.table_selected_columns_border_fg
7151
6947
  if self.selection_boxes:
7152
6948
  next(reversed(self.selection_boxes.values())).state = "normal"
7153
- x1, y1, x2, y2 = self.box_coords_x_canvas_coords(r1, c1, r2, c2, type_)
6949
+ x1, y1, x2, y2 = self.box_coords_x_canvas_coords(r1, c1, r2, c2)
7154
6950
  fill_iid = self.get_selection_fill()
7155
6951
  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 (
6952
+ if self.PAR.ops.show_selected_cells_border and (
7175
6953
  ext
7176
6954
  or self.ctrl_b1_pressed
7177
6955
  or (self.being_drawn_item is None and self.RI.being_drawn_item is None and self.CH.being_drawn_item is None)
7178
6956
  ):
7179
- bd_iid = self.display_box(
6957
+ bd_iid = self.display_border(
7180
6958
  x1,
7181
6959
  y1,
7182
- x2,
6960
+ self.canvasx(self.winfo_width()) if self.PAR.name == "!SheetDropdown" else x2,
7183
6961
  y2,
7184
- fill="",
7185
- outline=mt_border_col,
6962
+ fill=mt_border_col,
7186
6963
  state="normal",
7187
6964
  tags=f"{type_}bd",
7188
6965
  width=1,
@@ -7209,22 +6986,8 @@ class MainTable(tk.Canvas):
7209
6986
  self.run_selection_binding(type_)
7210
6987
  return fill_iid
7211
6988
 
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
6989
+ def box_coords_x_canvas_coords(self, r1: int, c1: int, r2: int, c2: int) -> tuple[float, float, float, float]:
6990
+ return self.col_positions[c1], self.row_positions[r1], self.col_positions[c2], self.row_positions[r2]
7228
6991
 
7229
6992
  def recreate_selection_box(
7230
6993
  self,
@@ -7253,17 +7016,16 @@ class MainTable(tk.Canvas):
7253
7016
  state = "normal"
7254
7017
  if self.selected.fill_iid == fill_iid:
7255
7018
  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_)
7019
+ x1, y1, x2, y2 = self.box_coords_x_canvas_coords(r1, c1, r2, c2)
7257
7020
  self.selection_boxes[fill_iid].state = state
7258
7021
  if bd_iid := self.selection_boxes[fill_iid].bd_iid:
7259
7022
  if self.PAR.ops.show_selected_cells_border:
7260
- self.display_box(
7023
+ self.display_border(
7261
7024
  x1,
7262
7025
  y1,
7263
7026
  x2,
7264
7027
  y2,
7265
- fill="",
7266
- outline=mt_border_col,
7028
+ fill=mt_border_col,
7267
7029
  state="normal",
7268
7030
  tags=f"{type_}bd",
7269
7031
  width=1,
@@ -7271,7 +7033,7 @@ class MainTable(tk.Canvas):
7271
7033
  )
7272
7034
  self.tag_raise(bd_iid)
7273
7035
  else:
7274
- self.hide_box(bd_iid)
7036
+ self.hide_border(bd_iid)
7275
7037
  if run_binding:
7276
7038
  self.run_selection_binding(type_)
7277
7039
  return fill_iid
@@ -7727,19 +7489,8 @@ class MainTable(tk.Canvas):
7727
7489
  value = self.text_editor.get()
7728
7490
  r, c = self.text_editor.coords
7729
7491
  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},
7492
+ event_data = self.new_single_edit_event(
7493
+ r, c, datarn, datacn, event.keysym, self.get_cell_data(datarn, datacn), value
7743
7494
  )
7744
7495
  value, event_data = self.single_edit_run_validation(datarn, datacn, event_data)
7745
7496
  edited = False
@@ -8034,19 +7785,8 @@ class MainTable(tk.Canvas):
8034
7785
  datacn = self.datacn(c)
8035
7786
  datarn = self.datarn(r)
8036
7787
  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},
7788
+ event_data = self.new_single_edit_event(
7789
+ r, c, datarn, datacn, "??", self.get_cell_data(datarn, datacn), selection
8050
7790
  )
8051
7791
  try_binding(kwargs["select_function"], event_data)
8052
7792
  selection, event_data = self.single_edit_run_validation(datarn, datacn, event_data)
@@ -8118,20 +7858,7 @@ class MainTable(tk.Canvas):
8118
7858
  cell_resize=False,
8119
7859
  check_input_valid=False,
8120
7860
  )
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
- )
7861
+ event_data = self.new_single_edit_event(r, c, datarn, datacn, "??", pre_edit_value, value)
8135
7862
  if kwargs["check_function"] is not None:
8136
7863
  kwargs["check_function"](event_data)
8137
7864
  try_binding(self.extra_end_edit_cell_func, event_data)
@@ -8227,20 +7954,22 @@ class MainTable(tk.Canvas):
8227
7954
  ):
8228
7955
  return False
8229
7956
  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
- )
7957
+ kwargs := self.get_cell_kwargs(
7958
+ datarn,
7959
+ datacn,
7960
+ key="dropdown",
7961
+ cell=r_ops and c_ops,
7962
+ row=r_ops,
7963
+ column=c_ops,
8239
7964
  )
8240
- and kwargs["validate_input"]
8241
- and kwargs["values"]
8242
- ):
8243
- return kwargs["values"][0]
7965
+ ) and kwargs["validate_input"]:
7966
+ if kwargs["default_value"] is None:
7967
+ if kwargs["values"]:
7968
+ return safe_copy(kwargs["values"][0])
7969
+ else:
7970
+ return self.format_value(datarn, datacn, "")
7971
+ else:
7972
+ return safe_copy(kwargs["default_value"])
8244
7973
  else:
8245
7974
  return self.format_value(datarn, datacn, "")
8246
7975