tksheet 7.2.18__py3-none-any.whl → 7.2.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.2.18"
7
+ __version__ = "7.2.20"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
@@ -12,6 +12,8 @@ from .colors import (
12
12
  from .column_headers import ColumnHeaders
13
13
  from .formatters import (
14
14
  Formatter,
15
+ alt_percentage_to_str,
16
+ alt_to_percentage,
15
17
  bool_formatter,
16
18
  data_to_str,
17
19
  float_formatter,
@@ -28,6 +30,7 @@ from .formatters import (
28
30
  to_bool,
29
31
  to_float,
30
32
  to_int,
33
+ to_percentage,
31
34
  to_str,
32
35
  try_to_bool,
33
36
  )
tksheet/column_headers.py CHANGED
@@ -56,8 +56,7 @@ from .vars import (
56
56
 
57
57
  class ColumnHeaders(tk.Canvas):
58
58
  def __init__(self, *args, **kwargs):
59
- tk.Canvas.__init__(
60
- self,
59
+ super().__init__(
61
60
  kwargs["parent"],
62
61
  background=kwargs["parent"].ops.header_bg,
63
62
  highlightthickness=0,
@@ -290,8 +289,7 @@ class ColumnHeaders(tk.Canvas):
290
289
 
291
290
  def shift_b1_press(self, event: object) -> None:
292
291
  self.mouseclick_outside_editor_or_dropdown_all_canvases(inside=True)
293
- x = event.x
294
- c = self.MT.identify_col(x=x)
292
+ c = self.MT.identify_col(x=event.x)
295
293
  if (self.drag_and_drop_enabled or self.col_selection_enabled) and self.rsz_h is None and self.rsz_w is None:
296
294
  if c < len(self.MT.col_positions) - 1:
297
295
  c_selected = self.MT.col_selected(c)
@@ -316,7 +314,7 @@ class ColumnHeaders(tk.Canvas):
316
314
  )
317
315
 
318
316
  def get_shift_select_box(self, c: int, min_c: int) -> tuple[int, int, int, int, str]:
319
- if c > min_c:
317
+ if c >= min_c:
320
318
  return 0, min_c, len(self.MT.row_positions) - 1, c + 1
321
319
  elif c < min_c:
322
320
  return 0, c, len(self.MT.row_positions) - 1, min_c + 1
tksheet/formatters.py CHANGED
@@ -5,19 +5,25 @@ from collections.abc import Callable
5
5
  from .vars import falsy, nonelike, truthy
6
6
 
7
7
 
8
- def is_none_like(o: object):
8
+ def is_none_like(o: object) -> bool:
9
9
  if (isinstance(o, str) and o.lower().replace(" ", "") in nonelike) or o in nonelike:
10
10
  return True
11
11
  return False
12
12
 
13
13
 
14
- def to_int(o: object, **kwargs):
14
+ def to_int(o: object, **kwargs) -> int:
15
15
  if isinstance(o, int):
16
16
  return o
17
17
  return int(float(o))
18
18
 
19
19
 
20
- def to_float(o: object, **kwargs):
20
+ def to_float(o: object, **kwargs) -> float:
21
+ if isinstance(o, float):
22
+ return o
23
+ return float(o)
24
+
25
+
26
+ def to_percentage(o: object, **kwargs) -> float:
21
27
  if isinstance(o, float):
22
28
  return o
23
29
  if isinstance(o, str) and o.endswith("%"):
@@ -25,7 +31,15 @@ def to_float(o: object, **kwargs):
25
31
  return float(o)
26
32
 
27
33
 
28
- def to_bool(val: object, **kwargs):
34
+ def alt_to_percentage(o: object, **kwargs) -> float:
35
+ if isinstance(o, float):
36
+ return o
37
+ if isinstance(o, str) and o.endswith("%"):
38
+ return float(o.replace("%", ""))
39
+ return float(o)
40
+
41
+
42
+ def to_bool(val: object, **kwargs) -> bool:
29
43
  if isinstance(val, bool):
30
44
  return val
31
45
  if isinstance(val, str):
@@ -47,14 +61,14 @@ def to_bool(val: object, **kwargs):
47
61
  raise ValueError(f'Cannot map "{val}" to bool.')
48
62
 
49
63
 
50
- def try_to_bool(o: object, **kwargs):
64
+ def try_to_bool(o: object, **kwargs) -> object:
51
65
  try:
52
66
  return to_bool(o)
53
67
  except Exception:
54
68
  return o
55
69
 
56
70
 
57
- def is_bool_like(o: object, **kwargs):
71
+ def is_bool_like(o: object, **kwargs) -> bool:
58
72
  try:
59
73
  to_bool(o)
60
74
  return True
@@ -66,7 +80,7 @@ def to_str(o: object, **kwargs: dict) -> str:
66
80
  return f"{o}"
67
81
 
68
82
 
69
- def float_to_str(v: int | float, **kwargs: dict) -> str:
83
+ def float_to_str(v: object, **kwargs: dict) -> str:
70
84
  if isinstance(v, float):
71
85
  if v.is_integer():
72
86
  return f"{int(v)}"
@@ -77,7 +91,7 @@ def float_to_str(v: int | float, **kwargs: dict) -> str:
77
91
  return f"{v}"
78
92
 
79
93
 
80
- def percentage_to_str(v: int | float, **kwargs: dict) -> str:
94
+ def percentage_to_str(v: object, **kwargs: dict) -> str:
81
95
  if isinstance(v, (int, float)):
82
96
  x = v * 100
83
97
  if isinstance(x, float):
@@ -87,7 +101,12 @@ def percentage_to_str(v: int | float, **kwargs: dict) -> str:
87
101
  if kwargs["decimals"]:
88
102
  return f"{round(x, kwargs['decimals'])}%"
89
103
  return f"{int(round(x, kwargs['decimals']))}%"
90
- return f"{x}%"
104
+ return f"{x}%"
105
+ return f"{v}%"
106
+
107
+
108
+ def alt_percentage_to_str(v: object, **kwargs: dict) -> str:
109
+ return f"{float_to_str(v)}%"
91
110
 
92
111
 
93
112
  def bool_to_str(v: object, **kwargs: dict) -> str:
@@ -126,7 +145,7 @@ def float_formatter(
126
145
 
127
146
  def percentage_formatter(
128
147
  datatypes: tuple[object] | object = float,
129
- format_function: Callable = to_float,
148
+ format_function: Callable = to_percentage,
130
149
  to_str_function: Callable = percentage_to_str,
131
150
  decimals: int = 2,
132
151
  **kwargs,
tksheet/functions.py CHANGED
@@ -325,16 +325,11 @@ def force_bool(o: object) -> bool:
325
325
  return False
326
326
 
327
327
 
328
- def str_to_coords(s: str) -> None | tuple[int]:
329
- s = s.split(":")
330
-
331
-
332
328
  def alpha2idx(a: str) -> int | None:
333
329
  try:
334
- a = a.upper()
335
330
  n = 0
336
331
  orda = ord("A")
337
- for c in a:
332
+ for c in a.upper():
338
333
  n = n * 26 + ord(c) - orda + 1
339
334
  return n - 1
340
335
  except Exception:
@@ -522,9 +517,7 @@ def add_to_displayed(displayed: list[int], to_add: Iterator[int]) -> list[int]:
522
517
  # assumes to_add is sorted in reverse
523
518
  for i in reversed(to_add):
524
519
  ins = bisect_left(displayed, i)
525
- displayed[ins:] = [e + 1 for e in islice(displayed, ins, None)]
526
- for i in reversed(to_add):
527
- displayed.insert(bisect_left(displayed, i), i)
520
+ displayed[ins:] = [i] + [e + 1 for e in islice(displayed, ins, None)]
528
521
  return displayed
529
522
 
530
523
 
@@ -595,7 +588,11 @@ def get_new_indexes(
595
588
  return new_idxs
596
589
 
597
590
 
598
- def insert_items(seq: list | tuple, to_insert: dict, seq_len_func: Callable | None = None) -> list:
591
+ def insert_items(
592
+ seq: list[object] | tuple[object],
593
+ to_insert: dict[int, object],
594
+ seq_len_func: Callable | None = None,
595
+ ) -> list:
599
596
  # inserts many items into a list using a dict of reverse sorted order of
600
597
  # {index: value, index: value, ...}
601
598
  res = []
@@ -1425,7 +1422,7 @@ def mod_event_val(
1425
1422
 
1426
1423
 
1427
1424
  def pop_positions(
1428
- itr: Iterator[int],
1425
+ itr: Callable,
1429
1426
  to_pop: dict[int, int], # displayed index: data index
1430
1427
  save_to: dict[int, int],
1431
1428
  ) -> Iterator[int]:
tksheet/main_table.py CHANGED
@@ -115,8 +115,7 @@ from .vars import (
115
115
 
116
116
  class MainTable(tk.Canvas):
117
117
  def __init__(self, *args, **kwargs):
118
- tk.Canvas.__init__(
119
- self,
118
+ super().__init__(
120
119
  kwargs["parent"],
121
120
  background=kwargs["parent"].ops.table_bg,
122
121
  highlightthickness=0,
@@ -126,6 +125,7 @@ class MainTable(tk.Canvas):
126
125
  self.PAR_height = 0
127
126
  self.scrollregion = tuple()
128
127
  self.current_cursor = ""
128
+ self.ctrl_b1_pressed = False
129
129
  self.b1_pressed_loc = None
130
130
  self.closed_dropdown = None
131
131
  self.centre_alignment_text_mod_indexes = (slice(1, None), slice(None, -1))
@@ -670,8 +670,6 @@ class MainTable(tk.Canvas):
670
670
  event_data,
671
671
  )
672
672
  writer.writerow(row)
673
- if event_data["cells"]["table"]:
674
- self.undo_stack.append(pickled_event_dict(event_data))
675
673
  self.clipboard_clear()
676
674
  if len(event_data["cells"]["table"]) == 1 and self.PAR.ops.to_clipboard_lineterminator not in next(
677
675
  iter(event_data["cells"]["table"].values())
@@ -684,9 +682,10 @@ class MainTable(tk.Canvas):
684
682
  for r1, c1, r2, c2 in boxes:
685
683
  self.show_ctrl_outline(canvas="table", start_cell=(c1, r1), end_cell=(c2, r2))
686
684
  if event_data["cells"]["table"]:
685
+ self.undo_stack.append(pickled_event_dict(event_data))
687
686
  try_binding(self.extra_end_ctrl_x_func, event_data, "end_ctrl_x")
688
- self.sheet_modified(event_data)
689
- self.PAR.emit_event("<<Cut>>", event_data)
687
+ self.sheet_modified(event_data)
688
+ self.PAR.emit_event("<<Cut>>", event_data)
690
689
  return event_data
691
690
 
692
691
  def ctrl_v(self, event: object = None, validation: bool = True) -> None | EventDataDict:
@@ -716,7 +715,7 @@ class MainTable(tk.Canvas):
716
715
  selected_c, selected_r = len(self.col_positions) - 1, 0
717
716
  elif len(self.row_positions) > 1 and len(self.col_positions) > 1:
718
717
  selected_c, selected_r = 0, len(self.row_positions) - 1
719
- curr_coords = (selected_r, selected_c)
718
+ curr_coords = (selected_r, selected_c)
720
719
  try:
721
720
  data = get_data_from_clipboard(
722
721
  widget=self,
@@ -936,8 +935,6 @@ class MainTable(tk.Canvas):
936
935
  )
937
936
  event_data["selection_boxes"] = self.get_boxes()
938
937
  event_data["selected"] = self.selected
939
- if event_data["cells"]["table"] or event_data["added"]["rows"] or event_data["added"]["columns"]:
940
- self.undo_stack.append(pickled_event_dict(event_data))
941
938
  self.see(
942
939
  r=selected_r,
943
940
  c=selected_c,
@@ -949,9 +946,10 @@ class MainTable(tk.Canvas):
949
946
  )
950
947
  self.refresh()
951
948
  if event_data["cells"]["table"] or event_data["added"]["rows"] or event_data["added"]["columns"]:
949
+ self.undo_stack.append(pickled_event_dict(event_data))
952
950
  try_binding(self.extra_end_ctrl_v_func, event_data, "end_ctrl_v")
953
- self.sheet_modified(event_data)
954
- self.PAR.emit_event("<<Paste>>", event_data)
951
+ self.sheet_modified(event_data)
952
+ self.PAR.emit_event("<<Paste>>", event_data)
955
953
  return event_data
956
954
 
957
955
  def delete_key(self, event: object = None, validation: bool = True) -> None | EventDataDict:
@@ -987,11 +985,11 @@ class MainTable(tk.Canvas):
987
985
  event_data,
988
986
  )
989
987
  if event_data["cells"]["table"]:
988
+ self.refresh()
990
989
  self.undo_stack.append(pickled_event_dict(event_data))
991
990
  try_binding(self.extra_end_delete_key_func, event_data, "end_delete")
992
- self.refresh()
993
- self.sheet_modified(event_data)
994
- self.PAR.emit_event("<<Delete>>", event_data)
991
+ self.sheet_modified(event_data)
992
+ self.PAR.emit_event("<<Delete>>", event_data)
995
993
  return event_data
996
994
 
997
995
  def event_data_set_cell(self, datarn: int, datacn: int, value: object, event_data: dict) -> EventDataDict:
@@ -1515,8 +1513,12 @@ class MainTable(tk.Canvas):
1515
1513
  self.purge_redo_stack()
1516
1514
 
1517
1515
  def edit_cells_using_modification(self, modification: dict, event_data: dict) -> EventDataDict:
1518
- for datarn, v in modification["cells"]["index"].items():
1519
- self._row_index[datarn] = v
1516
+ if self.PAR.ops.treeview:
1517
+ for datarn, v in modification["cells"]["index"].items():
1518
+ self._row_index[datarn].text = v
1519
+ else:
1520
+ for datarn, v in modification["cells"]["index"].items():
1521
+ self._row_index[datarn] = v
1520
1522
  for datacn, v in modification["cells"]["header"].items():
1521
1523
  self._headers[datacn] = v
1522
1524
  for (datarn, datacn), v in modification["cells"]["table"].items():
@@ -2312,6 +2314,102 @@ class MainTable(tk.Canvas):
2312
2314
  check_cell_visibility=False,
2313
2315
  )
2314
2316
 
2317
+ def shift_arrowkey_select_box(
2318
+ self,
2319
+ r1: int,
2320
+ c1: int,
2321
+ r2: int,
2322
+ c2: int,
2323
+ current_r: int,
2324
+ current_c: int,
2325
+ see_r: int,
2326
+ see_c: int,
2327
+ keep_xscroll: bool = False,
2328
+ keep_yscroll: bool = False,
2329
+ ) -> None:
2330
+ box_to_hide = self.selected.fill_iid
2331
+ self.set_currently_selected(
2332
+ current_r,
2333
+ current_c,
2334
+ self.create_selection_box(
2335
+ r1,
2336
+ c1,
2337
+ r2,
2338
+ c2,
2339
+ self.selected.type_,
2340
+ set_current=False,
2341
+ run_binding=True,
2342
+ ),
2343
+ run_binding=False,
2344
+ )
2345
+ self.hide_selection_box(box_to_hide)
2346
+ self.see(see_r, see_c, keep_xscroll=keep_xscroll, keep_yscroll=keep_yscroll, redraw=False)
2347
+ self.refresh()
2348
+
2349
+ def shift_arrowkey_UP(self, event: object = None) -> None:
2350
+ if not self.selected:
2351
+ return
2352
+ r1, c1, r2, c2 = self.selected.box
2353
+ current_r, current_c = self.selected.row, self.selected.column
2354
+ if not r1 and self.selected.row == r2 - 1:
2355
+ return
2356
+ if (r2 - r1 != 1 and self.selected.row != r1 and self.selected.row != r2 - 1) or (
2357
+ r2 - r1 != 1 and self.selected.row == r1
2358
+ ):
2359
+ r2 -= 1
2360
+ see_r = r2 - 1
2361
+ else:
2362
+ r1 -= 1
2363
+ see_r = r1
2364
+ self.shift_arrowkey_select_box(r1, c1, r2, c2, current_r, current_c, see_r, c1, keep_xscroll=True)
2365
+
2366
+ def shift_arrowkey_DOWN(self, event: object = None) -> None:
2367
+ if not self.selected:
2368
+ return
2369
+ r1, c1, r2, c2 = self.selected.box
2370
+ current_r, current_c = self.selected.row, self.selected.column
2371
+ if r2 == len(self.row_positions) - 1 and self.selected.row == r1:
2372
+ return
2373
+ if r2 - r1 == 1 or self.selected.row == r1:
2374
+ r2 += 1
2375
+ see_r = r2 - 1
2376
+ else:
2377
+ r1 += 1
2378
+ see_r = r1
2379
+ self.shift_arrowkey_select_box(r1, c1, r2, c2, current_r, current_c, see_r, c1, keep_xscroll=True)
2380
+
2381
+ def shift_arrowkey_LEFT(self, event: object = None) -> None:
2382
+ if not self.selected:
2383
+ return
2384
+ r1, c1, r2, c2 = self.selected.box
2385
+ current_r, current_c = self.selected.row, self.selected.column
2386
+ if not c1 and self.selected.column == c2 - 1:
2387
+ return
2388
+ if (c2 - c1 != 1 and self.selected.column != c1 and self.selected.column != c2 - 1) or (
2389
+ c2 - c1 != 1 and self.selected.column == c1
2390
+ ):
2391
+ c2 -= 1
2392
+ see_c = c2 - 1
2393
+ else:
2394
+ c1 -= 1
2395
+ see_c = c1
2396
+ self.shift_arrowkey_select_box(r1, c1, r2, c2, current_r, current_c, r1, see_c, keep_yscroll=True)
2397
+
2398
+ def shift_arrowkey_RIGHT(self, event: object = None) -> None:
2399
+ if not self.selected:
2400
+ return
2401
+ r1, c1, r2, c2 = self.selected.box
2402
+ current_r, current_c = self.selected.row, self.selected.column
2403
+ if c2 == len(self.col_positions) - 1 and self.selected.column == c1:
2404
+ return
2405
+ if c2 - c1 == 1 or self.selected.column == c1:
2406
+ c2 += 1
2407
+ see_c = c2 - 1
2408
+ else:
2409
+ c1 += 1
2410
+ see_c = c1
2411
+ self.shift_arrowkey_select_box(r1, c1, r2, c2, current_r, current_c, r1, see_c, keep_yscroll=True)
2412
+
2315
2413
  def menu_add_command(self, menu: tk.Menu, **kwargs) -> None:
2316
2414
  if "label" not in kwargs:
2317
2415
  return
@@ -2614,15 +2712,19 @@ class MainTable(tk.Canvas):
2614
2712
  if binding in ("all", "arrowkeys", "up"):
2615
2713
  self.up_enabled = True
2616
2714
  self._tksheet_bind("up_bindings", self.arrowkey_UP)
2715
+ self._tksheet_bind("shift_up_bindings", self.shift_arrowkey_UP)
2617
2716
  if binding in ("all", "arrowkeys", "right"):
2618
2717
  self.right_enabled = True
2619
2718
  self._tksheet_bind("right_bindings", self.arrowkey_RIGHT)
2719
+ self._tksheet_bind("shift_right_bindings", self.shift_arrowkey_RIGHT)
2620
2720
  if binding in ("all", "arrowkeys", "down"):
2621
2721
  self.down_enabled = True
2622
2722
  self._tksheet_bind("down_bindings", self.arrowkey_DOWN)
2723
+ self._tksheet_bind("shift_down_bindings", self.shift_arrowkey_DOWN)
2623
2724
  if binding in ("all", "arrowkeys", "left"):
2624
2725
  self.left_enabled = True
2625
2726
  self._tksheet_bind("left_bindings", self.arrowkey_LEFT)
2727
+ self._tksheet_bind("shift_left_bindings", self.shift_arrowkey_LEFT)
2626
2728
  if binding in ("all", "arrowkeys", "prior"):
2627
2729
  self.prior_enabled = True
2628
2730
  self._tksheet_bind("prior_bindings", self.page_UP)
@@ -2882,6 +2984,7 @@ class MainTable(tk.Canvas):
2882
2984
  def ctrl_b1_press(self, event=None):
2883
2985
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
2884
2986
  self.focus_set()
2987
+ self.ctrl_b1_pressed = True
2885
2988
  if self.ctrl_select_enabled and self.not_currently_resizing():
2886
2989
  self.b1_pressed_loc = None
2887
2990
  rowsel = int(self.identify_row(y=event.y))
@@ -2900,6 +3003,7 @@ class MainTable(tk.Canvas):
2900
3003
  def ctrl_shift_b1_press(self, event=None):
2901
3004
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
2902
3005
  self.focus_set()
3006
+ self.ctrl_b1_pressed = True
2903
3007
  if self.ctrl_select_enabled and self.drag_selection_enabled and self.not_currently_resizing():
2904
3008
  self.b1_pressed_loc = None
2905
3009
  rowsel = int(self.identify_row(y=event.y))
@@ -3130,6 +3234,7 @@ class MainTable(tk.Canvas):
3130
3234
  self.open_cell(event)
3131
3235
  else:
3132
3236
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
3237
+ self.ctrl_b1_pressed = False
3133
3238
  self.b1_pressed_loc = None
3134
3239
  self.closed_dropdown = None
3135
3240
  try_binding(self.extra_b1_release_func, event)
@@ -6090,8 +6195,8 @@ class MainTable(tk.Canvas):
6090
6195
  bd_iid = None
6091
6196
  if self.PAR.ops.show_selected_cells_border and (
6092
6197
  ext
6198
+ or self.ctrl_b1_pressed
6093
6199
  or (self.being_drawn_item is None and self.RI.being_drawn_item is None and self.CH.being_drawn_item is None)
6094
- or self.selection_boxes
6095
6200
  ):
6096
6201
  bd_iid = self.display_box(
6097
6202
  x1,
tksheet/other_classes.py CHANGED
@@ -38,6 +38,47 @@ TextCfg = namedtuple("TextCfg", "txt tf font align")
38
38
  DraggedRowColumn = namedtuple("DraggedRowColumn", "dragged to_move")
39
39
 
40
40
 
41
+ class SelectionBox:
42
+ __slots__ = ("fill_iid", "bd_iid", "index", "header", "coords", "type_")
43
+
44
+ def __init__(
45
+ self,
46
+ fill_iid: int | None = None,
47
+ bd_iid: int | None = None,
48
+ index: int | None = None,
49
+ header: int | None = None,
50
+ coords: tuple[int, int, int, int] = None,
51
+ type_: Literal["cells", "rows", "columns"] = "cells",
52
+ ) -> None:
53
+ self.fill_iid = fill_iid
54
+ self.bd_iid = bd_iid
55
+ self.index = index
56
+ self.header = header
57
+ self.coords = coords
58
+ self.type_ = type_
59
+
60
+
61
+ Selected = namedtuple(
62
+ "Selected",
63
+ (
64
+ "row",
65
+ "column",
66
+ "type_",
67
+ "box",
68
+ "iid",
69
+ "fill_iid",
70
+ ),
71
+ defaults=(
72
+ None,
73
+ None,
74
+ None,
75
+ None,
76
+ None,
77
+ None,
78
+ ),
79
+ )
80
+
81
+
41
82
  def num2alpha(n: int) -> str | None:
42
83
  try:
43
84
  s = ""
@@ -468,47 +509,6 @@ class TextEditorStorage:
468
509
  return self.window.c
469
510
 
470
511
 
471
- class SelectionBox:
472
- __slots__ = ("fill_iid", "bd_iid", "index", "header", "coords", "type_")
473
-
474
- def __init__(
475
- self,
476
- fill_iid: int | None = None,
477
- bd_iid: int | None = None,
478
- index: int | None = None,
479
- header: int | None = None,
480
- coords: tuple[int, int, int, int] = None,
481
- type_: Literal["cells", "rows", "columns"] = "cells",
482
- ) -> None:
483
- self.fill_iid = fill_iid
484
- self.bd_iid = bd_iid
485
- self.index = index
486
- self.header = header
487
- self.coords = coords
488
- self.type_ = type_
489
-
490
-
491
- Selected = namedtuple(
492
- "Selected",
493
- (
494
- "row",
495
- "column",
496
- "type_",
497
- "box",
498
- "iid",
499
- "fill_iid",
500
- ),
501
- defaults=(
502
- None,
503
- None,
504
- None,
505
- None,
506
- None,
507
- None,
508
- ),
509
- )
510
-
511
-
512
512
  class ProgressBar:
513
513
  __slots__ = ("bg", "fg", "name", "percent", "del_when_done")
514
514
 
tksheet/row_index.py CHANGED
@@ -66,8 +66,7 @@ from .vars import (
66
66
 
67
67
  class RowIndex(tk.Canvas):
68
68
  def __init__(self, *args, **kwargs):
69
- tk.Canvas.__init__(
70
- self,
69
+ super().__init__(
71
70
  kwargs["parent"],
72
71
  background=kwargs["parent"].ops.index_bg,
73
72
  highlightthickness=0,
@@ -276,8 +275,7 @@ class RowIndex(tk.Canvas):
276
275
 
277
276
  def shift_b1_press(self, event: object) -> None:
278
277
  self.mouseclick_outside_editor_or_dropdown_all_canvases(inside=True)
279
- y = event.y
280
- r = self.MT.identify_row(y=y)
278
+ r = self.MT.identify_row(y=event.y)
281
279
  if (self.drag_and_drop_enabled or self.row_selection_enabled) and self.rsz_h is None and self.rsz_w is None:
282
280
  if r < len(self.MT.row_positions) - 1:
283
281
  r_selected = self.MT.row_selected(r)
@@ -302,7 +300,7 @@ class RowIndex(tk.Canvas):
302
300
  )
303
301
 
304
302
  def get_shift_select_box(self, r: int, min_r: int) -> tuple[int, int, int, int, str]:
305
- if r > min_r:
303
+ if r >= min_r:
306
304
  return min_r, 0, r + 1, len(self.MT.col_positions) - 1
307
305
  elif r < min_r:
308
306
  return r, 0, min_r + 1, len(self.MT.col_positions) - 1
@@ -2364,6 +2362,8 @@ class RowIndex(tk.Canvas):
2364
2362
  self.fix_index(datarn)
2365
2363
  if self.get_cell_kwargs(datarn, key="checkbox"):
2366
2364
  self.MT._row_index[datarn] = try_to_bool(value)
2365
+ elif self.PAR.ops.treeview:
2366
+ self.MT._row_index[datarn].text = value
2367
2367
  else:
2368
2368
  self.MT._row_index[datarn] = value
2369
2369
 
@@ -2404,6 +2404,8 @@ class RowIndex(tk.Canvas):
2404
2404
  or (self.MT._row_index[datarn] is None and none_to_empty_str)
2405
2405
  ):
2406
2406
  return ""
2407
+ if self.PAR.ops.treeview:
2408
+ return self.MT._row_index[datarn].text
2407
2409
  return self.MT._row_index[datarn]
2408
2410
 
2409
2411
  def get_valid_cell_data_as_str(self, datarn: int, fix: bool = True) -> str:
tksheet/sheet.py CHANGED
@@ -28,6 +28,7 @@ from .column_headers import ColumnHeaders
28
28
  from .functions import (
29
29
  add_highlight,
30
30
  add_to_options,
31
+ alpha2idx,
31
32
  consecutive_ranges,
32
33
  convert_align,
33
34
  data_to_displayed_idxs,
@@ -288,8 +289,7 @@ class Sheet(tk.Frame):
288
289
  row_index_width: int | None = None,
289
290
  expand_sheet_if_paste_too_big: bool | None = None,
290
291
  ) -> None:
291
- tk.Frame.__init__(
292
- self,
292
+ super().__init__(
293
293
  parent,
294
294
  background=frame_bg,
295
295
  highlightthickness=outline_thickness,
@@ -2907,10 +2907,16 @@ class Sheet(tk.Frame):
2907
2907
  set_readonly(self.MT.cell_options, (r, c), readonly)
2908
2908
  elif span.kind == "row":
2909
2909
  for r in rows:
2910
- set_readonly(self.MT.row_options, r, readonly)
2910
+ if index:
2911
+ set_readonly(self.RI.cell_options, r, readonly)
2912
+ if table:
2913
+ set_readonly(self.MT.row_options, r, readonly)
2911
2914
  elif span.kind == "column":
2912
2915
  for c in cols:
2913
- set_readonly(self.MT.col_options, c, readonly)
2916
+ if header:
2917
+ set_readonly(self.CH.cell_options, c, readonly)
2918
+ if table:
2919
+ set_readonly(self.MT.col_options, c, readonly)
2914
2920
  return span
2915
2921
 
2916
2922
  # Text Font and Alignment
@@ -4152,6 +4158,7 @@ class Sheet(tk.Frame):
4152
4158
  canvas: Literal[
4153
4159
  "all",
4154
4160
  "row_index",
4161
+ "index",
4155
4162
  "header",
4156
4163
  "top_left",
4157
4164
  "x_scrollbar",
@@ -4174,7 +4181,7 @@ class Sheet(tk.Frame):
4174
4181
  self.yscroll_showing = True
4175
4182
  self.xscroll_disabled = False
4176
4183
  self.yscroll_disabled = False
4177
- elif canvas == "row_index":
4184
+ elif canvas in ("row_index", "index"):
4178
4185
  self.RI.grid(row=1, column=0, sticky="nswe")
4179
4186
  self.MT["yscrollcommand"] = self.yscroll.set
4180
4187
  self.RI["yscrollcommand"] = self.yscroll.set
@@ -4423,14 +4430,107 @@ class Sheet(tk.Frame):
4423
4430
  and event.widget == self.TL
4424
4431
  )
4425
4432
 
4433
+ def props(
4434
+ self,
4435
+ row: int,
4436
+ column: int | str,
4437
+ key: None
4438
+ | Literal[
4439
+ "format",
4440
+ "highlight",
4441
+ "dropdown",
4442
+ "checkbox",
4443
+ "readonly",
4444
+ "align",
4445
+ ] = None,
4446
+ cellops: bool = True,
4447
+ rowops: bool = True,
4448
+ columnops: bool = True,
4449
+ ) -> dict:
4450
+ """
4451
+ Retrieve options (properties - props)
4452
+ from a single cell in the main table
4453
+
4454
+ Also retrieves any row or column options
4455
+ impacting that cell
4456
+ """
4457
+ if isinstance(column, str):
4458
+ column = alpha2idx(column)
4459
+ if key is not None:
4460
+ return self.MT.get_cell_kwargs(
4461
+ datarn=row,
4462
+ datacn=column,
4463
+ key=key,
4464
+ cell=cellops,
4465
+ row=rowops,
4466
+ column=columnops,
4467
+ )
4468
+ if cellops and (row, column) in self.MT.cell_options:
4469
+ return self.MT.cell_options[(row, column)]
4470
+ if rowops and row in self.MT.row_options:
4471
+ return self.MT.row_options[row]
4472
+ if columnops and column in self.MT.col_options:
4473
+ return self.MT.col_options[column]
4474
+ return {}
4475
+
4476
+ def index_props(
4477
+ self,
4478
+ row: int,
4479
+ key: None
4480
+ | Literal[
4481
+ "format",
4482
+ "highlight",
4483
+ "dropdown",
4484
+ "checkbox",
4485
+ "readonly",
4486
+ "align",
4487
+ ] = None,
4488
+ ) -> dict:
4489
+ """
4490
+ Retrieve options (properties - props)
4491
+ from a cell in the index
4492
+ """
4493
+ if key is not None:
4494
+ return self.RI.get_cell_kwargs(
4495
+ datarn=row,
4496
+ key=key,
4497
+ )
4498
+ return self.RI.cell_options[row] if row in self.RI.cell_options else {}
4499
+
4500
+ def header_props(
4501
+ self,
4502
+ column: int | str,
4503
+ key: None
4504
+ | Literal[
4505
+ "format",
4506
+ "highlight",
4507
+ "dropdown",
4508
+ "checkbox",
4509
+ "readonly",
4510
+ "align",
4511
+ ] = None,
4512
+ ) -> dict:
4513
+ """
4514
+ Retrieve options (properties - props)
4515
+ from a cell in the header
4516
+ """
4517
+ if isinstance(column, str):
4518
+ column = alpha2idx(column)
4519
+ if key is not None:
4520
+ return self.CH.get_cell_kwargs(
4521
+ datacn=column,
4522
+ key=key,
4523
+ )
4524
+ return self.CH.cell_options[column] if column in self.CH.cell_options else {}
4525
+
4426
4526
  def get_cell_options(
4427
4527
  self,
4428
4528
  key: None | str = None,
4429
- canvas: Literal["table", "row_index", "header"] = "table",
4529
+ canvas: Literal["table", "row_index", "index", "header"] = "table",
4430
4530
  ) -> dict:
4431
4531
  if canvas == "table":
4432
4532
  target = self.MT.cell_options
4433
- elif canvas == "row_index":
4533
+ elif canvas in ("row_index", "index"):
4434
4534
  target = self.RI.cell_options
4435
4535
  elif canvas == "header":
4436
4536
  target = self.CH.cell_options
@@ -6024,7 +6124,7 @@ class Sheet(tk.Frame):
6024
6124
  row: int | Literal["all"] = 0,
6025
6125
  column: int = 0,
6026
6126
  cells: list[tuple[int, int]] = [],
6027
- canvas: Literal["table", "row_index", "header"] = "table",
6127
+ canvas: Literal["table", "row_index", "index", "header"] = "table",
6028
6128
  all_: bool = False,
6029
6129
  redraw: bool = True,
6030
6130
  ) -> Sheet:
@@ -6057,7 +6157,7 @@ class Sheet(tk.Frame):
6057
6157
  for k in self.MT.cell_options:
6058
6158
  if "highlight" in self.MT.cell_options[k]:
6059
6159
  del self.MT.cell_options[k]["highlight"]
6060
- elif canvas == "row_index":
6160
+ elif canvas in ("row_index", "index"):
6061
6161
  if cells and not all_:
6062
6162
  for r in cells:
6063
6163
  try:
@@ -6087,10 +6187,13 @@ class Sheet(tk.Frame):
6087
6187
  del self.CH.cell_options[c]["highlight"]
6088
6188
  return self.set_refresh_timer(redraw)
6089
6189
 
6090
- def get_highlighted_cells(self, canvas: str = "table") -> dict | None:
6190
+ def get_highlighted_cells(
6191
+ self,
6192
+ canvas: Literal["table", "row_index", "index", "header"] = "table",
6193
+ ) -> dict | None:
6091
6194
  if canvas == "table":
6092
6195
  return {k: v["highlight"] for k, v in self.MT.cell_options.items() if "highlight" in v}
6093
- elif canvas == "row_index":
6196
+ elif canvas in ("row_index", "index"):
6094
6197
  return {k: v["highlight"] for k, v in self.RI.cell_options.items() if "highlight" in v}
6095
6198
  elif canvas == "header":
6096
6199
  return {k: v["highlight"] for k, v in self.CH.cell_options.items() if "highlight" in v}
tksheet/sheet_options.py CHANGED
@@ -118,6 +118,18 @@ def new_sheet_options() -> DotDict:
118
118
  "left_bindings": [
119
119
  "<Left>",
120
120
  ],
121
+ "shift_up_bindings": [
122
+ "<Shift-Up>",
123
+ ],
124
+ "shift_right_bindings": [
125
+ "<Shift-Right>",
126
+ ],
127
+ "shift_down_bindings": [
128
+ "<Shift-Down>",
129
+ ],
130
+ "shift_left_bindings": [
131
+ "<Shift-Left>",
132
+ ],
121
133
  "prior_bindings": [
122
134
  "<Prior>",
123
135
  ],
tksheet/text_editor.py CHANGED
@@ -22,8 +22,7 @@ class TextEditorTkText(tk.Text):
22
22
  parent: tk.Misc,
23
23
  newline_binding: None | Callable = None,
24
24
  ) -> None:
25
- tk.Text.__init__(
26
- self,
25
+ super().__init__(
27
26
  parent,
28
27
  spacing1=0,
29
28
  spacing2=1,
@@ -170,8 +169,7 @@ class TextEditor(tk.Frame):
170
169
  parent: tk.Misc,
171
170
  newline_binding: None | Callable = None,
172
171
  ) -> None:
173
- tk.Frame.__init__(
174
- self,
172
+ super().__init__(
175
173
  parent,
176
174
  width=0,
177
175
  height=0,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tksheet
3
- Version: 7.2.18
3
+ Version: 7.2.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
@@ -0,0 +1,20 @@
1
+ tksheet/__init__.py,sha256=LFB6RLXByzaiFRyaeQYjbIcN5EE9e-vzpjzqMGJi6FA,2237
2
+ tksheet/colors.py,sha256=1k06VorynLmnC4FdJg8H4reIA6rXaeXBpdMwXLhN8oc,51594
3
+ tksheet/column_headers.py,sha256=LtWvogLqd76JpkG_Vp2XQKoyxqkDjfcx2w-hzVVWPi8,102187
4
+ tksheet/formatters.py,sha256=_exO2KnjtcnE_MVWLG1ngOZ-wmrXZhuh7uEi2iPs1Tk,10546
5
+ tksheet/functions.py,sha256=P7nyiL5Q4nGmWo6CgPz0g2Vn56QclmOkniPDRFUNfTI,42768
6
+ tksheet/main_table.py,sha256=x-3gKhAB-aZXSSmlu5cy2_FiUkNAQcWB40s3-41xRiU,332289
7
+ tksheet/other_classes.py,sha256=eB-kDTJjYOe5QcSA25Bg9JS2JimZau2fAvyz8rcBT0Q,15631
8
+ tksheet/row_index.py,sha256=5biQK0Rv3tq5nI98htOeiyEXYpuhiz_gQIWTYfrAJkM,111174
9
+ tksheet/sheet.py,sha256=Wd2PjnMh-NQl-8hkEbwLLrmHhLdz1lSJAznyyXRECiM,283226
10
+ tksheet/sheet_options.py,sha256=XM3XSWWVnAOctP2z2_WkkXonoIT8_brXwJaSO0sFZbE,12788
11
+ tksheet/text_editor.py,sha256=pf9o3JuRI6cbr7ZoVfaookCBJsmRBgGDubdtShLZXBA,7064
12
+ tksheet/themes.py,sha256=OhUzZL4JH0YPhb2f1F62CcJFzhVsEvNxF-ObC9zVb44,14474
13
+ tksheet/top_left_rectangle.py,sha256=ri7hb9CC5l37ynmxceprq11UuWWRpWEI_0AI42wzv0A,8444
14
+ tksheet/types.py,sha256=IgoEHMbceKpakcZtanxKaKJ4RdCq7UW6EoEIIz5O59k,340
15
+ tksheet/vars.py,sha256=86ubZZElsnQuC6Lv6bW2lt2NhD9wAp6PxtkK7ufKqq0,3452
16
+ tksheet-7.2.20.dist-info/LICENSE.txt,sha256=ndbcCPe9SlHfweE_W2RAueWUe2k7yudyxYLq6WjFdn4,1101
17
+ tksheet-7.2.20.dist-info/METADATA,sha256=YGaZ0fM_GcLhPCZ_KWkL8JNGdEwYWcGx74ar1MUbJZI,6476
18
+ tksheet-7.2.20.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
19
+ tksheet-7.2.20.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
20
+ tksheet-7.2.20.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.3.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,20 +0,0 @@
1
- tksheet/__init__.py,sha256=is58VlhUF5KQscGCYwk0pTBy6HY87VZ3y2NNFmaCbWs,2165
2
- tksheet/colors.py,sha256=1k06VorynLmnC4FdJg8H4reIA6rXaeXBpdMwXLhN8oc,51594
3
- tksheet/column_headers.py,sha256=bHv67vRhRYxw_qyrw5akJo-b77vtN4y-mEO617FEqxE,102222
4
- tksheet/formatters.py,sha256=DXif00aq9DgFpXwkbiqD86KxtDg0Meop51hLY-KcGNQ,10037
5
- tksheet/functions.py,sha256=FpykRY-rmGmiKY2fSX_b89RSjXQN229uKe5wYoZN2K0,42897
6
- tksheet/main_table.py,sha256=Al8dgIfL3WEvF-QN170uQeRJAfmUmYx4uqr1o0L1q50,328303
7
- tksheet/other_classes.py,sha256=fPZYOyu8uly3AFBry9lljp0G-EkBhwPaq2nKGcfWh7I,15631
8
- tksheet/row_index.py,sha256=hBehEVSG1j6zgo2HkCxyUtPIr9efUTPEnH1QSWu1h80,111024
9
- tksheet/sheet.py,sha256=_SvXmHWjibkZ4vxJXeLL01B2AMnat3V7MX642aK37Y8,280222
10
- tksheet/sheet_options.py,sha256=hA4Gi2spLmltq3HrgfzetUaqvT_FaVI8PrSQkgdoyEE,12442
11
- tksheet/text_editor.py,sha256=lmmHOPb11S8tlNtC10vijF1QqVB5Ts2hUKnGJd_JkWA,7103
12
- tksheet/themes.py,sha256=OhUzZL4JH0YPhb2f1F62CcJFzhVsEvNxF-ObC9zVb44,14474
13
- tksheet/top_left_rectangle.py,sha256=ri7hb9CC5l37ynmxceprq11UuWWRpWEI_0AI42wzv0A,8444
14
- tksheet/types.py,sha256=IgoEHMbceKpakcZtanxKaKJ4RdCq7UW6EoEIIz5O59k,340
15
- tksheet/vars.py,sha256=86ubZZElsnQuC6Lv6bW2lt2NhD9wAp6PxtkK7ufKqq0,3452
16
- tksheet-7.2.18.dist-info/LICENSE.txt,sha256=ndbcCPe9SlHfweE_W2RAueWUe2k7yudyxYLq6WjFdn4,1101
17
- tksheet-7.2.18.dist-info/METADATA,sha256=FjaCGtvPZBCmm8hH3EzNTJEC3hchE8xvqTsbX-m0CWE,6476
18
- tksheet-7.2.18.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
19
- tksheet-7.2.18.dist-info/top_level.txt,sha256=my61PXCcck_HHAc9cq3NAlyAr3A3FXxCy9gptEOaCN8,8
20
- tksheet-7.2.18.dist-info/RECORD,,