tksheet 7.2.18__tar.gz → 7.2.19__tar.gz

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.
Files changed (24) hide show
  1. {tksheet-7.2.18/tksheet.egg-info → tksheet-7.2.19}/PKG-INFO +1 -1
  2. {tksheet-7.2.18 → tksheet-7.2.19}/pyproject.toml +1 -1
  3. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/__init__.py +1 -1
  4. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/column_headers.py +2 -3
  5. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/formatters.py +4 -3
  6. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/functions.py +8 -11
  7. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/main_table.py +112 -4
  8. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/other_classes.py +41 -41
  9. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/row_index.py +6 -3
  10. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/sheet.py +113 -9
  11. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/sheet_options.py +12 -0
  12. {tksheet-7.2.18 → tksheet-7.2.19/tksheet.egg-info}/PKG-INFO +1 -1
  13. {tksheet-7.2.18 → tksheet-7.2.19}/LICENSE.txt +0 -0
  14. {tksheet-7.2.18 → tksheet-7.2.19}/README.md +0 -0
  15. {tksheet-7.2.18 → tksheet-7.2.19}/setup.cfg +0 -0
  16. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/colors.py +0 -0
  17. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/text_editor.py +0 -0
  18. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/themes.py +0 -0
  19. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/top_left_rectangle.py +0 -0
  20. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/types.py +0 -0
  21. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet/vars.py +0 -0
  22. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet.egg-info/SOURCES.txt +0 -0
  23. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet.egg-info/dependency_links.txt +0 -0
  24. {tksheet-7.2.18 → tksheet-7.2.19}/tksheet.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tksheet
3
- Version: 7.2.18
3
+ Version: 7.2.19
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
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
  name = "tksheet"
7
7
  description = "Tkinter table / sheet widget"
8
8
  readme = "README.md"
9
- version = "7.2.18"
9
+ version = "7.2.19"
10
10
  authors = [{ name = "ragardner", email = "github@ragardner.simplelogin.com" }]
11
11
  requires-python = ">=3.8"
12
12
  license = {file = "LICENSE.txt"}
@@ -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.19"
8
8
 
9
9
  from .colors import (
10
10
  color_map,
@@ -290,8 +290,7 @@ class ColumnHeaders(tk.Canvas):
290
290
 
291
291
  def shift_b1_press(self, event: object) -> None:
292
292
  self.mouseclick_outside_editor_or_dropdown_all_canvases(inside=True)
293
- x = event.x
294
- c = self.MT.identify_col(x=x)
293
+ c = self.MT.identify_col(x=event.x)
295
294
  if (self.drag_and_drop_enabled or self.col_selection_enabled) and self.rsz_h is None and self.rsz_w is None:
296
295
  if c < len(self.MT.col_positions) - 1:
297
296
  c_selected = self.MT.col_selected(c)
@@ -316,7 +315,7 @@ class ColumnHeaders(tk.Canvas):
316
315
  )
317
316
 
318
317
  def get_shift_select_box(self, c: int, min_c: int) -> tuple[int, int, int, int, str]:
319
- if c > min_c:
318
+ if c >= min_c:
320
319
  return 0, min_c, len(self.MT.row_positions) - 1, c + 1
321
320
  elif c < min_c:
322
321
  return 0, c, len(self.MT.row_positions) - 1, min_c + 1
@@ -66,7 +66,7 @@ def to_str(o: object, **kwargs: dict) -> str:
66
66
  return f"{o}"
67
67
 
68
68
 
69
- def float_to_str(v: int | float, **kwargs: dict) -> str:
69
+ def float_to_str(v: object, **kwargs: dict) -> str:
70
70
  if isinstance(v, float):
71
71
  if v.is_integer():
72
72
  return f"{int(v)}"
@@ -77,7 +77,7 @@ def float_to_str(v: int | float, **kwargs: dict) -> str:
77
77
  return f"{v}"
78
78
 
79
79
 
80
- def percentage_to_str(v: int | float, **kwargs: dict) -> str:
80
+ def percentage_to_str(v: object, **kwargs: dict) -> str:
81
81
  if isinstance(v, (int, float)):
82
82
  x = v * 100
83
83
  if isinstance(x, float):
@@ -87,7 +87,8 @@ def percentage_to_str(v: int | float, **kwargs: dict) -> str:
87
87
  if kwargs["decimals"]:
88
88
  return f"{round(x, kwargs['decimals'])}%"
89
89
  return f"{int(round(x, kwargs['decimals']))}%"
90
- return f"{x}%"
90
+ return f"{x}%"
91
+ return f"{v}%"
91
92
 
92
93
 
93
94
  def bool_to_str(v: object, **kwargs: dict) -> str:
@@ -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]:
@@ -126,6 +126,7 @@ class MainTable(tk.Canvas):
126
126
  self.PAR_height = 0
127
127
  self.scrollregion = tuple()
128
128
  self.current_cursor = ""
129
+ self.ctrl_b1_pressed = False
129
130
  self.b1_pressed_loc = None
130
131
  self.closed_dropdown = None
131
132
  self.centre_alignment_text_mod_indexes = (slice(1, None), slice(None, -1))
@@ -716,7 +717,7 @@ class MainTable(tk.Canvas):
716
717
  selected_c, selected_r = len(self.col_positions) - 1, 0
717
718
  elif len(self.row_positions) > 1 and len(self.col_positions) > 1:
718
719
  selected_c, selected_r = 0, len(self.row_positions) - 1
719
- curr_coords = (selected_r, selected_c)
720
+ curr_coords = (selected_r, selected_c)
720
721
  try:
721
722
  data = get_data_from_clipboard(
722
723
  widget=self,
@@ -1515,8 +1516,12 @@ class MainTable(tk.Canvas):
1515
1516
  self.purge_redo_stack()
1516
1517
 
1517
1518
  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
1519
+ if self.PAR.ops.treeview:
1520
+ for datarn, v in modification["cells"]["index"].items():
1521
+ self._row_index[datarn].text = v
1522
+ else:
1523
+ for datarn, v in modification["cells"]["index"].items():
1524
+ self._row_index[datarn] = v
1520
1525
  for datacn, v in modification["cells"]["header"].items():
1521
1526
  self._headers[datacn] = v
1522
1527
  for (datarn, datacn), v in modification["cells"]["table"].items():
@@ -2312,6 +2317,102 @@ class MainTable(tk.Canvas):
2312
2317
  check_cell_visibility=False,
2313
2318
  )
2314
2319
 
2320
+ def shift_arrowkey_select_box(
2321
+ self,
2322
+ r1: int,
2323
+ c1: int,
2324
+ r2: int,
2325
+ c2: int,
2326
+ current_r: int,
2327
+ current_c: int,
2328
+ see_r: int,
2329
+ see_c: int,
2330
+ keep_xscroll: bool = False,
2331
+ keep_yscroll: bool = False,
2332
+ ) -> None:
2333
+ box_to_hide = self.selected.fill_iid
2334
+ self.set_currently_selected(
2335
+ current_r,
2336
+ current_c,
2337
+ self.create_selection_box(
2338
+ r1,
2339
+ c1,
2340
+ r2,
2341
+ c2,
2342
+ self.selected.type_,
2343
+ set_current=False,
2344
+ run_binding=True,
2345
+ ),
2346
+ run_binding=False,
2347
+ )
2348
+ self.hide_selection_box(box_to_hide)
2349
+ self.see(see_r, see_c, keep_xscroll=keep_xscroll, keep_yscroll=keep_yscroll, redraw=False)
2350
+ self.refresh()
2351
+
2352
+ def shift_arrowkey_UP(self, event: object = None) -> None:
2353
+ if not self.selected:
2354
+ return
2355
+ r1, c1, r2, c2 = self.selected.box
2356
+ current_r, current_c = self.selected.row, self.selected.column
2357
+ if not r1 and self.selected.row == r2 - 1:
2358
+ return
2359
+ if (r2 - r1 != 1 and self.selected.row != r1 and self.selected.row != r2 - 1) or (
2360
+ r2 - r1 != 1 and self.selected.row == r1
2361
+ ):
2362
+ r2 -= 1
2363
+ see_r = r2 - 1
2364
+ else:
2365
+ r1 -= 1
2366
+ see_r = r1
2367
+ self.shift_arrowkey_select_box(r1, c1, r2, c2, current_r, current_c, see_r, c1, keep_xscroll=True)
2368
+
2369
+ def shift_arrowkey_DOWN(self, event: object = None) -> None:
2370
+ if not self.selected:
2371
+ return
2372
+ r1, c1, r2, c2 = self.selected.box
2373
+ current_r, current_c = self.selected.row, self.selected.column
2374
+ if r2 == len(self.row_positions) - 1 and self.selected.row == r1:
2375
+ return
2376
+ if r2 - r1 == 1 or self.selected.row == r1:
2377
+ r2 += 1
2378
+ see_r = r2 - 1
2379
+ else:
2380
+ r1 += 1
2381
+ see_r = r1
2382
+ self.shift_arrowkey_select_box(r1, c1, r2, c2, current_r, current_c, see_r, c1, keep_xscroll=True)
2383
+
2384
+ def shift_arrowkey_LEFT(self, event: object = None) -> None:
2385
+ if not self.selected:
2386
+ return
2387
+ r1, c1, r2, c2 = self.selected.box
2388
+ current_r, current_c = self.selected.row, self.selected.column
2389
+ if not c1 and self.selected.column == c2 - 1:
2390
+ return
2391
+ if (c2 - c1 != 1 and self.selected.column != c1 and self.selected.column != c2 - 1) or (
2392
+ c2 - c1 != 1 and self.selected.column == c1
2393
+ ):
2394
+ c2 -= 1
2395
+ see_c = c2 - 1
2396
+ else:
2397
+ c1 -= 1
2398
+ see_c = c1
2399
+ self.shift_arrowkey_select_box(r1, c1, r2, c2, current_r, current_c, r1, see_c, keep_yscroll=True)
2400
+
2401
+ def shift_arrowkey_RIGHT(self, event: object = None) -> None:
2402
+ if not self.selected:
2403
+ return
2404
+ r1, c1, r2, c2 = self.selected.box
2405
+ current_r, current_c = self.selected.row, self.selected.column
2406
+ if c2 == len(self.col_positions) - 1 and self.selected.column == c1:
2407
+ return
2408
+ if c2 - c1 == 1 or self.selected.column == c1:
2409
+ c2 += 1
2410
+ see_c = c2 - 1
2411
+ else:
2412
+ c1 += 1
2413
+ see_c = c1
2414
+ self.shift_arrowkey_select_box(r1, c1, r2, c2, current_r, current_c, r1, see_c, keep_yscroll=True)
2415
+
2315
2416
  def menu_add_command(self, menu: tk.Menu, **kwargs) -> None:
2316
2417
  if "label" not in kwargs:
2317
2418
  return
@@ -2614,15 +2715,19 @@ class MainTable(tk.Canvas):
2614
2715
  if binding in ("all", "arrowkeys", "up"):
2615
2716
  self.up_enabled = True
2616
2717
  self._tksheet_bind("up_bindings", self.arrowkey_UP)
2718
+ self._tksheet_bind("shift_up_bindings", self.shift_arrowkey_UP)
2617
2719
  if binding in ("all", "arrowkeys", "right"):
2618
2720
  self.right_enabled = True
2619
2721
  self._tksheet_bind("right_bindings", self.arrowkey_RIGHT)
2722
+ self._tksheet_bind("shift_right_bindings", self.shift_arrowkey_RIGHT)
2620
2723
  if binding in ("all", "arrowkeys", "down"):
2621
2724
  self.down_enabled = True
2622
2725
  self._tksheet_bind("down_bindings", self.arrowkey_DOWN)
2726
+ self._tksheet_bind("shift_down_bindings", self.shift_arrowkey_DOWN)
2623
2727
  if binding in ("all", "arrowkeys", "left"):
2624
2728
  self.left_enabled = True
2625
2729
  self._tksheet_bind("left_bindings", self.arrowkey_LEFT)
2730
+ self._tksheet_bind("shift_left_bindings", self.shift_arrowkey_LEFT)
2626
2731
  if binding in ("all", "arrowkeys", "prior"):
2627
2732
  self.prior_enabled = True
2628
2733
  self._tksheet_bind("prior_bindings", self.page_UP)
@@ -2882,6 +2987,7 @@ class MainTable(tk.Canvas):
2882
2987
  def ctrl_b1_press(self, event=None):
2883
2988
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
2884
2989
  self.focus_set()
2990
+ self.ctrl_b1_pressed = True
2885
2991
  if self.ctrl_select_enabled and self.not_currently_resizing():
2886
2992
  self.b1_pressed_loc = None
2887
2993
  rowsel = int(self.identify_row(y=event.y))
@@ -2900,6 +3006,7 @@ class MainTable(tk.Canvas):
2900
3006
  def ctrl_shift_b1_press(self, event=None):
2901
3007
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
2902
3008
  self.focus_set()
3009
+ self.ctrl_b1_pressed = True
2903
3010
  if self.ctrl_select_enabled and self.drag_selection_enabled and self.not_currently_resizing():
2904
3011
  self.b1_pressed_loc = None
2905
3012
  rowsel = int(self.identify_row(y=event.y))
@@ -3130,6 +3237,7 @@ class MainTable(tk.Canvas):
3130
3237
  self.open_cell(event)
3131
3238
  else:
3132
3239
  self.mouseclick_outside_editor_or_dropdown_all_canvases()
3240
+ self.ctrl_b1_pressed = False
3133
3241
  self.b1_pressed_loc = None
3134
3242
  self.closed_dropdown = None
3135
3243
  try_binding(self.extra_b1_release_func, event)
@@ -6090,8 +6198,8 @@ class MainTable(tk.Canvas):
6090
6198
  bd_iid = None
6091
6199
  if self.PAR.ops.show_selected_cells_border and (
6092
6200
  ext
6201
+ or self.ctrl_b1_pressed
6093
6202
  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
6203
  ):
6096
6204
  bd_iid = self.display_box(
6097
6205
  x1,
@@ -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
 
@@ -276,8 +276,7 @@ class RowIndex(tk.Canvas):
276
276
 
277
277
  def shift_b1_press(self, event: object) -> None:
278
278
  self.mouseclick_outside_editor_or_dropdown_all_canvases(inside=True)
279
- y = event.y
280
- r = self.MT.identify_row(y=y)
279
+ r = self.MT.identify_row(y=event.y)
281
280
  if (self.drag_and_drop_enabled or self.row_selection_enabled) and self.rsz_h is None and self.rsz_w is None:
282
281
  if r < len(self.MT.row_positions) - 1:
283
282
  r_selected = self.MT.row_selected(r)
@@ -302,7 +301,7 @@ class RowIndex(tk.Canvas):
302
301
  )
303
302
 
304
303
  def get_shift_select_box(self, r: int, min_r: int) -> tuple[int, int, int, int, str]:
305
- if r > min_r:
304
+ if r >= min_r:
306
305
  return min_r, 0, r + 1, len(self.MT.col_positions) - 1
307
306
  elif r < min_r:
308
307
  return r, 0, min_r + 1, len(self.MT.col_positions) - 1
@@ -2364,6 +2363,8 @@ class RowIndex(tk.Canvas):
2364
2363
  self.fix_index(datarn)
2365
2364
  if self.get_cell_kwargs(datarn, key="checkbox"):
2366
2365
  self.MT._row_index[datarn] = try_to_bool(value)
2366
+ elif self.PAR.ops.treeview:
2367
+ self.MT._row_index[datarn].text = value
2367
2368
  else:
2368
2369
  self.MT._row_index[datarn] = value
2369
2370
 
@@ -2404,6 +2405,8 @@ class RowIndex(tk.Canvas):
2404
2405
  or (self.MT._row_index[datarn] is None and none_to_empty_str)
2405
2406
  ):
2406
2407
  return ""
2408
+ if self.PAR.ops.treeview:
2409
+ return self.MT._row_index[datarn].text
2407
2410
  return self.MT._row_index[datarn]
2408
2411
 
2409
2412
  def get_valid_cell_data_as_str(self, datarn: int, fix: bool = True) -> str:
@@ -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,
@@ -2907,10 +2908,16 @@ class Sheet(tk.Frame):
2907
2908
  set_readonly(self.MT.cell_options, (r, c), readonly)
2908
2909
  elif span.kind == "row":
2909
2910
  for r in rows:
2910
- set_readonly(self.MT.row_options, r, readonly)
2911
+ if index:
2912
+ set_readonly(self.RI.cell_options, r, readonly)
2913
+ if table:
2914
+ set_readonly(self.MT.row_options, r, readonly)
2911
2915
  elif span.kind == "column":
2912
2916
  for c in cols:
2913
- set_readonly(self.MT.col_options, c, readonly)
2917
+ if header:
2918
+ set_readonly(self.CH.cell_options, c, readonly)
2919
+ if table:
2920
+ set_readonly(self.MT.col_options, c, readonly)
2914
2921
  return span
2915
2922
 
2916
2923
  # Text Font and Alignment
@@ -4152,6 +4159,7 @@ class Sheet(tk.Frame):
4152
4159
  canvas: Literal[
4153
4160
  "all",
4154
4161
  "row_index",
4162
+ "index",
4155
4163
  "header",
4156
4164
  "top_left",
4157
4165
  "x_scrollbar",
@@ -4174,7 +4182,7 @@ class Sheet(tk.Frame):
4174
4182
  self.yscroll_showing = True
4175
4183
  self.xscroll_disabled = False
4176
4184
  self.yscroll_disabled = False
4177
- elif canvas == "row_index":
4185
+ elif canvas in ("row_index", "index"):
4178
4186
  self.RI.grid(row=1, column=0, sticky="nswe")
4179
4187
  self.MT["yscrollcommand"] = self.yscroll.set
4180
4188
  self.RI["yscrollcommand"] = self.yscroll.set
@@ -4423,14 +4431,107 @@ class Sheet(tk.Frame):
4423
4431
  and event.widget == self.TL
4424
4432
  )
4425
4433
 
4434
+ def props(
4435
+ self,
4436
+ row: int,
4437
+ column: int | str,
4438
+ key: None
4439
+ | Literal[
4440
+ "format",
4441
+ "highlight",
4442
+ "dropdown",
4443
+ "checkbox",
4444
+ "readonly",
4445
+ "align",
4446
+ ] = None,
4447
+ cellops: bool = True,
4448
+ rowops: bool = True,
4449
+ columnops: bool = True,
4450
+ ) -> dict:
4451
+ """
4452
+ Retrieve options (properties - props)
4453
+ from a single cell in the main table
4454
+
4455
+ Also retrieves any row or column options
4456
+ impacting that cell
4457
+ """
4458
+ if isinstance(column, str):
4459
+ column = alpha2idx(column)
4460
+ if key is not None:
4461
+ return self.MT.get_cell_kwargs(
4462
+ datarn=row,
4463
+ datacn=column,
4464
+ key=key,
4465
+ cell=cellops,
4466
+ row=rowops,
4467
+ column=columnops,
4468
+ )
4469
+ if cellops and (row, column) in self.MT.cell_options:
4470
+ return self.MT.cell_options[(row, column)]
4471
+ if rowops and row in self.MT.row_options:
4472
+ return self.MT.row_options[row]
4473
+ if columnops and column in self.MT.col_options:
4474
+ return self.MT.col_options[column]
4475
+ return {}
4476
+
4477
+ def index_props(
4478
+ self,
4479
+ row: int,
4480
+ key: None
4481
+ | Literal[
4482
+ "format",
4483
+ "highlight",
4484
+ "dropdown",
4485
+ "checkbox",
4486
+ "readonly",
4487
+ "align",
4488
+ ] = None,
4489
+ ) -> dict:
4490
+ """
4491
+ Retrieve options (properties - props)
4492
+ from a cell in the index
4493
+ """
4494
+ if key is not None:
4495
+ return self.RI.get_cell_kwargs(
4496
+ datarn=row,
4497
+ key=key,
4498
+ )
4499
+ return self.RI.cell_options[row] if row in self.RI.cell_options else {}
4500
+
4501
+ def header_props(
4502
+ self,
4503
+ column: int | str,
4504
+ key: None
4505
+ | Literal[
4506
+ "format",
4507
+ "highlight",
4508
+ "dropdown",
4509
+ "checkbox",
4510
+ "readonly",
4511
+ "align",
4512
+ ] = None,
4513
+ ) -> dict:
4514
+ """
4515
+ Retrieve options (properties - props)
4516
+ from a cell in the header
4517
+ """
4518
+ if isinstance(column, str):
4519
+ column = alpha2idx(column)
4520
+ if key is not None:
4521
+ return self.CH.get_cell_kwargs(
4522
+ datacn=column,
4523
+ key=key,
4524
+ )
4525
+ return self.CH.cell_options[column] if column in self.CH.cell_options else {}
4526
+
4426
4527
  def get_cell_options(
4427
4528
  self,
4428
4529
  key: None | str = None,
4429
- canvas: Literal["table", "row_index", "header"] = "table",
4530
+ canvas: Literal["table", "row_index", "index", "header"] = "table",
4430
4531
  ) -> dict:
4431
4532
  if canvas == "table":
4432
4533
  target = self.MT.cell_options
4433
- elif canvas == "row_index":
4534
+ elif canvas in ("row_index", "index"):
4434
4535
  target = self.RI.cell_options
4435
4536
  elif canvas == "header":
4436
4537
  target = self.CH.cell_options
@@ -6024,7 +6125,7 @@ class Sheet(tk.Frame):
6024
6125
  row: int | Literal["all"] = 0,
6025
6126
  column: int = 0,
6026
6127
  cells: list[tuple[int, int]] = [],
6027
- canvas: Literal["table", "row_index", "header"] = "table",
6128
+ canvas: Literal["table", "row_index", "index", "header"] = "table",
6028
6129
  all_: bool = False,
6029
6130
  redraw: bool = True,
6030
6131
  ) -> Sheet:
@@ -6057,7 +6158,7 @@ class Sheet(tk.Frame):
6057
6158
  for k in self.MT.cell_options:
6058
6159
  if "highlight" in self.MT.cell_options[k]:
6059
6160
  del self.MT.cell_options[k]["highlight"]
6060
- elif canvas == "row_index":
6161
+ elif canvas in ("row_index", "index"):
6061
6162
  if cells and not all_:
6062
6163
  for r in cells:
6063
6164
  try:
@@ -6087,10 +6188,13 @@ class Sheet(tk.Frame):
6087
6188
  del self.CH.cell_options[c]["highlight"]
6088
6189
  return self.set_refresh_timer(redraw)
6089
6190
 
6090
- def get_highlighted_cells(self, canvas: str = "table") -> dict | None:
6191
+ def get_highlighted_cells(
6192
+ self,
6193
+ canvas: Literal["table", "row_index", "index", "header"] = "table",
6194
+ ) -> dict | None:
6091
6195
  if canvas == "table":
6092
6196
  return {k: v["highlight"] for k, v in self.MT.cell_options.items() if "highlight" in v}
6093
- elif canvas == "row_index":
6197
+ elif canvas in ("row_index", "index"):
6094
6198
  return {k: v["highlight"] for k, v in self.RI.cell_options.items() if "highlight" in v}
6095
6199
  elif canvas == "header":
6096
6200
  return {k: v["highlight"] for k, v in self.CH.cell_options.items() if "highlight" in v}
@@ -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
  ],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tksheet
3
- Version: 7.2.18
3
+ Version: 7.2.19
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes