tksheet 7.1.11__py3-none-any.whl → 7.1.20__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/__init__.py CHANGED
@@ -4,7 +4,7 @@
4
4
  tksheet - A Python tkinter table widget
5
5
  """
6
6
 
7
- __version__ = "7.1.11"
7
+ __version__ = "7.1.20"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
@@ -42,6 +42,7 @@ from .functions import (
42
42
  event_dict,
43
43
  get_checkbox_dict,
44
44
  get_checkbox_kwargs,
45
+ get_data_from_clipboard,
45
46
  get_dropdown_dict,
46
47
  get_dropdown_kwargs,
47
48
  get_index_of_gap_in_sorted_integer_seq_forward,
tksheet/column_headers.py CHANGED
@@ -22,10 +22,10 @@ from .colors import (
22
22
  from .formatters import is_bool_like, try_to_bool
23
23
  from .functions import (
24
24
  consecutive_ranges,
25
- ev_stack_dict,
26
25
  event_dict,
27
26
  get_n2a,
28
27
  is_contiguous,
28
+ pickled_event_dict,
29
29
  rounded_box_coords,
30
30
  try_binding,
31
31
  )
@@ -133,6 +133,9 @@ class ColumnHeaders(tk.Canvas):
133
133
  self.bind("<Double-Button-1>", self.double_b1)
134
134
  self.bind(rc_binding, self.rc)
135
135
  self.bind("<MouseWheel>", self.mousewheel)
136
+ if USER_OS == "linux":
137
+ self.bind("<Button-4>", self.mousewheel)
138
+ self.bind("<Button-5>", self.mousewheel)
136
139
  else:
137
140
  self.unbind("<Motion>")
138
141
  self.unbind("<ButtonPress-1>")
@@ -141,6 +144,9 @@ class ColumnHeaders(tk.Canvas):
141
144
  self.unbind("<Double-Button-1>")
142
145
  self.unbind(rc_binding)
143
146
  self.unbind("<MouseWheel>")
147
+ if USER_OS == "linux":
148
+ self.unbind("<Button-4>")
149
+ self.unbind("<Button-5>")
144
150
 
145
151
  def mousewheel(self, event: object):
146
152
  maxlines = 0
@@ -845,7 +851,7 @@ class ColumnHeaders(tk.Canvas):
845
851
  "displayed": disp_new_idxs,
846
852
  }
847
853
  if self.MT.undo_enabled:
848
- self.MT.undo_stack.append(ev_stack_dict(event_data))
854
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
849
855
  self.MT.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
850
856
  try_binding(self.ch_extra_end_drag_drop_func, event_data, "end_move_columns")
851
857
  self.MT.sheet_modified(event_data)
@@ -1953,6 +1959,7 @@ class ColumnHeaders(tk.Canvas):
1953
1959
  self.dropdown.window.reset(**reset_kwargs)
1954
1960
  self.itemconfig(self.dropdown.canvas_id, state="normal")
1955
1961
  self.coords(self.dropdown.canvas_id, self.MT.col_positions[c], ypos)
1962
+ self.dropdown.window.tkraise()
1956
1963
  else:
1957
1964
  self.dropdown.window = self.PAR.dropdown_class(
1958
1965
  self.winfo_toplevel(),
@@ -2090,7 +2097,7 @@ class ColumnHeaders(tk.Canvas):
2090
2097
  self.fix_header(datacn)
2091
2098
  if not check_input_valid or self.input_valid_for_cell(datacn, value):
2092
2099
  if self.MT.undo_enabled and undo:
2093
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2100
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2094
2101
  self.set_cell_data(datacn=datacn, value=value)
2095
2102
  edited = True
2096
2103
  if edited and cell_resize and self.PAR.ops.cell_auto_resize_enabled:
tksheet/functions.py CHANGED
@@ -1,8 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import bisect
4
+ import csv
5
+ import io
4
6
  import pickle
5
7
  import re
8
+ import tkinter as tk
6
9
  import zlib
7
10
  from collections import deque
8
11
  from collections.abc import (
@@ -19,6 +22,7 @@ from .other_classes import (
19
22
  DotDict,
20
23
  EventDataDict,
21
24
  Highlight,
25
+ Loc,
22
26
  Span,
23
27
  )
24
28
 
@@ -27,6 +31,21 @@ pickle_obj = partial(pickle.dumps, protocol=pickle.HIGHEST_PROTOCOL)
27
31
  unpickle_obj = pickle.loads
28
32
 
29
33
 
34
+ def get_data_from_clipboard(
35
+ widget: tk.Misc,
36
+ delimiters: str,
37
+ lineterminator: str = "\n",
38
+ ) -> list[list[str]]:
39
+ data = widget.clipboard_get()
40
+ try:
41
+ dialect = csv.Sniffer().sniff(data, delimiters=delimiters)
42
+ except Exception:
43
+ dialect = csv.excel_tab
44
+ if dialect.delimiter in data or lineterminator in data:
45
+ return list(csv.reader(io.StringIO(data), dialect=dialect, skipinitialspace=True))
46
+ return [[data]]
47
+
48
+
30
49
  def pickle_compress(obj: object) -> bytes:
31
50
  return compress(pickle_obj(obj))
32
51
 
@@ -164,11 +183,8 @@ def change_eventname(event_dict: EventDataDict, newname: str) -> EventDataDict:
164
183
  return EventDataDict({**event_dict, **{"eventname": newname}})
165
184
 
166
185
 
167
- def ev_stack_dict(d: DotDict) -> DotDict:
168
- return DotDict(
169
- name=d["eventname"],
170
- data=pickle_compress(d),
171
- )
186
+ def pickled_event_dict(d: DotDict) -> DotDict:
187
+ return DotDict(name=d["eventname"], data=pickle_compress(d))
172
188
 
173
189
 
174
190
  def len_to_idx(n: int) -> int:
@@ -204,8 +220,6 @@ def get_dropdown_kwargs(
204
220
  def get_dropdown_dict(**kwargs) -> dict:
205
221
  return {
206
222
  "values": kwargs["values"],
207
- "window": "no dropdown open",
208
- "canvas_id": "no dropdown open",
209
223
  "select_function": kwargs["selection_function"],
210
224
  "modified_function": kwargs["modified_function"],
211
225
  "search_function": kwargs["search_function"],
@@ -408,11 +422,13 @@ def index_exists(seq: Sequence[object], index: int) -> bool:
408
422
  def move_elements_by_mapping(
409
423
  seq: list[object],
410
424
  new_idxs: dict[int, int],
411
- old_idxs: dict[int, int],
425
+ old_idxs: dict[int, int] | None = None,
412
426
  ) -> list[object]:
413
427
  # move elements of a list around, displacing
414
428
  # other elements based on mapping
415
429
  # of {old index: new index, ...}
430
+ if old_idxs is None:
431
+ old_idxs = dict(zip(new_idxs.values(), new_idxs))
416
432
 
417
433
  # create dummy list
418
434
  res = [0] * len(seq)
@@ -1295,10 +1311,12 @@ def mod_span_widget(span: Span, widget: object) -> Span:
1295
1311
  def mod_event_val(
1296
1312
  event_data: EventDataDict,
1297
1313
  val: object,
1298
- loc: tuple[int, int] | int,
1314
+ loc: Loc | int,
1299
1315
  ) -> EventDataDict:
1300
1316
  event_data.value = val
1301
- event_data.loc = loc
1317
+ event_data.loc = Loc(*loc)
1318
+ event_data.row = loc[0]
1319
+ event_data.column = loc[1]
1302
1320
  return event_data
1303
1321
 
1304
1322
 
tksheet/main_table.py CHANGED
@@ -52,9 +52,9 @@ from .functions import (
52
52
  decompress_load,
53
53
  diff_gen,
54
54
  diff_list,
55
- ev_stack_dict,
56
55
  event_dict,
57
56
  gen_formatted,
57
+ get_data_from_clipboard,
58
58
  get_new_indexes,
59
59
  get_seq_without_gaps_at_index,
60
60
  index_exists,
@@ -68,6 +68,7 @@ from .functions import (
68
68
  mod_span_widget,
69
69
  move_elements_by_mapping,
70
70
  pickle_obj,
71
+ pickled_event_dict,
71
72
  rounded_box_coords,
72
73
  span_idxs_post_move,
73
74
  try_binding,
@@ -91,6 +92,10 @@ from .text_editor import (
91
92
  )
92
93
  from .vars import (
93
94
  USER_OS,
95
+ bind_add_columns,
96
+ bind_add_rows,
97
+ bind_del_columns,
98
+ bind_del_rows,
94
99
  ctrl_key,
95
100
  rc_binding,
96
101
  symbols_set,
@@ -359,10 +364,10 @@ class MainTable(tk.Canvas):
359
364
  ("<ButtonRelease-1>", self, self.b1_release),
360
365
  ("<Double-Button-1>", self, self.double_b1),
361
366
  ("<MouseWheel>", self, self.mousewheel),
367
+ ("<MouseWheel>", self.RI, self.mousewheel),
362
368
  ("<Shift-ButtonPress-1>", self, self.shift_b1_press),
363
369
  ("<Shift-ButtonPress-1>", self.CH, self.CH.shift_b1_press),
364
370
  ("<Shift-ButtonPress-1>", self.RI, self.RI.shift_b1_press),
365
- ("<MouseWheel>", self.RI, self.mousewheel),
366
371
  (rc_binding, self, self.rc),
367
372
  (f"<{ctrl_key}-ButtonPress-1>", self, self.ctrl_b1_press),
368
373
  (f"<{ctrl_key}-ButtonPress-1>", self.CH, self.CH.ctrl_b1_press),
@@ -381,9 +386,11 @@ class MainTable(tk.Canvas):
381
386
  ("<Control-equal>", self.zoom_in),
382
387
  ("<Control-minus>", self.zoom_out),
383
388
  )
384
- all_canvas_linux_bindings = {
389
+ mt_ri_canvas_linux_bindings = {
385
390
  ("<Button-4>", self.mousewheel),
386
391
  ("<Button-5>", self.mousewheel),
392
+ }
393
+ all_canvas_linux_bindings = {
387
394
  ("<Shift-Button-4>", self.shift_mousewheel),
388
395
  ("<Shift-Button-5>", self.shift_mousewheel),
389
396
  ("<Control-Button-4>", self.ctrl_mousewheel),
@@ -396,6 +403,9 @@ class MainTable(tk.Canvas):
396
403
  for canvas in (self, self.RI, self.CH):
397
404
  canvas.bind(b[0], b[1])
398
405
  if USER_OS == "linux":
406
+ for b in mt_ri_canvas_linux_bindings:
407
+ for canvas in (self, self.RI):
408
+ canvas.bind(b[0], b[1])
399
409
  for b in all_canvas_linux_bindings:
400
410
  for canvas in (self, self.RI, self.CH):
401
411
  canvas.bind(b[0], b[1])
@@ -406,6 +416,9 @@ class MainTable(tk.Canvas):
406
416
  for canvas in (self, self.RI, self.CH):
407
417
  canvas.unbind(b[0])
408
418
  if USER_OS == "linux":
419
+ for b in mt_ri_canvas_linux_bindings:
420
+ for canvas in (self, self.RI):
421
+ canvas.unbind(b[0])
409
422
  for b in all_canvas_linux_bindings:
410
423
  for canvas in (self, self.RI, self.CH):
411
424
  canvas.unbind(b[0])
@@ -491,6 +504,8 @@ class MainTable(tk.Canvas):
491
504
  def get_ctrl_x_c_boxes(self) -> tuple[dict[tuple[int, int, int, int], str], int]:
492
505
  boxes = {}
493
506
  maxrows = 0
507
+ if not self.selected:
508
+ return boxes, maxrows
494
509
  if self.selected.type_ in ("cells", "columns"):
495
510
  curr_box = self.selection_boxes[self.selected.fill_iid].coords
496
511
  maxrows = curr_box[2] - curr_box[0]
@@ -513,7 +528,7 @@ class MainTable(tk.Canvas):
513
528
  )
514
529
  return s, writer
515
530
 
516
- def ctrl_c(self, event=None) -> None:
531
+ def ctrl_c(self, event=None) -> None | EventDataDict:
517
532
  if not self.selected:
518
533
  return
519
534
  event_data = event_dict(
@@ -551,14 +566,17 @@ class MainTable(tk.Canvas):
551
566
  for r1, c1, r2, c2 in boxes:
552
567
  self.show_ctrl_outline(canvas="table", start_cell=(c1, r1), end_cell=(c2, r2))
553
568
  self.clipboard_clear()
554
- if len(event_data["cells"]["table"]) == 1:
569
+ if len(event_data["cells"]["table"]) == 1 and self.PAR.ops.to_clipboard_lineterminator not in next(
570
+ iter(event_data["cells"]["table"].values())
571
+ ):
555
572
  self.clipboard_append(next(iter(event_data["cells"]["table"].values())))
556
573
  else:
557
574
  self.clipboard_append(s.getvalue())
558
575
  self.update_idletasks()
559
576
  try_binding(self.extra_end_ctrl_c_func, event_data, "end_ctrl_c")
577
+ return event_data
560
578
 
561
- def ctrl_x(self, event=None) -> None:
579
+ def ctrl_x(self, event=None, validation: bool = True) -> None | EventDataDict:
562
580
  if not self.selected:
563
581
  return
564
582
  event_data = event_dict(
@@ -582,10 +600,14 @@ class MainTable(tk.Canvas):
582
600
  datacn = self.datacn(c)
583
601
  row.append(self.get_cell_clipboard(datarn, datacn))
584
602
  val = self.get_value_for_empty_cell(datarn, datacn)
585
- if not self.edit_validation_func or (
586
- self.edit_validation_func
587
- and (val := self.edit_validation_func(mod_event_val(event_data, val, (r1 + rn, c))))
588
- is not None
603
+ if (
604
+ not self.edit_validation_func
605
+ or not validation
606
+ or (
607
+ self.edit_validation_func
608
+ and (val := self.edit_validation_func(mod_event_val(event_data, val, (r1 + rn, c))))
609
+ is not None
610
+ )
589
611
  ):
590
612
  event_data = self.event_data_set_cell(
591
613
  datarn,
@@ -603,10 +625,14 @@ class MainTable(tk.Canvas):
603
625
  datacn = self.datacn(c)
604
626
  row.append(self.get_cell_clipboard(datarn, datacn))
605
627
  val = self.get_value_for_empty_cell(datarn, datacn)
606
- if not self.edit_validation_func or (
607
- self.edit_validation_func
608
- and (val := self.edit_validation_func(mod_event_val(event_data, val, (r1 + rn, c))))
609
- is not None
628
+ if (
629
+ not self.edit_validation_func
630
+ or not validation
631
+ or (
632
+ self.edit_validation_func
633
+ and (val := self.edit_validation_func(mod_event_val(event_data, val, (r1 + rn, c))))
634
+ is not None
635
+ )
610
636
  ):
611
637
  event_data = self.event_data_set_cell(
612
638
  datarn,
@@ -616,9 +642,11 @@ class MainTable(tk.Canvas):
616
642
  )
617
643
  writer.writerow(row)
618
644
  if event_data["cells"]["table"]:
619
- self.undo_stack.append(ev_stack_dict(event_data))
645
+ self.undo_stack.append(pickled_event_dict(event_data))
620
646
  self.clipboard_clear()
621
- if len(event_data["cells"]["table"]) == 1:
647
+ if len(event_data["cells"]["table"]) == 1 and self.PAR.ops.to_clipboard_lineterminator not in next(
648
+ iter(event_data["cells"]["table"].values())
649
+ ):
622
650
  self.clipboard_append(next(iter(event_data["cells"]["table"].values())))
623
651
  else:
624
652
  self.clipboard_append(s.getvalue())
@@ -629,8 +657,9 @@ class MainTable(tk.Canvas):
629
657
  if event_data["cells"]["table"]:
630
658
  try_binding(self.extra_end_ctrl_x_func, event_data, "end_ctrl_x")
631
659
  self.sheet_modified(event_data)
660
+ return event_data
632
661
 
633
- def ctrl_v(self, event: object = None) -> None:
662
+ def ctrl_v(self, event: object = None, validation: bool = True) -> None | EventDataDict:
634
663
  if not self.PAR.ops.expand_sheet_if_paste_too_big and (
635
664
  len(self.col_positions) == 1 or len(self.row_positions) == 1
636
665
  ):
@@ -656,18 +685,13 @@ class MainTable(tk.Canvas):
656
685
  elif len(self.row_positions) > 1 and len(self.col_positions) > 1:
657
686
  selected_c, selected_r = 0, len(self.row_positions) - 1
658
687
  try:
659
- data = self.clipboard_get()
688
+ data = get_data_from_clipboard(
689
+ widget=self,
690
+ delimiters=self.PAR.ops.from_clipboard_delimiters,
691
+ lineterminator=self.PAR.ops.to_clipboard_lineterminator,
692
+ )
660
693
  except Exception:
661
694
  return
662
- try:
663
- dialect = csv.Sniffer().sniff(data, delimiters=self.PAR.ops.from_clipboard_delimiters)
664
- except Exception:
665
- dialect = csv.excel_tab
666
- if dialect.delimiter in data:
667
- if not (data := list(csv.reader(io.StringIO(data), dialect=dialect, skipinitialspace=True))):
668
- return
669
- else:
670
- data = [[data]]
671
695
  new_data_numcols = max(map(len, data))
672
696
  new_data_numrows = len(data)
673
697
  for rn, r in enumerate(data):
@@ -745,9 +769,13 @@ class MainTable(tk.Canvas):
745
769
  for ndr, r in enumerate(range(selected_r, selected_r_adjusted_new_data_numrows)):
746
770
  for ndc, c in enumerate(range(selected_c, selected_c_adjusted_new_data_numcols)):
747
771
  val = data[ndr][ndc]
748
- if not self.edit_validation_func or (
749
- self.edit_validation_func
750
- and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
772
+ if (
773
+ not self.edit_validation_func
774
+ or not validation
775
+ or (
776
+ self.edit_validation_func
777
+ and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
778
+ )
751
779
  ):
752
780
  event_data = self.event_data_set_cell(
753
781
  datarn=self.datarn(r),
@@ -781,10 +809,14 @@ class MainTable(tk.Canvas):
781
809
  ):
782
810
  val = data[ndr][ndc]
783
811
  datacn = self.datacn(c)
784
- if not self.edit_validation_func or (
785
- self.edit_validation_func
786
- and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
787
- and self.input_valid_for_cell(r, datacn, val, ignore_empty=True)
812
+ if (
813
+ not self.edit_validation_func
814
+ or not validation
815
+ or (
816
+ self.edit_validation_func
817
+ and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
818
+ and self.input_valid_for_cell(r, datacn, val, ignore_empty=True)
819
+ )
788
820
  ):
789
821
  rows[r][datacn] = val
790
822
  ctr += 1
@@ -819,10 +851,14 @@ class MainTable(tk.Canvas):
819
851
  ):
820
852
  val = data[ndr][ndc]
821
853
  datarn = self.datarn(r)
822
- if not self.edit_validation_func or (
823
- self.edit_validation_func
824
- and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
825
- and self.input_valid_for_cell(datarn, c, val, ignore_empty=True)
854
+ if (
855
+ not self.edit_validation_func
856
+ or not validation
857
+ or (
858
+ self.edit_validation_func
859
+ and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
860
+ and self.input_valid_for_cell(datarn, c, val, ignore_empty=True)
861
+ )
826
862
  ):
827
863
  columns[c][datarn] = val
828
864
  ctr += 1
@@ -835,7 +871,7 @@ class MainTable(tk.Canvas):
835
871
  )
836
872
  self.deselect("all", redraw=False)
837
873
  if event_data["cells"]["table"] or event_data["added"]["rows"] or event_data["added"]["columns"]:
838
- self.undo_stack.append(ev_stack_dict(event_data))
874
+ self.undo_stack.append(pickled_event_dict(event_data))
839
875
  self.create_selection_box(
840
876
  selected_r,
841
877
  selected_c,
@@ -857,8 +893,9 @@ class MainTable(tk.Canvas):
857
893
  if event_data["cells"]["table"] or event_data["added"]["rows"] or event_data["added"]["columns"]:
858
894
  try_binding(self.extra_end_ctrl_v_func, event_data, "end_ctrl_v")
859
895
  self.sheet_modified(event_data)
896
+ return event_data
860
897
 
861
- def delete_key(self, event: object = None) -> None:
898
+ def delete_key(self, event: object = None, validation: bool = True) -> None | EventDataDict:
862
899
  if not self.selected:
863
900
  return
864
901
  event_data = event_dict(
@@ -875,9 +912,13 @@ class MainTable(tk.Canvas):
875
912
  for c in range(c1, c2):
876
913
  datarn, datacn = self.datarn(r), self.datacn(c)
877
914
  val = self.get_value_for_empty_cell(datarn, datacn)
878
- if not self.edit_validation_func or (
879
- self.edit_validation_func
880
- and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
915
+ if (
916
+ not self.edit_validation_func
917
+ or not validation
918
+ or (
919
+ self.edit_validation_func
920
+ and (val := self.edit_validation_func(mod_event_val(event_data, val, (r, c)))) is not None
921
+ )
881
922
  ):
882
923
  event_data = self.event_data_set_cell(
883
924
  datarn,
@@ -886,10 +927,11 @@ class MainTable(tk.Canvas):
886
927
  event_data,
887
928
  )
888
929
  if event_data["cells"]["table"]:
889
- self.undo_stack.append(ev_stack_dict(event_data))
930
+ self.undo_stack.append(pickled_event_dict(event_data))
890
931
  try_binding(self.extra_end_delete_key_func, event_data, "end_delete")
891
932
  self.refresh()
892
933
  self.sheet_modified(event_data)
934
+ return event_data
893
935
 
894
936
  def event_data_set_cell(self, datarn: int, datacn: int, value: object, event_data: dict) -> EventDataDict:
895
937
  if self.input_valid_for_cell(datarn, datacn, value):
@@ -1366,39 +1408,36 @@ class MainTable(tk.Canvas):
1366
1408
  # all the way from 0 to max_idx
1367
1409
  if old_idxs is None:
1368
1410
  old_idxs = dict(zip(new_idxs.values(), new_idxs))
1369
- seq = tuple(range(max_idx + 1))
1370
1411
  return dict(
1371
1412
  zip(
1372
- move_elements_by_mapping(seq, new_idxs, old_idxs),
1373
- seq,
1413
+ move_elements_by_mapping(tuple(range(max_idx + 1)), new_idxs, old_idxs),
1414
+ range(max_idx + 1),
1374
1415
  )
1375
1416
  )
1376
1417
 
1377
- def undo(self, event: object = None) -> None:
1418
+ def undo(self, event: object = None) -> None | EventDataDict:
1378
1419
  if not self.undo_stack:
1379
1420
  return
1380
- if isinstance(self.undo_stack[-1]["data"], dict):
1381
- modification = self.undo_stack[-1]["data"]
1382
- else:
1383
- modification = decompress_load(self.undo_stack[-1]["data"])
1421
+ modification = decompress_load(self.undo_stack[-1]["data"])
1384
1422
  if not try_binding(self.extra_begin_ctrl_z_func, modification, "begin_undo"):
1385
1423
  return
1386
- self.redo_stack.append(self.undo_modification_invert_event(modification))
1424
+ event_data = self.undo_modification_invert_event(modification)
1425
+ self.redo_stack.append(pickled_event_dict(event_data))
1387
1426
  self.undo_stack.pop()
1388
- try_binding(self.extra_end_ctrl_z_func, modification, "end_undo")
1427
+ try_binding(self.extra_end_ctrl_z_func, event_data, "end_undo")
1428
+ return event_data
1389
1429
 
1390
- def redo(self, event: object = None) -> None:
1430
+ def redo(self, event: object = None) -> None | EventDataDict:
1391
1431
  if not self.redo_stack:
1392
1432
  return
1393
- if isinstance(self.redo_stack[-1]["data"], dict):
1394
- modification = self.redo_stack[-1]["data"]
1395
- else:
1396
- modification = decompress_load(self.redo_stack[-1]["data"])
1433
+ modification = decompress_load(self.redo_stack[-1]["data"])
1397
1434
  if not try_binding(self.extra_begin_ctrl_z_func, modification, "begin_redo"):
1398
1435
  return
1399
- self.undo_stack.append(self.undo_modification_invert_event(modification, name="redo"))
1436
+ event_data = self.undo_modification_invert_event(modification, name="redo")
1437
+ self.undo_stack.append(pickled_event_dict(event_data))
1400
1438
  self.redo_stack.pop()
1401
- try_binding(self.extra_end_ctrl_z_func, modification, "end_redo")
1439
+ try_binding(self.extra_end_ctrl_z_func, event_data, "end_redo")
1440
+ return event_data
1402
1441
 
1403
1442
  def sheet_modified(self, event_data: EventDataDict, purge_redo: bool = True) -> None:
1404
1443
  self.PAR.emit_event("<<SheetModified>>", event_data)
@@ -1446,7 +1485,7 @@ class MainTable(tk.Canvas):
1446
1485
  k: mod_span_widget(unpickle_obj(v), self.PAR) for k, v in modification["named_spans"].items()
1447
1486
  }
1448
1487
 
1449
- def undo_modification_invert_event(self, modification: EventDataDict, name: str = "undo") -> bytes | EventDataDict:
1488
+ def undo_modification_invert_event(self, modification: EventDataDict, name: str = "undo") -> EventDataDict:
1450
1489
  self.deselect("all", redraw=False)
1451
1490
  event_data = event_dict(
1452
1491
  name=modification["eventname"],
@@ -1611,7 +1650,7 @@ class MainTable(tk.Canvas):
1611
1650
 
1612
1651
  self.sheet_modified(event_data, purge_redo=False)
1613
1652
  self.refresh()
1614
- return ev_stack_dict(event_data)
1653
+ return event_data
1615
1654
 
1616
1655
  def see(
1617
1656
  self,
@@ -2544,19 +2583,19 @@ class MainTable(tk.Canvas):
2544
2583
  self.undo_enabled = True
2545
2584
  self._tksheet_bind("undo_bindings", self.undo)
2546
2585
  self._tksheet_bind("redo_bindings", self.redo)
2547
- if binding in ("all", "rc_delete_column"):
2586
+ if binding in bind_del_columns:
2548
2587
  self.rc_delete_column_enabled = True
2549
2588
  self.rc_popup_menus_enabled = True
2550
2589
  self.rc_select_enabled = True
2551
- if binding in ("all", "rc_delete_row"):
2590
+ if binding in bind_del_rows:
2552
2591
  self.rc_delete_row_enabled = True
2553
2592
  self.rc_popup_menus_enabled = True
2554
2593
  self.rc_select_enabled = True
2555
- if binding in ("all", "rc_insert_column"):
2594
+ if binding in bind_add_columns:
2556
2595
  self.rc_insert_column_enabled = True
2557
2596
  self.rc_popup_menus_enabled = True
2558
2597
  self.rc_select_enabled = True
2559
- if binding in ("all", "rc_insert_row"):
2598
+ if binding in bind_add_rows:
2560
2599
  self.rc_insert_row_enabled = True
2561
2600
  self.rc_popup_menus_enabled = True
2562
2601
  self.rc_select_enabled = True
@@ -2615,25 +2654,16 @@ class MainTable(tk.Canvas):
2615
2654
  self.RI.row_selection_enabled = False
2616
2655
  if binding in ("all", "row_drag_and_drop", "move_rows"):
2617
2656
  self.RI.drag_and_drop_enabled = False
2618
- if binding in ("all", "rc_delete_column"):
2657
+ if binding in bind_del_columns:
2619
2658
  self.rc_delete_column_enabled = False
2620
- self.rc_popup_menus_enabled = False
2621
- self.rc_select_enabled = False
2622
- if binding in ("all", "rc_delete_row"):
2659
+ if binding in bind_del_rows:
2623
2660
  self.rc_delete_row_enabled = False
2624
- self.rc_popup_menus_enabled = False
2625
- self.rc_select_enabled = False
2626
- if binding in ("all", "rc_insert_column"):
2661
+ if binding in bind_add_columns:
2627
2662
  self.rc_insert_column_enabled = False
2628
- self.rc_popup_menus_enabled = False
2629
- self.rc_select_enabled = False
2630
- if binding in ("all", "rc_insert_row"):
2663
+ if binding in bind_add_rows:
2631
2664
  self.rc_insert_row_enabled = False
2632
- self.rc_popup_menus_enabled = False
2633
- self.rc_select_enabled = False
2634
2665
  if binding in ("all", "right_click_popup_menu", "rc_popup_menu"):
2635
2666
  self.rc_popup_menus_enabled = False
2636
- self.rc_select_enabled = False
2637
2667
  if binding in ("all", "right_click_select", "rc_select"):
2638
2668
  self.rc_select_enabled = False
2639
2669
  if binding in ("all", "edit_cell", "edit_bindings", "edit"):
@@ -2738,9 +2768,10 @@ class MainTable(tk.Canvas):
2738
2768
  popup_menu = self.rc_popup_menu
2739
2769
  else:
2740
2770
  self.deselect("all")
2741
- popup_menu = self.empty_rc_popup_menu
2771
+ if self.rc_popup_menus_enabled:
2772
+ popup_menu = self.empty_rc_popup_menu
2742
2773
  try_binding(self.extra_rc_func, event)
2743
- if popup_menu is not None:
2774
+ if popup_menu:
2744
2775
  popup_menu.tk_popup(event.x_root, event.y_root)
2745
2776
 
2746
2777
  def b1_press(self, event=None):
@@ -3720,6 +3751,22 @@ class MainTable(tk.Canvas):
3720
3751
  del self.row_positions[idx]
3721
3752
  self.row_positions[idx:] = [e - w for e in islice(self.row_positions, idx, len(self.row_positions))]
3722
3753
 
3754
+ def del_col_positions(self, idxs: Iterator[int] | None = None):
3755
+ if idxs is None:
3756
+ del self.col_positions[-1]
3757
+ else:
3758
+ if not isinstance(idxs, set):
3759
+ idxs = set(idxs)
3760
+ self.set_col_positions(itr=(w for i, w in enumerate(self.gen_column_widths()) if i not in idxs))
3761
+
3762
+ def del_row_positions(self, idxs: Iterator[int] | None = None):
3763
+ if idxs is None:
3764
+ del self.row_positions[-1]
3765
+ else:
3766
+ if not isinstance(idxs, set):
3767
+ idxs = set(idxs)
3768
+ self.set_row_positions(itr=(h for i, h in enumerate(self.gen_row_heights()) if i not in idxs))
3769
+
3723
3770
  def get_column_widths(self) -> list[int]:
3724
3771
  return diff_list(self.col_positions)
3725
3772
 
@@ -3732,26 +3779,6 @@ class MainTable(tk.Canvas):
3732
3779
  def gen_row_heights(self) -> Generator[int]:
3733
3780
  return diff_gen(self.row_positions)
3734
3781
 
3735
- def del_col_positions(self, idx: int, num: int = 1, deselect_all: bool = False):
3736
- if deselect_all:
3737
- self.deselect("all", redraw=False)
3738
- if idx == "end" or len(self.col_positions) <= idx + 1:
3739
- del self.col_positions[-1]
3740
- else:
3741
- cws = self.get_column_widths()
3742
- cws[idx : idx + num] = []
3743
- self.set_col_positions(itr=cws)
3744
-
3745
- def del_row_positions(self, idx: int, numrows: int = 1, deselect_all: bool = False):
3746
- if deselect_all:
3747
- self.deselect("all", redraw=False)
3748
- if idx == "end" or len(self.row_positions) <= idx + 1:
3749
- del self.row_positions[-1]
3750
- else:
3751
- rhs = self.get_row_heights()
3752
- rhs[idx : idx + numrows] = []
3753
- self.set_row_positions(itr=rhs)
3754
-
3755
3782
  def insert_col_position(
3756
3783
  self,
3757
3784
  idx: Literal["end"] | int = "end",
@@ -4188,6 +4215,7 @@ class MainTable(tk.Canvas):
4188
4215
  create_ops: bool = True,
4189
4216
  create_selections: bool = True,
4190
4217
  add_row_positions: bool = True,
4218
+ push_ops: bool = True,
4191
4219
  ) -> EventDataDict:
4192
4220
  self.saved_column_widths = {}
4193
4221
  saved_displayed_columns = list(self.displayed_columns)
@@ -4235,10 +4263,11 @@ class MainTable(tk.Canvas):
4235
4263
  )
4236
4264
  if isinstance(self._headers, list):
4237
4265
  self._headers = insert_items(self._headers, header, self.CH.fix_header)
4238
- self.adjust_options_post_add_columns(
4239
- cols=tuple(reversed(columns)),
4240
- create_ops=create_ops,
4241
- )
4266
+ if push_ops:
4267
+ self.adjust_options_post_add_columns(
4268
+ cols=tuple(reversed(columns)),
4269
+ create_ops=create_ops,
4270
+ )
4242
4271
  if create_selections:
4243
4272
  self.deselect("all")
4244
4273
  for boxst, boxend in consecutive_ranges(tuple(reversed(column_widths))):
@@ -4304,7 +4333,7 @@ class MainTable(tk.Canvas):
4304
4333
  event_data=event_data,
4305
4334
  )
4306
4335
  if self.undo_enabled:
4307
- self.undo_stack.append(ev_stack_dict(event_data))
4336
+ self.undo_stack.append(pickled_event_dict(event_data))
4308
4337
  self.refresh()
4309
4338
  try_binding(self.extra_end_insert_cols_rc_func, event_data, "end_add_columns")
4310
4339
  self.sheet_modified(event_data)
@@ -4319,6 +4348,7 @@ class MainTable(tk.Canvas):
4319
4348
  create_ops: bool = True,
4320
4349
  create_selections: bool = True,
4321
4350
  add_col_positions: bool = True,
4351
+ push_ops: bool = True,
4322
4352
  ) -> EventDataDict:
4323
4353
  self.saved_row_heights = {}
4324
4354
  saved_displayed_rows = list(self.displayed_rows)
@@ -4364,10 +4394,11 @@ class MainTable(tk.Canvas):
4364
4394
  (self.PAR.ops.default_column_width for i in range(len(self.col_positions) - 1, maxcn + 1)),
4365
4395
  )
4366
4396
  )
4367
- self.adjust_options_post_add_rows(
4368
- rows=tuple(reversed(rows)),
4369
- create_ops=create_ops,
4370
- )
4397
+ if push_ops:
4398
+ self.adjust_options_post_add_rows(
4399
+ rows=tuple(reversed(rows)),
4400
+ create_ops=create_ops,
4401
+ )
4371
4402
  if create_selections:
4372
4403
  self.deselect("all")
4373
4404
  for boxst, boxend in consecutive_ranges(tuple(reversed(row_heights))):
@@ -4433,7 +4464,7 @@ class MainTable(tk.Canvas):
4433
4464
  event_data=event_data,
4434
4465
  )
4435
4466
  if self.undo_enabled:
4436
- self.undo_stack.append(ev_stack_dict(event_data))
4467
+ self.undo_stack.append(pickled_event_dict(event_data))
4437
4468
  self.refresh()
4438
4469
  try_binding(self.extra_end_insert_rows_rc_func, event_data, "end_add_rows")
4439
4470
  self.sheet_modified(event_data)
@@ -4605,7 +4636,7 @@ class MainTable(tk.Canvas):
4605
4636
  data_cols = selected if self.all_columns_displayed else [self.displayed_columns[c] for c in selected]
4606
4637
  event_data = self.delete_columns_data(data_cols, event_data)
4607
4638
  if self.undo_enabled:
4608
- self.undo_stack.append(ev_stack_dict(event_data))
4639
+ self.undo_stack.append(pickled_event_dict(event_data))
4609
4640
  self.deselect("all")
4610
4641
  try_binding(self.extra_end_del_cols_rc_func, event_data, "end_delete_columns")
4611
4642
  self.sheet_modified(event_data)
@@ -4659,7 +4690,7 @@ class MainTable(tk.Canvas):
4659
4690
  data_rows = selected if self.all_rows_displayed else [self.displayed_rows[r] for r in selected]
4660
4691
  event_data = self.delete_rows_data(data_rows, event_data)
4661
4692
  if self.undo_enabled:
4662
- self.undo_stack.append(ev_stack_dict(event_data))
4693
+ self.undo_stack.append(pickled_event_dict(event_data))
4663
4694
  self.deselect("all")
4664
4695
  try_binding(self.extra_end_del_rows_rc_func, event_data, "end_delete_rows")
4665
4696
  self.sheet_modified(event_data)
@@ -6752,6 +6783,7 @@ class MainTable(tk.Canvas):
6752
6783
  win_w = self.col_positions[c + 1] - self.col_positions[c] + 1
6753
6784
  if anchor == "nw":
6754
6785
  if kwargs["state"] == "normal":
6786
+ self.text_editor.window.update_idletasks()
6755
6787
  ypos = self.row_positions[r] + self.text_editor.window.winfo_height() - 1
6756
6788
  else:
6757
6789
  ypos = self.row_positions[r + 1]
@@ -6770,8 +6802,9 @@ class MainTable(tk.Canvas):
6770
6802
  }
6771
6803
  if self.dropdown.window:
6772
6804
  self.dropdown.window.reset(**reset_kwargs)
6773
- self.itemconfig(self.dropdown.canvas_id, state="normal", anchor=anchor)
6774
6805
  self.coords(self.dropdown.canvas_id, self.col_positions[c], ypos)
6806
+ self.itemconfig(self.dropdown.canvas_id, state="normal", anchor=anchor)
6807
+ self.dropdown.window.tkraise()
6775
6808
  else:
6776
6809
  self.dropdown.window = self.PAR.dropdown_class(
6777
6810
  self.winfo_toplevel(),
@@ -6969,7 +7002,7 @@ class MainTable(tk.Canvas):
6969
7002
  )
6970
7003
  if not check_input_valid or self.input_valid_for_cell(datarn, datacn, value):
6971
7004
  if self.undo_enabled and undo:
6972
- self.undo_stack.append(ev_stack_dict(event_data))
7005
+ self.undo_stack.append(pickled_event_dict(event_data))
6973
7006
  self.set_cell_data(datarn, datacn, value)
6974
7007
  if cell_resize and self.PAR.ops.cell_auto_resize_enabled:
6975
7008
  self.set_cell_size_to_text(r, c, only_set_if_too_small=True, redraw=redraw, run_binding=True)
tksheet/row_index.py CHANGED
@@ -29,11 +29,11 @@ from .formatters import (
29
29
  )
30
30
  from .functions import (
31
31
  consecutive_chunks,
32
- ev_stack_dict,
33
32
  event_dict,
34
33
  get_n2a,
35
34
  is_contiguous,
36
35
  num2alpha,
36
+ pickled_event_dict,
37
37
  rounded_box_coords,
38
38
  try_binding,
39
39
  )
@@ -851,7 +851,7 @@ class RowIndex(tk.Canvas):
851
851
  "displayed": disp_new_idxs,
852
852
  }
853
853
  if self.MT.undo_enabled:
854
- self.MT.undo_stack.append(ev_stack_dict(event_data))
854
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
855
855
  self.MT.main_table_redraw_grid_and_text(redraw_header=True, redraw_row_index=True)
856
856
  try_binding(self.ri_extra_end_drag_drop_func, event_data, "end_move_rows")
857
857
  self.MT.sheet_modified(event_data)
@@ -2029,6 +2029,7 @@ class RowIndex(tk.Canvas):
2029
2029
  win_w = self.current_width + 1
2030
2030
  if anchor == "nw":
2031
2031
  if kwargs["state"] == "normal":
2032
+ self.text_editor.window.update_idletasks()
2032
2033
  ypos = self.MT.row_positions[r] + self.text_editor.window.winfo_height() - 1
2033
2034
  else:
2034
2035
  ypos = self.MT.row_positions[r + 1]
@@ -2049,6 +2050,7 @@ class RowIndex(tk.Canvas):
2049
2050
  self.dropdown.window.reset(**reset_kwargs)
2050
2051
  self.itemconfig(self.dropdown.canvas_id, state="normal", anchor=anchor)
2051
2052
  self.coords(self.dropdown.canvas_id, 0, ypos)
2053
+ self.dropdown.window.tkraise()
2052
2054
  else:
2053
2055
  self.dropdown.window = self.PAR.dropdown_class(
2054
2056
  self.winfo_toplevel(),
@@ -2187,7 +2189,7 @@ class RowIndex(tk.Canvas):
2187
2189
  self.fix_index(datarn)
2188
2190
  if not check_input_valid or self.input_valid_for_cell(datarn, value):
2189
2191
  if self.MT.undo_enabled and undo:
2190
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2192
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2191
2193
  self.set_cell_data(datarn=datarn, value=value)
2192
2194
  edited = True
2193
2195
  if edited and cell_resize and self.PAR.ops.cell_auto_resize_enabled:
tksheet/sheet.py CHANGED
@@ -19,7 +19,6 @@ from .functions import (
19
19
  del_named_span_options,
20
20
  del_named_span_options_nested,
21
21
  dropdown_search_function,
22
- ev_stack_dict,
23
22
  event_dict,
24
23
  fix_format_kwargs,
25
24
  get_checkbox_dict,
@@ -30,6 +29,7 @@ from .functions import (
30
29
  is_iterable,
31
30
  key_to_span,
32
31
  num2alpha,
32
+ pickled_event_dict,
33
33
  pop_positions,
34
34
  set_align,
35
35
  set_readonly,
@@ -1050,29 +1050,23 @@ class Sheet(tk.Frame):
1050
1050
  canvas.basic_bindings(enable)
1051
1051
  return self
1052
1052
 
1053
- def cut(self, event: object = None) -> Sheet:
1054
- self.MT.ctrl_x(event)
1055
- return self
1053
+ def cut(self, event: object = None, validation: bool = True) -> None | EventDataDict:
1054
+ return self.MT.ctrl_x(event, validation)
1056
1055
 
1057
- def copy(self, event: object = None) -> Sheet:
1058
- self.MT.ctrl_c(event)
1059
- return self
1056
+ def copy(self, event: object = None) -> None | EventDataDict:
1057
+ return self.MT.ctrl_c(event)
1060
1058
 
1061
- def paste(self, event: object = None) -> Sheet:
1062
- self.MT.ctrl_v(event)
1063
- return self
1059
+ def paste(self, event: object = None, validation: bool = True) -> None | EventDataDict:
1060
+ return self.MT.ctrl_v(event, validation)
1064
1061
 
1065
- def delete(self, event: object = None) -> Sheet:
1066
- self.MT.delete_key(event)
1067
- return self
1062
+ def delete(self, event: object = None, validation: bool = True) -> None | EventDataDict:
1063
+ return self.MT.delete_key(event, validation)
1068
1064
 
1069
- def undo(self, event: object = None) -> Sheet:
1070
- self.MT.undo(event)
1071
- return self
1065
+ def undo(self, event: object = None) -> None | EventDataDict:
1066
+ return self.MT.undo(event)
1072
1067
 
1073
- def redo(self, event: object = None) -> Sheet:
1074
- self.MT.redo(event)
1075
- return self
1068
+ def redo(self, event: object = None) -> None | EventDataDict:
1069
+ return self.MT.redo(event)
1076
1070
 
1077
1071
  def has_focus(
1078
1072
  self,
@@ -1801,7 +1795,7 @@ class Sheet(tk.Frame):
1801
1795
  or event_data["added"]["rows"]
1802
1796
  ):
1803
1797
  if undo is True or (undo is None and span.undo):
1804
- self.MT.undo_stack.append(ev_stack_dict(event_data))
1798
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
1805
1799
  if emit_event is True or (emit_event is None and span.emit_event):
1806
1800
  self.emit_event("<<SheetModified>>", event_data)
1807
1801
  self.set_refresh_timer(redraw)
@@ -1840,7 +1834,7 @@ class Sheet(tk.Frame):
1840
1834
  event_data = clear_t(r, c, quick_tval(r, c), event_data)
1841
1835
  if event_data["cells"]["table"] or event_data["cells"]["header"] or event_data["cells"]["index"]:
1842
1836
  if undo is True or (undo is None and span.undo):
1843
- self.MT.undo_stack.append(ev_stack_dict(event_data))
1837
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
1844
1838
  if emit_event is True or (emit_event is None and span.emit_event):
1845
1839
  self.emit_event("<<SheetModified>>", event_data)
1846
1840
  self.set_refresh_timer(redraw)
@@ -1939,6 +1933,7 @@ class Sheet(tk.Frame):
1939
1933
  emit_event: bool = False,
1940
1934
  create_selections: bool = True,
1941
1935
  add_column_widths: bool = True,
1936
+ push_ops: bool = True,
1942
1937
  redraw: bool = True,
1943
1938
  ) -> EventDataDict:
1944
1939
  total_cols = None
@@ -2005,9 +2000,10 @@ class Sheet(tk.Frame):
2005
2000
  selected=self.MT.selected,
2006
2001
  ),
2007
2002
  create_selections=create_selections,
2003
+ push_ops=push_ops,
2008
2004
  )
2009
2005
  if undo:
2010
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2006
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2011
2007
  if emit_event:
2012
2008
  self.emit_event("<<SheetModified>>", event_data)
2013
2009
  self.set_refresh_timer(redraw)
@@ -2024,6 +2020,7 @@ class Sheet(tk.Frame):
2024
2020
  emit_event: bool = False,
2025
2021
  create_selections: bool = True,
2026
2022
  add_row_heights: bool = True,
2023
+ push_ops: bool = True,
2027
2024
  redraw: bool = True,
2028
2025
  ) -> EventDataDict:
2029
2026
  old_total = self.MT.equalize_data_row_lengths()
@@ -2098,9 +2095,10 @@ class Sheet(tk.Frame):
2098
2095
  selected=self.MT.selected,
2099
2096
  ),
2100
2097
  create_selections=create_selections,
2098
+ push_ops=push_ops,
2101
2099
  )
2102
2100
  if undo:
2103
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2101
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2104
2102
  if emit_event:
2105
2103
  self.emit_event("<<SheetModified>>", event_data)
2106
2104
  self.set_refresh_timer(redraw)
@@ -2174,7 +2172,7 @@ class Sheet(tk.Frame):
2174
2172
  event_data,
2175
2173
  )
2176
2174
  if undo:
2177
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2175
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2178
2176
  if emit_event:
2179
2177
  self.emit_event("<<SheetModified>>", event_data)
2180
2178
  self.MT.deselect("all", redraw=False)
@@ -2215,7 +2213,7 @@ class Sheet(tk.Frame):
2215
2213
  event_data,
2216
2214
  )
2217
2215
  if undo:
2218
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2216
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2219
2217
  if emit_event:
2220
2218
  self.emit_event("<<SheetModified>>", event_data)
2221
2219
  self.MT.deselect("all", redraw=False)
@@ -2316,7 +2314,7 @@ class Sheet(tk.Frame):
2316
2314
  data_indexes=data_indexes,
2317
2315
  )
2318
2316
  if undo:
2319
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2317
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2320
2318
  if emit_event:
2321
2319
  self.emit_event("<<SheetModified>>", event_data)
2322
2320
  self.set_refresh_timer(redraw)
@@ -2344,7 +2342,7 @@ class Sheet(tk.Frame):
2344
2342
  data_indexes=data_indexes,
2345
2343
  )
2346
2344
  if undo:
2347
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2345
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2348
2346
  if emit_event:
2349
2347
  self.emit_event("<<SheetModified>>", event_data)
2350
2348
  self.set_refresh_timer(redraw)
@@ -2371,7 +2369,7 @@ class Sheet(tk.Frame):
2371
2369
  data_indexes=data_indexes,
2372
2370
  )
2373
2371
  if undo:
2374
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2372
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2375
2373
  if emit_event:
2376
2374
  self.emit_event("<<SheetModified>>", event_data)
2377
2375
  self.set_refresh_timer(redraw)
@@ -2398,7 +2396,7 @@ class Sheet(tk.Frame):
2398
2396
  data_indexes=data_indexes,
2399
2397
  )
2400
2398
  if undo:
2401
- self.MT.undo_stack.append(ev_stack_dict(event_data))
2399
+ self.MT.undo_stack.append(pickled_event_dict(event_data))
2402
2400
  if emit_event:
2403
2401
  self.emit_event("<<SheetModified>>", event_data)
2404
2402
  self.set_refresh_timer(redraw)
@@ -2571,7 +2569,7 @@ class Sheet(tk.Frame):
2571
2569
  self.MT.open_dropdown_window(r, c)
2572
2570
  return self
2573
2571
 
2574
- def close_dropdown(self, r: int, c: int) -> Sheet:
2572
+ def close_dropdown(self, r: int | None = None, c: int | None = None) -> Sheet:
2575
2573
  self.MT.close_dropdown_window(r, c)
2576
2574
  return self
2577
2575
 
@@ -2579,7 +2577,7 @@ class Sheet(tk.Frame):
2579
2577
  self.CH.open_dropdown_window(c)
2580
2578
  return self
2581
2579
 
2582
- def close_header_dropdown(self, c: int) -> Sheet:
2580
+ def close_header_dropdown(self, c: int | None = None) -> Sheet:
2583
2581
  self.CH.close_dropdown_window(c)
2584
2582
  return self
2585
2583
 
@@ -2587,7 +2585,7 @@ class Sheet(tk.Frame):
2587
2585
  self.RI.open_dropdown_window(r)
2588
2586
  return self
2589
2587
 
2590
- def close_index_dropdown(self, r: int) -> Sheet:
2588
+ def close_index_dropdown(self, r: int | None = None) -> Sheet:
2591
2589
  self.RI.close_dropdown_window(r)
2592
2590
  return self
2593
2591
 
@@ -3442,12 +3440,22 @@ class Sheet(tk.Frame):
3442
3440
 
3443
3441
  delete_row_position = del_row_position
3444
3442
 
3443
+ def del_row_positions(self, idxs: Iterator[int] | None = None) -> Sheet:
3444
+ self.MT.del_row_positions(idxs=idxs)
3445
+ self.set_refresh_timer()
3446
+ return self
3447
+
3445
3448
  def del_column_position(self, idx: int, deselect_all: bool = False) -> Sheet:
3446
3449
  self.MT.del_col_position(idx, deselect_all=deselect_all)
3447
3450
  return self
3448
3451
 
3449
3452
  delete_column_position = del_column_position
3450
3453
 
3454
+ def del_column_positions(self, idxs: Iterator[int] | None = None) -> Sheet:
3455
+ self.MT.del_col_positions(idxs=idxs)
3456
+ self.set_refresh_timer()
3457
+ return self
3458
+
3451
3459
  def insert_column_position(
3452
3460
  self,
3453
3461
  idx: Literal["end"] | int = "end",
@@ -4249,27 +4257,27 @@ class Sheet(tk.Frame):
4249
4257
  target = self.CH.cell_options
4250
4258
  if key is None:
4251
4259
  return target
4252
- return {k: v for k, v in target.items() if key in v}
4260
+ return {k: v[key] for k, v in target.items() if key in v}
4253
4261
 
4254
4262
  def get_row_options(self, key: None | str = None) -> dict:
4255
4263
  if key is None:
4256
4264
  return self.MT.row_options
4257
- return {k: v for k, v in self.MT.row_options.items() if key in v}
4265
+ return {k: v[key] for k, v in self.MT.row_options.items() if key in v}
4258
4266
 
4259
4267
  def get_column_options(self, key: None | str = None) -> dict:
4260
4268
  if key is None:
4261
4269
  return self.MT.col_options
4262
- return {k: v for k, v in self.MT.col_options.items() if key in v}
4270
+ return {k: v[key] for k, v in self.MT.col_options.items() if key in v}
4263
4271
 
4264
4272
  def get_index_options(self, key: None | str = None) -> dict:
4265
4273
  if key is None:
4266
4274
  return self.RI.cell_options
4267
- return {k: v for k, v in self.RI.cell_options.items() if key in v}
4275
+ return {k: v[key] for k, v in self.RI.cell_options.items() if key in v}
4268
4276
 
4269
4277
  def get_header_options(self, key: None | str = None) -> dict:
4270
4278
  if key is None:
4271
4279
  return self.CH.cell_options
4272
- return {k: v for k, v in self.CH.cell_options.items() if key in v}
4280
+ return {k: v[key] for k, v in self.CH.cell_options.items() if key in v}
4273
4281
 
4274
4282
  def del_out_of_bounds_options(self) -> Sheet:
4275
4283
  maxc = self.total_columns()
@@ -4470,6 +4478,7 @@ class Sheet(tk.Frame):
4470
4478
  iid_column: int,
4471
4479
  parent_column: int,
4472
4480
  text_column: None | int = None,
4481
+ push_ops: bool = False,
4473
4482
  ) -> Sheet:
4474
4483
  if text_column is None:
4475
4484
  text_column = iid_column
@@ -4518,6 +4527,7 @@ class Sheet(tk.Frame):
4518
4527
  row_index=True,
4519
4528
  create_selections=False,
4520
4529
  fill=False,
4530
+ push_ops=push_ops,
4521
4531
  )
4522
4532
  self.RI.tree_rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
4523
4533
  self.hide_rows(
@@ -6231,8 +6241,8 @@ class Sheet(tk.Frame):
6231
6241
  kwargs = self.RI.get_cell_kwargs(r_, key="dropdown")
6232
6242
  if kwargs:
6233
6243
  kwargs["values"] = values
6234
- if self.RI.current_dropdown_window is not None:
6235
- self.RI.current_dropdown_window.values(values)
6244
+ if self.RI.dropdown.open:
6245
+ self.RI.dropdown.window.values(values)
6236
6246
  if set_value is not None:
6237
6247
  self.MT.row_index(newindex=set_value, index=r_)
6238
6248
  # here
@@ -6454,7 +6464,7 @@ class Dropdown(Sheet):
6454
6464
  width: int | None = None,
6455
6465
  height: int | None = None,
6456
6466
  font: None | tuple[str, int, str] = None,
6457
- outline_thickness: int = 1,
6467
+ outline_thickness: int = 2,
6458
6468
  values: list[object] = [],
6459
6469
  close_dropdown_window: Callable | None = None,
6460
6470
  search_function: Callable = dropdown_search_function,
@@ -6512,6 +6522,7 @@ class Dropdown(Sheet):
6512
6522
  align: str,
6513
6523
  values: list[object] | None = None,
6514
6524
  ) -> None:
6525
+ self.deselect(redraw=False)
6515
6526
  self.r = r
6516
6527
  self.c = c
6517
6528
  self.row = -1
tksheet/themes.py CHANGED
@@ -1,6 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
- theme_light_blue: dict[str, str] = {
3
+ from .other_classes import DotDict
4
+
5
+ theme_light_blue: dict[str, str] = DotDict({
4
6
  "popup_menu_fg": "#000000",
5
7
  "popup_menu_bg": "#FFFFFF",
6
8
  "popup_menu_highlight_bg": "#DCDEE0",
@@ -70,9 +72,9 @@ theme_light_blue: dict[str, str] = {
70
72
  "horizontal_scroll_not_active_fg": "#DADCE0",
71
73
  "vertical_scroll_pressed_fg": "#bdc1c6",
72
74
  "horizontal_scroll_pressed_fg": "#bdc1c6",
73
- }
75
+ })
74
76
 
75
- theme_light_green: dict[str, str] = {
77
+ theme_light_green: dict[str, str] = DotDict({
76
78
  "popup_menu_fg": "#000000",
77
79
  "popup_menu_bg": "#FFFFFF",
78
80
  "popup_menu_highlight_bg": "#DCDEE0",
@@ -142,9 +144,9 @@ theme_light_green: dict[str, str] = {
142
144
  "horizontal_scroll_not_active_fg": "#c1c1c1",
143
145
  "vertical_scroll_pressed_fg": "#707070",
144
146
  "horizontal_scroll_pressed_fg": "#707070",
145
- }
147
+ })
146
148
 
147
- theme_dark: dict[str, str] = {
149
+ theme_dark: dict[str, str] = DotDict({
148
150
  "popup_menu_fg": "white",
149
151
  "popup_menu_bg": "gray15",
150
152
  "popup_menu_highlight_bg": "gray40",
@@ -214,9 +216,9 @@ theme_dark: dict[str, str] = {
214
216
  "horizontal_scroll_not_active_fg": "#3b3b3d",
215
217
  "vertical_scroll_pressed_fg": "#a0a0a0",
216
218
  "horizontal_scroll_pressed_fg": "#a0a0a0",
217
- }
219
+ })
218
220
 
219
- theme_black: dict[str, str] = {
221
+ theme_black: dict[str, str] = DotDict({
220
222
  "popup_menu_fg": "white",
221
223
  "popup_menu_bg": "gray15",
222
224
  "popup_menu_highlight_bg": "gray40",
@@ -286,9 +288,9 @@ theme_black: dict[str, str] = {
286
288
  "horizontal_scroll_not_active_fg": "#3b3a39",
287
289
  "vertical_scroll_pressed_fg": "#a0a0a0",
288
290
  "horizontal_scroll_pressed_fg": "#a0a0a0",
289
- }
291
+ })
290
292
 
291
- theme_dark_blue: dict[str, str] = theme_black.copy()
293
+ theme_dark_blue: dict[str, str] = DotDict(theme_black.copy())
292
294
  theme_dark_blue["header_fg"] = "#6ACAD8"
293
295
  theme_dark_blue["header_selected_cells_fg"] = "#6ACAD8"
294
296
  theme_dark_blue["index_fg"] = "#6ACAD8"
@@ -303,7 +305,7 @@ theme_dark_blue["index_selected_rows_bg"] = "#6ACAD8"
303
305
  theme_dark_blue["table_selected_rows_border_fg"] = "#6ACAD8"
304
306
  theme_dark_blue["table_selected_columns_border_fg"] = "#6ACAD8"
305
307
 
306
- theme_dark_green: dict[str, str] = theme_black.copy()
308
+ theme_dark_green: dict[str, str] = DotDict(theme_black.copy())
307
309
  theme_dark_green["header_fg"] = "#66FFBF"
308
310
  theme_dark_green["header_selected_cells_fg"] = "#66FFBF"
309
311
  theme_dark_green["index_fg"] = "#66FFBF"
tksheet/vars.py CHANGED
@@ -9,23 +9,28 @@ symbols_set: set[str] = set("""!#$%&'()*+,-./:;"@[]^_`{|}~>?= \\""")
9
9
  nonelike: set[object] = {None, "none", ""}
10
10
  truthy: set[object] = {True, "true", "t", "yes", "y", "on", "1", 1, 1.0}
11
11
  falsy: set[object] = {False, "false", "f", "no", "n", "off", "0", 0, 0.0}
12
+
12
13
  val_modifying_options: set[str, str, str] = {"checkbox", "format", "dropdown"}
13
- named_span_types = (
14
+
15
+ named_span_types: set[str] = {
14
16
  "format",
15
17
  "highlight",
16
18
  "dropdown",
17
19
  "checkbox",
18
20
  "readonly",
19
21
  "align",
20
- )
22
+ }
23
+
21
24
  emitted_events: set[str] = {
22
25
  "<<SheetModified>>",
23
26
  "<<SheetRedrawn>>",
24
27
  "<<SheetSelect>>",
25
28
  }
29
+
26
30
  backwards_compatibility_keys: dict[str, str] = {
27
31
  "font": "table_font",
28
32
  }
33
+
29
34
  text_editor_to_unbind: tuple[str] = (
30
35
  "<Alt-Return>",
31
36
  "<Alt-KP_Enter>",
@@ -36,6 +41,7 @@ text_editor_to_unbind: tuple[str] = (
36
41
  "<FocusOut>",
37
42
  "<Escape>",
38
43
  )
44
+
39
45
  scrollbar_options_keys: set[str] = {
40
46
  "vertical_scroll_background",
41
47
  "horizontal_scroll_background",
@@ -70,3 +76,47 @@ scrollbar_options_keys: set[str] = {
70
76
  "vertical_scroll_pressed_fg",
71
77
  "horizontal_scroll_pressed_fg",
72
78
  }
79
+
80
+ bind_add_columns: set[str] = {
81
+ "all",
82
+ "rc_insert_column",
83
+ "insert_column",
84
+ "add_column",
85
+ "insert_columns",
86
+ "add_columns",
87
+ "insert column",
88
+ "add column",
89
+ }
90
+
91
+ bind_del_columns: set[str] = {
92
+ "all",
93
+ "rc_delete_column",
94
+ "delete_column",
95
+ "del_column",
96
+ "delete_columns",
97
+ "del_columns",
98
+ "delete columns",
99
+ "del columns",
100
+ }
101
+
102
+ bind_add_rows: set[str] = {
103
+ "all",
104
+ "rc_insert_row",
105
+ "insert_row",
106
+ "add_row",
107
+ "insert_rows",
108
+ "add_rows",
109
+ "insert row",
110
+ "add row",
111
+ }
112
+
113
+ bind_del_rows: set[str] = {
114
+ "all",
115
+ "rc_delete_row",
116
+ "delete_row",
117
+ "del_row",
118
+ "delete_rows",
119
+ "del_rows",
120
+ "delete rows",
121
+ "del rows",
122
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tksheet
3
- Version: 7.1.11
3
+ Version: 7.1.20
4
4
  Summary: Tkinter table / sheet widget
5
5
  Author-email: ragardner <github@ragardner.simplelogin.com>
6
6
  License: Copyright (c) 2019 ragardner and open source contributors
@@ -42,7 +42,7 @@ License-File: LICENSE.txt
42
42
 
43
43
  # tksheet
44
44
 
45
- [![PyPI version shields.io](https://img.shields.io/pypi/v/tksheet.svg)](https://pypi.python.org/pypi/tksheet/) ![python](https://img.shields.io/badge/python-3.8+-blue) [![License: MIT](https://img.shields.io/badge/License-MIT%20-blue.svg)](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
45
+ [![PyPI version shields.io](https://img.shields.io/pypi/v/tksheet.svg)](https://pypi.python.org/pypi/tksheet/) ![python](https://img.shields.io/badge/python-3.8|3.9|3.10|3.11|3.12-blue) [![License: MIT](https://img.shields.io/badge/License-MIT%20-blue.svg)](https://github.com/ragardner/tksheet/blob/master/LICENSE.txt)
46
46
 
47
47
  [![GitHub Release Date](https://img.shields.io/github/release-date-pre/ragardner/tksheet.svg)](https://github.com/ragardner/tksheet/releases) [![Downloads](https://img.shields.io/pypi/dm/tksheet.svg)](https://pypi.org/project/tksheet/)
48
48
 
@@ -0,0 +1,20 @@
1
+ tksheet/__init__.py,sha256=n15iE0L6zsiYW5IhLE5m3yb867QM9gl2SBrdQk_bjLc,2044
2
+ tksheet/colors.py,sha256=1k06VorynLmnC4FdJg8H4reIA6rXaeXBpdMwXLhN8oc,51594
3
+ tksheet/column_headers.py,sha256=Kzu_nIMt3oFZO6F00iHBmjv5L0STsVN7Gc34wzwKDJ4,100785
4
+ tksheet/formatters.py,sha256=DXif00aq9DgFpXwkbiqD86KxtDg0Meop51hLY-KcGNQ,10037
5
+ tksheet/functions.py,sha256=Vm_tCPCaos8C_or_70OGpSrXKmFnE8OxODchfrUJBMM,40281
6
+ tksheet/main_table.py,sha256=DrRC3WLGiS6JkAS4Ir-8c1n_4C4l4Coe6jb45Uceekc,320235
7
+ tksheet/other_classes.py,sha256=P3FYUYreLhstATvHCNow8sDQoCsD_02KB6oXcca3ahE,13628
8
+ tksheet/row_index.py,sha256=57cWphhUGsghh9UiHtAHi0m9S403-9MrYiMtTzK7h8E,106014
9
+ tksheet/sheet.py,sha256=TLWV_C-C3XiweHbPdskCnT9v6Zr6Dxym2Ijv-CULgWs,260302
10
+ tksheet/sheet_options.py,sha256=mh0rTvWrFvIKaiv88jtMZy0TSA8zTS1GXSe88u8_rzk,11978
11
+ tksheet/text_editor.py,sha256=81_IZKrTVa2KIx2cJ4n3cFvFMAwvbHIQYgqtyat-97I,6681
12
+ tksheet/themes.py,sha256=0XY97zB9e26edyxMWutofNarNon8Pp5lpprHYeL_4b0,13490
13
+ tksheet/top_left_rectangle.py,sha256=-2u9GfOvcqhkKwHEtbqdFvXCY3RbvL5k2Sh9l3r_k04,8275
14
+ tksheet/types.py,sha256=IgoEHMbceKpakcZtanxKaKJ4RdCq7UW6EoEIIz5O59k,340
15
+ tksheet/vars.py,sha256=Nb0mhxJt-SXipi3cE9J9Ea1H1iPqC8PRvUR9CqqMlVA,3062
16
+ tksheet-7.1.20.dist-info/LICENSE.txt,sha256=ndbcCPe9SlHfweE_W2RAueWUe2k7yudyxYLq6WjFdn4,1101
17
+ tksheet-7.1.20.dist-info/METADATA,sha256=C_WIADFKe41LVlFXKzK7QFO6vQIi0ym2Uk40WiNx9zM,6032
18
+ tksheet-7.1.20.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
19
+ tksheet-7.1.20.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
20
+ tksheet-7.1.20.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- tksheet/__init__.py,sha256=w1YOGIZHF7gjLLEWIH-XLK-ftzuYgSiLTvMUg6ORTYM,2014
2
- tksheet/colors.py,sha256=1k06VorynLmnC4FdJg8H4reIA6rXaeXBpdMwXLhN8oc,51594
3
- tksheet/column_headers.py,sha256=6yYncfnKKKlSGTln35eP74e2Oom9A2XX85SrIsDeq9g,100452
4
- tksheet/formatters.py,sha256=DXif00aq9DgFpXwkbiqD86KxtDg0Meop51hLY-KcGNQ,10037
5
- tksheet/functions.py,sha256=ytmHQtSa8cN6dKYLFra5G0393-4sU7bivvT_U4wxksI,39697
6
- tksheet/main_table.py,sha256=1K-JpLixwx_cnqp5IXeghRWyzaMdQiP6BPm6QVOtfzs,319012
7
- tksheet/other_classes.py,sha256=P3FYUYreLhstATvHCNow8sDQoCsD_02KB6oXcca3ahE,13628
8
- tksheet/row_index.py,sha256=BnQF-lxH50MfPWlXW94oYSEJXoPewoX29VS7j0X1Jwc,105895
9
- tksheet/sheet.py,sha256=dvYtZpNJsu6WfjdUKt6RKcwKeDY5c7wZ-tQfL1rjglQ,259484
10
- tksheet/sheet_options.py,sha256=mh0rTvWrFvIKaiv88jtMZy0TSA8zTS1GXSe88u8_rzk,11978
11
- tksheet/text_editor.py,sha256=81_IZKrTVa2KIx2cJ4n3cFvFMAwvbHIQYgqtyat-97I,6681
12
- tksheet/themes.py,sha256=OwUe31NRbosjw3ZoZsMyB8lNVyYin9YcKLhCturi5q8,13398
13
- tksheet/top_left_rectangle.py,sha256=-2u9GfOvcqhkKwHEtbqdFvXCY3RbvL5k2Sh9l3r_k04,8275
14
- tksheet/types.py,sha256=IgoEHMbceKpakcZtanxKaKJ4RdCq7UW6EoEIIz5O59k,340
15
- tksheet/vars.py,sha256=8Qxas-m5nU-yMaeAweO4Z30FM9cOQoRTiOsH4kgZp5s,2288
16
- tksheet-7.1.11.dist-info/LICENSE.txt,sha256=ndbcCPe9SlHfweE_W2RAueWUe2k7yudyxYLq6WjFdn4,1101
17
- tksheet-7.1.11.dist-info/METADATA,sha256=SRDk-Is6G0UmdJ6PAMgPzkwumb4PLOFETNplec7bkbE,6014
18
- tksheet-7.1.11.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
19
- tksheet-7.1.11.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
20
- tksheet-7.1.11.dist-info/RECORD,,