tksheet 7.0.6__py3-none-any.whl → 7.1.1__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/sheet.py CHANGED
@@ -2,9 +2,10 @@ from __future__ import annotations
2
2
 
3
3
  import tkinter as tk
4
4
  from bisect import bisect_left
5
- from collections import deque
5
+ from collections import defaultdict, deque
6
6
  from collections.abc import Callable, Generator, Iterator, Sequence
7
7
  from itertools import accumulate, chain, islice, product
8
+ from timeit import default_timer
8
9
  from tkinter import ttk
9
10
  from typing import Literal
10
11
  from warnings import warn as WARNING
@@ -29,20 +30,23 @@ from .functions import (
29
30
  is_iterable,
30
31
  key_to_span,
31
32
  num2alpha,
33
+ pop_positions,
32
34
  set_align,
33
35
  set_readonly,
34
36
  span_froms,
35
37
  span_ranges,
36
38
  tksheet_type_error,
39
+ unpack,
37
40
  )
38
41
  from .main_table import MainTable
39
42
  from .other_classes import (
40
- CurrentlySelectedClass, # noqa: F401
41
43
  DotDict,
42
44
  EventDataDict,
43
45
  FontTuple,
44
46
  GeneratedMouseEvent,
47
+ Node,
45
48
  Span,
49
+ Selected,
46
50
  )
47
51
  from .row_index import RowIndex
48
52
  from .sheet_options import (
@@ -66,6 +70,7 @@ from .vars import (
66
70
  emitted_events,
67
71
  named_span_types,
68
72
  rc_binding,
73
+ scrollbar_options_keys,
69
74
  )
70
75
 
71
76
 
@@ -115,52 +120,6 @@ class Sheet(tk.Frame):
115
120
  all_columns_displayed: bool = True,
116
121
  displayed_rows: list[int] = [],
117
122
  all_rows_displayed: bool = True,
118
- outline_thickness: int = 0,
119
- outline_color: str = theme_light_blue["outline_color"],
120
- theme: str = "light blue",
121
- frame_bg: str = theme_light_blue["table_bg"],
122
- popup_menu_fg: str = theme_light_blue["popup_menu_fg"],
123
- popup_menu_bg: str = theme_light_blue["popup_menu_bg"],
124
- popup_menu_highlight_bg: str = theme_light_blue["popup_menu_highlight_bg"],
125
- popup_menu_highlight_fg: str = theme_light_blue["popup_menu_highlight_fg"],
126
- table_grid_fg: str = theme_light_blue["table_grid_fg"],
127
- table_bg: str = theme_light_blue["table_bg"],
128
- table_fg: str = theme_light_blue["table_fg"],
129
- table_selected_box_cells_fg: str = theme_light_blue["table_selected_box_cells_fg"],
130
- table_selected_box_rows_fg: str = theme_light_blue["table_selected_box_rows_fg"],
131
- table_selected_box_columns_fg: str = theme_light_blue["table_selected_box_columns_fg"],
132
- table_selected_cells_border_fg: str = theme_light_blue["table_selected_cells_border_fg"],
133
- table_selected_cells_bg: str = theme_light_blue["table_selected_cells_bg"],
134
- table_selected_cells_fg: str = theme_light_blue["table_selected_cells_fg"],
135
- table_selected_rows_border_fg: str = theme_light_blue["table_selected_rows_border_fg"],
136
- table_selected_rows_bg: str = theme_light_blue["table_selected_rows_bg"],
137
- table_selected_rows_fg: str = theme_light_blue["table_selected_rows_fg"],
138
- table_selected_columns_border_fg: str = theme_light_blue["table_selected_columns_border_fg"],
139
- table_selected_columns_bg: str = theme_light_blue["table_selected_columns_bg"],
140
- table_selected_columns_fg: str = theme_light_blue["table_selected_columns_fg"],
141
- resizing_line_fg: str = theme_light_blue["resizing_line_fg"],
142
- drag_and_drop_bg: str = theme_light_blue["drag_and_drop_bg"],
143
- index_bg: str = theme_light_blue["index_bg"],
144
- index_border_fg: str = theme_light_blue["index_border_fg"],
145
- index_grid_fg: str = theme_light_blue["index_grid_fg"],
146
- index_fg: str = theme_light_blue["index_fg"],
147
- index_selected_cells_bg: str = theme_light_blue["index_selected_cells_bg"],
148
- index_selected_cells_fg: str = theme_light_blue["index_selected_cells_fg"],
149
- index_selected_rows_bg: str = theme_light_blue["index_selected_rows_bg"],
150
- index_selected_rows_fg: str = theme_light_blue["index_selected_rows_fg"],
151
- index_hidden_rows_expander_bg: str = theme_light_blue["index_hidden_rows_expander_bg"],
152
- header_bg: str = theme_light_blue["header_bg"],
153
- header_border_fg: str = theme_light_blue["header_border_fg"],
154
- header_grid_fg: str = theme_light_blue["header_grid_fg"],
155
- header_fg: str = theme_light_blue["header_fg"],
156
- header_selected_cells_bg: str = theme_light_blue["header_selected_cells_bg"],
157
- header_selected_cells_fg: str = theme_light_blue["header_selected_cells_fg"],
158
- header_selected_columns_bg: str = theme_light_blue["header_selected_columns_bg"],
159
- header_selected_columns_fg: str = theme_light_blue["header_selected_columns_fg"],
160
- header_hidden_columns_expander_bg: str = theme_light_blue["header_hidden_columns_expander_bg"],
161
- top_left_bg: str = theme_light_blue["top_left_bg"],
162
- top_left_fg: str = theme_light_blue["top_left_fg"],
163
- top_left_fg_highlight: str = theme_light_blue["top_left_fg_highlight"],
164
123
  to_clipboard_delimiter: str = "\t",
165
124
  to_clipboard_quotechar: str = '"',
166
125
  to_clipboard_lineterminator: str = "\n",
@@ -174,7 +133,7 @@ class Sheet(tk.Frame):
174
133
  show_dropdown_borders: bool = False,
175
134
  arrow_key_down_right_scroll_page: bool = False,
176
135
  cell_auto_resize_enabled: bool = True,
177
- auto_resize_row_index: bool = True,
136
+ auto_resize_row_index: bool | Literal["empty"] = "empty",
178
137
  auto_resize_columns: int | None = None,
179
138
  auto_resize_rows: int | None = None,
180
139
  set_cell_sizes_on_zoom: bool = False,
@@ -210,6 +169,91 @@ class Sheet(tk.Frame):
210
169
  show_horizontal_grid: bool = True,
211
170
  display_selected_fg_over_highlights: bool = False,
212
171
  show_selected_cells_border: bool = True,
172
+ treeview: bool = False,
173
+ # colors
174
+ outline_thickness: int = 0,
175
+ outline_color: str = theme_light_blue["outline_color"],
176
+ theme: str = "light blue",
177
+ frame_bg: str = theme_light_blue["table_bg"],
178
+ popup_menu_fg: str = theme_light_blue["popup_menu_fg"],
179
+ popup_menu_bg: str = theme_light_blue["popup_menu_bg"],
180
+ popup_menu_highlight_bg: str = theme_light_blue["popup_menu_highlight_bg"],
181
+ popup_menu_highlight_fg: str = theme_light_blue["popup_menu_highlight_fg"],
182
+ table_grid_fg: str = theme_light_blue["table_grid_fg"],
183
+ table_bg: str = theme_light_blue["table_bg"],
184
+ table_fg: str = theme_light_blue["table_fg"],
185
+ table_selected_box_cells_fg: str = theme_light_blue["table_selected_box_cells_fg"],
186
+ table_selected_box_rows_fg: str = theme_light_blue["table_selected_box_rows_fg"],
187
+ table_selected_box_columns_fg: str = theme_light_blue["table_selected_box_columns_fg"],
188
+ table_selected_cells_border_fg: str = theme_light_blue["table_selected_cells_border_fg"],
189
+ table_selected_cells_bg: str = theme_light_blue["table_selected_cells_bg"],
190
+ table_selected_cells_fg: str = theme_light_blue["table_selected_cells_fg"],
191
+ table_selected_rows_border_fg: str = theme_light_blue["table_selected_rows_border_fg"],
192
+ table_selected_rows_bg: str = theme_light_blue["table_selected_rows_bg"],
193
+ table_selected_rows_fg: str = theme_light_blue["table_selected_rows_fg"],
194
+ table_selected_columns_border_fg: str = theme_light_blue["table_selected_columns_border_fg"],
195
+ table_selected_columns_bg: str = theme_light_blue["table_selected_columns_bg"],
196
+ table_selected_columns_fg: str = theme_light_blue["table_selected_columns_fg"],
197
+ resizing_line_fg: str = theme_light_blue["resizing_line_fg"],
198
+ drag_and_drop_bg: str = theme_light_blue["drag_and_drop_bg"],
199
+ index_bg: str = theme_light_blue["index_bg"],
200
+ index_border_fg: str = theme_light_blue["index_border_fg"],
201
+ index_grid_fg: str = theme_light_blue["index_grid_fg"],
202
+ index_fg: str = theme_light_blue["index_fg"],
203
+ index_selected_cells_bg: str = theme_light_blue["index_selected_cells_bg"],
204
+ index_selected_cells_fg: str = theme_light_blue["index_selected_cells_fg"],
205
+ index_selected_rows_bg: str = theme_light_blue["index_selected_rows_bg"],
206
+ index_selected_rows_fg: str = theme_light_blue["index_selected_rows_fg"],
207
+ index_hidden_rows_expander_bg: str = theme_light_blue["index_hidden_rows_expander_bg"],
208
+ header_bg: str = theme_light_blue["header_bg"],
209
+ header_border_fg: str = theme_light_blue["header_border_fg"],
210
+ header_grid_fg: str = theme_light_blue["header_grid_fg"],
211
+ header_fg: str = theme_light_blue["header_fg"],
212
+ header_selected_cells_bg: str = theme_light_blue["header_selected_cells_bg"],
213
+ header_selected_cells_fg: str = theme_light_blue["header_selected_cells_fg"],
214
+ header_selected_columns_bg: str = theme_light_blue["header_selected_columns_bg"],
215
+ header_selected_columns_fg: str = theme_light_blue["header_selected_columns_fg"],
216
+ header_hidden_columns_expander_bg: str = theme_light_blue["header_hidden_columns_expander_bg"],
217
+ top_left_bg: str = theme_light_blue["top_left_bg"],
218
+ top_left_fg: str = theme_light_blue["top_left_fg"],
219
+ top_left_fg_highlight: str = theme_light_blue["top_left_fg_highlight"],
220
+ vertical_scroll_background: str = theme_light_blue["vertical_scroll_background"],
221
+ horizontal_scroll_background: str = theme_light_blue["horizontal_scroll_background"],
222
+ vertical_scroll_troughcolor: str = theme_light_blue["vertical_scroll_troughcolor"],
223
+ horizontal_scroll_troughcolor: str = theme_light_blue["horizontal_scroll_troughcolor"],
224
+ vertical_scroll_lightcolor: str = theme_light_blue["vertical_scroll_lightcolor"],
225
+ horizontal_scroll_lightcolor: str = theme_light_blue["horizontal_scroll_lightcolor"],
226
+ vertical_scroll_darkcolor: str = theme_light_blue["vertical_scroll_darkcolor"],
227
+ horizontal_scroll_darkcolor: str = theme_light_blue["horizontal_scroll_darkcolor"],
228
+ vertical_scroll_relief: str = theme_light_blue["vertical_scroll_relief"],
229
+ horizontal_scroll_relief: str = theme_light_blue["horizontal_scroll_relief"],
230
+ vertical_scroll_troughrelief: str = theme_light_blue["vertical_scroll_troughrelief"],
231
+ horizontal_scroll_troughrelief: str = theme_light_blue["horizontal_scroll_troughrelief"],
232
+ vertical_scroll_bordercolor: str = theme_light_blue["vertical_scroll_bordercolor"],
233
+ horizontal_scroll_bordercolor: str = theme_light_blue["horizontal_scroll_bordercolor"],
234
+ vertical_scroll_borderwidth: int = 1,
235
+ horizontal_scroll_borderwidth: int = 1,
236
+ vertical_scroll_gripcount: int = 0,
237
+ horizontal_scroll_gripcount: int = 0,
238
+ vertical_scroll_active_bg: str = theme_light_blue["vertical_scroll_active_bg"],
239
+ horizontal_scroll_active_bg: str = theme_light_blue["horizontal_scroll_active_bg"],
240
+ vertical_scroll_not_active_bg: str = theme_light_blue["vertical_scroll_not_active_bg"],
241
+ horizontal_scroll_not_active_bg: str = theme_light_blue["horizontal_scroll_not_active_bg"],
242
+ vertical_scroll_pressed_bg: str = theme_light_blue["vertical_scroll_pressed_bg"],
243
+ horizontal_scroll_pressed_bg: str = theme_light_blue["horizontal_scroll_pressed_bg"],
244
+ vertical_scroll_active_fg: str = theme_light_blue["vertical_scroll_active_fg"],
245
+ horizontal_scroll_active_fg: str = theme_light_blue["horizontal_scroll_active_fg"],
246
+ vertical_scroll_not_active_fg: str = theme_light_blue["vertical_scroll_not_active_fg"],
247
+ horizontal_scroll_not_active_fg: str = theme_light_blue["horizontal_scroll_not_active_fg"],
248
+ vertical_scroll_pressed_fg: str = theme_light_blue["vertical_scroll_pressed_fg"],
249
+ horizontal_scroll_pressed_fg: str = theme_light_blue["horizontal_scroll_pressed_fg"],
250
+ scrollbar_theme_inheritance: str = "default",
251
+ scrollbar_show_arrows: bool = True,
252
+ # changing the arrowsize (width) of the scrollbars
253
+ # is not working with 'default' theme
254
+ # use 'clam' theme instead if you want to change the width
255
+ vertical_scroll_arrowsize: str | int = "",
256
+ horizontal_scroll_arrowsize: str | int = "",
213
257
  # backwards compatibility
214
258
  column_width: int | None = None,
215
259
  header_height: str | int | None = None,
@@ -236,6 +280,9 @@ class Sheet(tk.Frame):
236
280
  default_row_height = row_height
237
281
  if row_index_width is not None:
238
282
  default_row_index_width = row_index_width
283
+ if treeview:
284
+ index_align = "w"
285
+ auto_resize_row_index = True
239
286
  for k, v in locals().items():
240
287
  if (xk := backwards_compatibility_keys.get(k, k)) in self.ops and v != self.ops[xk]:
241
288
  self.ops[xk] = v
@@ -306,8 +353,64 @@ class Sheet(tk.Frame):
306
353
  row_index_canvas=self.RI,
307
354
  header_canvas=self.CH,
308
355
  )
309
- self.yscroll = ttk.Scrollbar(self, command=self.MT.set_yviews, orient="vertical")
310
- self.xscroll = ttk.Scrollbar(self, command=self.MT.set_xviews, orient="horizontal")
356
+ self.unique_id = f"{default_timer()}{self.winfo_id()}".replace(".", "")
357
+ style = ttk.Style()
358
+ for orientation in ("Vertical", "Horizontal"):
359
+ style.element_create(
360
+ f"Sheet{self.unique_id}.{orientation}.TScrollbar.trough",
361
+ "from",
362
+ scrollbar_theme_inheritance,
363
+ )
364
+ style.element_create(
365
+ f"Sheet{self.unique_id}.{orientation}.TScrollbar.thumb",
366
+ "from",
367
+ scrollbar_theme_inheritance,
368
+ )
369
+ style.element_create(
370
+ f"Sheet{self.unique_id}.{orientation}.TScrollbar.grip",
371
+ "from",
372
+ scrollbar_theme_inheritance,
373
+ )
374
+ if not scrollbar_show_arrows:
375
+ style.layout(
376
+ f"Sheet{self.unique_id}.{orientation}.TScrollbar",
377
+ [
378
+ (
379
+ f"Sheet{self.unique_id}.{orientation}.TScrollbar.trough",
380
+ {
381
+ "children": [
382
+ (
383
+ f"Sheet{self.unique_id}.{orientation}.TScrollbar.thumb",
384
+ {
385
+ "unit": "1",
386
+ "children": [
387
+ (
388
+ f"Sheet{self.unique_id}.{orientation}.TScrollbar.grip",
389
+ {"sticky": ""},
390
+ )
391
+ ],
392
+ "sticky": "nswe",
393
+ },
394
+ )
395
+ ],
396
+ "sticky": "ns" if orientation == "Vertical" else "ew",
397
+ },
398
+ )
399
+ ],
400
+ )
401
+ self.set_scrollbar_options()
402
+ self.yscroll = ttk.Scrollbar(
403
+ self,
404
+ command=self.MT.set_yviews,
405
+ orient="vertical",
406
+ style=f"Sheet{self.unique_id}.Vertical.TScrollbar",
407
+ )
408
+ self.xscroll = ttk.Scrollbar(
409
+ self,
410
+ command=self.MT.set_xviews,
411
+ orient="horizontal",
412
+ style=f"Sheet{self.unique_id}.Horizontal.TScrollbar",
413
+ )
311
414
  if show_top_left:
312
415
  self.TL.grid(row=0, column=0)
313
416
  if show_table:
@@ -1343,9 +1446,11 @@ class Sheet(tk.Frame):
1343
1446
  row_heights: bool = True,
1344
1447
  column_widths: bool = True,
1345
1448
  cell_options: bool = True,
1449
+ tags: bool = True,
1346
1450
  undo_stack: bool = True,
1347
1451
  selections: bool = True,
1348
1452
  sheet_options: bool = False,
1453
+ tree: bool = True,
1349
1454
  redraw: bool = True,
1350
1455
  ) -> Sheet:
1351
1456
  if table:
@@ -1355,17 +1460,23 @@ class Sheet(tk.Frame):
1355
1460
  if index:
1356
1461
  self.MT._row_index = []
1357
1462
  if row_heights:
1463
+ self.MT.saved_row_heights = {}
1358
1464
  self.MT.set_row_positions([])
1359
1465
  if column_widths:
1466
+ self.MT.saved_column_widths = {}
1360
1467
  self.MT.set_col_positions([])
1361
1468
  if cell_options:
1362
1469
  self.reset_all_options()
1470
+ if tags:
1471
+ self.MT.reset_tags()
1363
1472
  if undo_stack:
1364
1473
  self.reset_undos()
1365
1474
  if selections:
1366
1475
  self.MT.deselect(redraw=False)
1367
1476
  if sheet_options:
1368
1477
  self.ops = new_sheet_options()
1478
+ if tree:
1479
+ self.RI.reset_tree()
1369
1480
  self.set_refresh_timer(redraw)
1370
1481
  return self
1371
1482
 
@@ -1470,7 +1581,7 @@ class Sheet(tk.Frame):
1470
1581
  event_data = event_dict(
1471
1582
  name="edit_table",
1472
1583
  sheet=self.name,
1473
- selected=self.MT.currently_selected(),
1584
+ selected=self.MT.selected,
1474
1585
  )
1475
1586
  set_t = self.event_data_set_table_cell
1476
1587
  set_i, set_h = self.event_data_set_index_cell, self.event_data_set_header_cell
@@ -1700,7 +1811,7 @@ class Sheet(tk.Frame):
1700
1811
  event_data = event_dict(
1701
1812
  name="edit_table",
1702
1813
  sheet=self.name,
1703
- selected=self.MT.currently_selected(),
1814
+ selected=self.MT.selected,
1704
1815
  )
1705
1816
  if index:
1706
1817
  for r in rows:
@@ -1811,6 +1922,7 @@ class Sheet(tk.Frame):
1811
1922
  fill: bool = True,
1812
1923
  undo: bool = False,
1813
1924
  emit_event: bool = False,
1925
+ create_selections: bool = True,
1814
1926
  redraw: bool = True,
1815
1927
  ) -> EventDataDict:
1816
1928
  total_cols = None
@@ -1873,8 +1985,9 @@ class Sheet(tk.Frame):
1873
1985
  name="add_rows",
1874
1986
  sheet=self.name,
1875
1987
  boxes=self.MT.get_boxes(),
1876
- selected=self.MT.currently_selected(),
1988
+ selected=self.MT.selected,
1877
1989
  ),
1990
+ create_selections=create_selections,
1878
1991
  )
1879
1992
  if undo:
1880
1993
  self.MT.undo_stack.append(ev_stack_dict(event_data))
@@ -1892,6 +2005,7 @@ class Sheet(tk.Frame):
1892
2005
  fill: bool = True,
1893
2006
  undo: bool = False,
1894
2007
  emit_event: bool = False,
2008
+ create_selections: bool = True,
1895
2009
  redraw: bool = True,
1896
2010
  ) -> EventDataDict:
1897
2011
  old_total = self.MT.equalize_data_row_lengths()
@@ -1962,8 +2076,9 @@ class Sheet(tk.Frame):
1962
2076
  name="add_columns",
1963
2077
  sheet=self.name,
1964
2078
  boxes=self.MT.get_boxes(),
1965
- selected=self.MT.currently_selected(),
2079
+ selected=self.MT.selected,
1966
2080
  ),
2081
+ create_selections=create_selections,
1967
2082
  )
1968
2083
  if undo:
1969
2084
  self.MT.undo_stack.append(ev_stack_dict(event_data))
@@ -2021,7 +2136,7 @@ class Sheet(tk.Frame):
2021
2136
  name="delete_rows",
2022
2137
  sheet=self.name,
2023
2138
  boxes=self.MT.get_boxes(),
2024
- selected=self.MT.currently_selected(),
2139
+ selected=self.MT.selected,
2025
2140
  )
2026
2141
  if not data_indexes:
2027
2142
  event_data = self.MT.delete_rows_displayed(rows, event_data)
@@ -2062,7 +2177,7 @@ class Sheet(tk.Frame):
2062
2177
  name="delete_columns",
2063
2178
  sheet=self.name,
2064
2179
  boxes=self.MT.get_boxes(),
2065
- selected=self.MT.currently_selected(),
2180
+ selected=self.MT.selected,
2066
2181
  )
2067
2182
  if not data_indexes:
2068
2183
  event_data = self.MT.delete_columns_displayed(columns, event_data)
@@ -2257,7 +2372,7 @@ class Sheet(tk.Frame):
2257
2372
  data_idxs, disp_idxs, event_data = self.MT.move_rows_adjust_options_dict(
2258
2373
  data_new_idxs=data_new_idxs,
2259
2374
  data_old_idxs=dict(zip(data_new_idxs.values(), data_new_idxs)),
2260
- totalcols=None,
2375
+ totalrows=None,
2261
2376
  disp_new_idxs=disp_new_idxs,
2262
2377
  move_data=move_data,
2263
2378
  create_selections=create_selections,
@@ -2401,11 +2516,11 @@ class Sheet(tk.Frame):
2401
2516
  ) -> Span:
2402
2517
  span = self.span_from_key(*key)
2403
2518
  if span.table:
2404
- self.MT.destroy_opened_dropdown_window()
2519
+ self.MT.hide_dropdown_window()
2405
2520
  if span.index:
2406
- self.RI.destroy_opened_dropdown_window()
2521
+ self.RI.hide_dropdown_window()
2407
2522
  if span.header:
2408
- self.CH.destroy_opened_dropdown_window()
2523
+ self.CH.hide_dropdown_window()
2409
2524
  self.del_options_using_span(span, "dropdown")
2410
2525
  self.set_refresh_timer(redraw)
2411
2526
  return span
@@ -2792,8 +2907,14 @@ class Sheet(tk.Frame):
2792
2907
 
2793
2908
  # Getting Selected Cells
2794
2909
 
2795
- def get_currently_selected(self) -> tuple[()] | CurrentlySelectedClass:
2796
- return self.MT.currently_selected()
2910
+ def get_currently_selected(self) -> tuple[()] | Selected:
2911
+ # if self.MT.selected:
2912
+ # return self.MT.selected._replace(type_=self.MT.selected.type_[:-1])
2913
+ return self.MT.selected
2914
+
2915
+ @property
2916
+ def selected(self) -> tuple[()] | Selected:
2917
+ return self.MT.selected
2797
2918
 
2798
2919
  def get_selected_rows(
2799
2920
  self,
@@ -3179,7 +3300,7 @@ class Sheet(tk.Frame):
3179
3300
  canvas_positions: bool = False,
3180
3301
  reset: bool = False,
3181
3302
  ) -> Sheet:
3182
- if reset:
3303
+ if reset or column_widths is None:
3183
3304
  self.MT.reset_col_positions()
3184
3305
  elif is_iterable(column_widths):
3185
3306
  if canvas_positions and isinstance(column_widths, list):
@@ -3194,9 +3315,9 @@ class Sheet(tk.Frame):
3194
3315
  canvas_positions: bool = False,
3195
3316
  reset: bool = False,
3196
3317
  ) -> Sheet:
3197
- if reset:
3318
+ if reset or row_heights is None:
3198
3319
  self.MT.reset_row_positions()
3199
- if is_iterable(row_heights):
3320
+ elif is_iterable(row_heights):
3200
3321
  if canvas_positions and isinstance(row_heights, list):
3201
3322
  self.MT.row_positions = row_heights
3202
3323
  else:
@@ -3447,15 +3568,25 @@ class Sheet(tk.Frame):
3447
3568
  def cell_completely_visible(self, r: int, c: int, seperate_axes: bool = False) -> bool:
3448
3569
  return self.MT.cell_completely_visible(r, c, seperate_axes)
3449
3570
 
3450
- def set_xview(self, position: float, option: str = "moveto") -> Sheet:
3451
- self.MT.set_xviews(option, position)
3452
- return self
3571
+ def set_xview(self, position: None | float = None, option: str = "moveto") -> Sheet | tuple[float, float]:
3572
+ if position is not None:
3573
+ self.MT.set_xviews(option, position)
3574
+ return self
3575
+ return self.MT.xview()
3453
3576
 
3454
- def set_yview(self, position: float, option: str = "moveto") -> Sheet:
3455
- self.MT.set_yviews(option, position)
3456
- return self
3577
+ xview = set_xview
3578
+ xview_moveto = set_xview
3579
+
3580
+ def set_yview(self, position: None | float = None, option: str = "moveto") -> Sheet | tuple[float, float]:
3581
+ if position is not None:
3582
+ self.MT.set_yviews(option, position)
3583
+ return self
3584
+ return self.MT.yview()
3585
+
3586
+ yview = set_yview
3587
+ yview_moveto = set_yview
3457
3588
 
3458
- def set_view(self, x_args: [str, float], y_args: [str, float]) -> Sheet:
3589
+ def set_view(self, x_args: list[str, float], y_args: list[str, float]) -> Sheet:
3459
3590
  self.MT.set_view(x_args, y_args)
3460
3591
  return self
3461
3592
 
@@ -3470,6 +3601,8 @@ class Sheet(tk.Frame):
3470
3601
  def displayed_column_to_data(self, c: int) -> int:
3471
3602
  return c if self.MT.all_columns_displayed else self.MT.displayed_columns[c]
3472
3603
 
3604
+ data_c = displayed_column_to_data
3605
+
3473
3606
  def display_columns(
3474
3607
  self,
3475
3608
  columns: None | Literal["all"] | Iterator[int] = None,
@@ -3494,31 +3627,70 @@ class Sheet(tk.Frame):
3494
3627
  self.set_refresh_timer(redraw if redraw else refresh)
3495
3628
  return res
3496
3629
 
3497
- # uses displayed indexes
3498
3630
  def hide_columns(
3499
3631
  self,
3500
- columns: int | set | Iterator[int] = set(),
3632
+ columns: int | set[int] | Iterator[int],
3501
3633
  redraw: bool = True,
3502
3634
  deselect_all: bool = True,
3635
+ data_indexes: bool = False,
3503
3636
  ) -> Sheet:
3504
3637
  if isinstance(columns, int):
3505
- _columns = {columns}
3506
- elif isinstance(columns, set):
3507
- _columns = columns
3508
- else:
3509
- _columns = set(columns)
3510
- if not _columns:
3511
- return
3638
+ columns = {columns}
3639
+ elif not isinstance(columns, set):
3640
+ columns = set(columns)
3641
+ if not columns:
3642
+ return
3512
3643
  if self.MT.all_columns_displayed:
3513
- _columns = [c for c in range(self.MT.total_data_cols()) if c not in _columns]
3644
+ self.MT.displayed_columns = [c for c in range(self.MT.total_data_cols()) if c not in columns]
3645
+ to_pop = {c: c for c in columns}
3514
3646
  else:
3515
- _columns = [e for c, e in enumerate(self.MT.displayed_columns) if c not in _columns]
3516
- self.display_columns(
3517
- columns=_columns,
3518
- all_columns_displayed=False,
3519
- redraw=redraw,
3520
- deselect_all=deselect_all,
3647
+ to_pop = {}
3648
+ new_disp = []
3649
+ if data_indexes:
3650
+ for i, c in enumerate(self.MT.displayed_columns):
3651
+ if c not in columns:
3652
+ new_disp.append(c)
3653
+ else:
3654
+ to_pop[i] = c
3655
+ else:
3656
+ for i, c in enumerate(self.MT.displayed_columns):
3657
+ if i not in columns:
3658
+ new_disp.append(c)
3659
+ else:
3660
+ to_pop[i] = c
3661
+ self.MT.displayed_columns = new_disp
3662
+ self.MT.all_columns_displayed = False
3663
+ self.MT.set_col_positions(
3664
+ pop_positions(
3665
+ itr=self.MT.gen_column_widths,
3666
+ to_pop=to_pop,
3667
+ save_to=self.MT.saved_column_widths,
3668
+ ),
3521
3669
  )
3670
+ if deselect_all:
3671
+ self.MT.deselect(redraw=False)
3672
+ self.set_refresh_timer(redraw)
3673
+ return self
3674
+
3675
+ # uses data indexes
3676
+ def show_columns(
3677
+ self,
3678
+ columns: int | Iterator[int],
3679
+ redraw: bool = True,
3680
+ deselect_all: bool = True,
3681
+ ) -> Sheet:
3682
+ if isinstance(columns, int):
3683
+ columns = [columns]
3684
+ cws = self.MT.get_column_widths()
3685
+ for column in columns:
3686
+ idx = bisect_left(self.MT.displayed_columns, column)
3687
+ if len(self.MT.displayed_columns) == idx or self.MT.displayed_columns[idx] != column:
3688
+ self.MT.displayed_columns.insert(idx, column)
3689
+ cws.insert(idx, self.MT.saved_column_widths.pop(column, self.PAR.ops.default_column_width))
3690
+ self.MT.set_col_positions(cws)
3691
+ if deselect_all:
3692
+ self.MT.deselect(redraw=False)
3693
+ self.set_refresh_timer(redraw)
3522
3694
  return self
3523
3695
 
3524
3696
  def all_columns_displayed(self, a: bool | None = None) -> bool:
@@ -3536,6 +3708,8 @@ class Sheet(tk.Frame):
3536
3708
  def displayed_row_to_data(self, r: int) -> int:
3537
3709
  return r if self.MT.all_rows_displayed else self.MT.displayed_rows[r]
3538
3710
 
3711
+ data_r = displayed_row_to_data
3712
+
3539
3713
  def display_rows(
3540
3714
  self,
3541
3715
  rows: None | Literal["all"] | Iterator[int] = None,
@@ -3558,31 +3732,70 @@ class Sheet(tk.Frame):
3558
3732
  self.set_refresh_timer(redraw if redraw else refresh)
3559
3733
  return res
3560
3734
 
3561
- # uses displayed indexes
3562
3735
  def hide_rows(
3563
3736
  self,
3564
- rows: int | set | Iterator[int] = set(),
3737
+ rows: int | set[int] | Iterator[int],
3565
3738
  redraw: bool = True,
3566
3739
  deselect_all: bool = True,
3740
+ data_indexes: bool = False,
3567
3741
  ) -> Sheet:
3568
3742
  if isinstance(rows, int):
3569
- _rows = {rows}
3570
- elif isinstance(rows, set):
3571
- _rows = rows
3572
- else:
3573
- _rows = set(rows)
3574
- if not _rows:
3575
- return
3743
+ rows = {rows}
3744
+ elif not isinstance(rows, set):
3745
+ rows = set(rows)
3746
+ if not rows:
3747
+ return
3576
3748
  if self.MT.all_rows_displayed:
3577
- _rows = [r for r in range(self.MT.total_data_rows()) if r not in _rows]
3749
+ self.MT.displayed_rows = [r for r in range(self.MT.total_data_rows()) if r not in rows]
3750
+ to_pop = {r: r for r in rows}
3578
3751
  else:
3579
- _rows = [e for r, e in enumerate(self.MT.displayed_rows) if r not in _rows]
3580
- self.display_rows(
3581
- rows=_rows,
3582
- all_rows_displayed=False,
3583
- redraw=redraw,
3584
- deselect_all=deselect_all,
3752
+ to_pop = {}
3753
+ new_disp = []
3754
+ if data_indexes:
3755
+ for i, r in enumerate(self.MT.displayed_rows):
3756
+ if r not in rows:
3757
+ new_disp.append(r)
3758
+ else:
3759
+ to_pop[i] = r
3760
+ else:
3761
+ for i, r in enumerate(self.MT.displayed_rows):
3762
+ if i not in rows:
3763
+ new_disp.append(r)
3764
+ else:
3765
+ to_pop[i] = r
3766
+ self.MT.displayed_rows = new_disp
3767
+ self.MT.all_rows_displayed = False
3768
+ self.MT.set_row_positions(
3769
+ pop_positions(
3770
+ itr=self.MT.gen_row_heights,
3771
+ to_pop=to_pop,
3772
+ save_to=self.MT.saved_row_heights,
3773
+ ),
3585
3774
  )
3775
+ if deselect_all:
3776
+ self.MT.deselect(redraw=False)
3777
+ self.set_refresh_timer(redraw)
3778
+ return self
3779
+
3780
+ # uses data indexes
3781
+ def show_rows(
3782
+ self,
3783
+ rows: int | Iterator[int],
3784
+ redraw: bool = True,
3785
+ deselect_all: bool = True,
3786
+ ) -> Sheet:
3787
+ if isinstance(rows, int):
3788
+ rows = [rows]
3789
+ rhs = self.MT.get_row_heights()
3790
+ for row in rows:
3791
+ idx = bisect_left(self.MT.displayed_rows, row)
3792
+ if len(self.MT.displayed_rows) == idx or self.MT.displayed_rows[idx] != row:
3793
+ self.MT.displayed_rows.insert(idx, row)
3794
+ rhs.insert(idx, self.MT.saved_row_heights.pop(row, self.MT.get_default_row_height()))
3795
+ self.MT.set_row_positions(rhs)
3796
+ if deselect_all:
3797
+ self.MT.deselect(redraw=False)
3798
+ self.set_refresh_timer(redraw)
3586
3799
  return self
3587
3800
 
3588
3801
  def all_rows_displayed(self, a: bool | None = None) -> bool:
@@ -3734,22 +3947,34 @@ class Sheet(tk.Frame):
3734
3947
  def set_text_editor_value(
3735
3948
  self,
3736
3949
  text: str = "",
3737
- r: int | None = None,
3738
- c: int | None = None,
3739
3950
  ) -> Sheet:
3740
- if self.MT.text_editor is not None and r is None and c is None:
3741
- self.MT.text_editor.set_text(text)
3742
- elif self.MT.text_editor is not None and self.MT.text_editor_loc == (r, c):
3743
- self.MT.text_editor.set_text(text)
3951
+ if self.MT.text_editor.open:
3952
+ self.MT.text_editor.window.set_text(text)
3953
+ return self
3954
+
3955
+ def set_index_text_editor_value(
3956
+ self,
3957
+ text: str = "",
3958
+ ) -> Sheet:
3959
+ if self.RI.text_editor.open:
3960
+ self.RI.text_editor.window.set_text(text)
3961
+ return self
3962
+
3963
+ def set_header_text_editor_value(
3964
+ self,
3965
+ text: str = "",
3966
+ ) -> Sheet:
3967
+ if self.CH.text_editor.open:
3968
+ self.CH.text_editor.window.set_text(text)
3744
3969
  return self
3745
3970
 
3746
3971
  def destroy_text_editor(self, event: object = None) -> Sheet:
3747
- self.MT.destroy_text_editor(event=event)
3972
+ self.MT.hide_text_editor(event=event)
3748
3973
  return self
3749
3974
 
3750
3975
  def get_text_editor_widget(self, event: object = None) -> tk.Text | None:
3751
3976
  try:
3752
- return self.MT.text_editor.textedit
3977
+ return self.MT.text_editor.tktext
3753
3978
  except Exception:
3754
3979
  return None
3755
3980
 
@@ -3761,7 +3986,7 @@ class Sheet(tk.Frame):
3761
3986
  if key == "all":
3762
3987
  for key in self.MT.text_editor_user_bound_keys:
3763
3988
  try:
3764
- self.MT.text_editor.textedit.unbind(key)
3989
+ self.MT.text_editor.tktext.unbind(key)
3765
3990
  except Exception:
3766
3991
  pass
3767
3992
  self.MT.text_editor_user_bound_keys = {}
@@ -3769,19 +3994,18 @@ class Sheet(tk.Frame):
3769
3994
  if key in self.MT.text_editor_user_bound_keys:
3770
3995
  del self.MT.text_editor_user_bound_keys[key]
3771
3996
  try:
3772
- self.MT.text_editor.textedit.unbind(key)
3997
+ self.MT.text_editor.tktext.unbind(key)
3773
3998
  except Exception:
3774
3999
  pass
3775
4000
  return self
3776
4001
 
3777
4002
  def get_text_editor_value(self) -> str | None:
3778
- if self.MT.text_editor:
3779
- return self.MT.text_editor.get()
4003
+ return self.MT.text_editor.get()
3780
4004
 
3781
4005
  def close_text_editor(self, set_data: bool = True) -> Sheet:
3782
- if self.MT.text_editor:
4006
+ if self.MT.text_editor.open:
3783
4007
  event = ("ButtonPress-1",) if set_data else ("Escape",)
3784
- self.MT.close_text_editor(editor_info=self.MT.text_editor_loc + event)
4008
+ self.MT.close_text_editor(editor_info=self.MT.text_editor.coords + event)
3785
4009
  return self
3786
4010
 
3787
4011
  # Sheet Options and Other Functions
@@ -3841,11 +4065,44 @@ class Sheet(tk.Frame):
3841
4065
  highlightbackground=kwargs["outline_color"],
3842
4066
  highlightcolor=kwargs["outline_color"],
3843
4067
  )
4068
+ if any(k in kwargs for k in scrollbar_options_keys):
4069
+ self.set_scrollbar_options()
3844
4070
  self.MT.create_rc_menus()
3845
4071
  self.MT.key_bindings()
3846
4072
  self.set_refresh_timer(redraw)
3847
4073
  return self
3848
4074
 
4075
+ def set_scrollbar_options(self) -> Sheet:
4076
+ style = ttk.Style()
4077
+ for orientation in ("vertical", "horizontal"):
4078
+ style.configure(
4079
+ f"Sheet{self.unique_id}.{orientation.capitalize()}.TScrollbar",
4080
+ background=self.ops[f"{orientation}_scroll_background"],
4081
+ troughcolor=self.ops[f"{orientation}_scroll_troughcolor"],
4082
+ lightcolor=self.ops[f"{orientation}_scroll_lightcolor"],
4083
+ darkcolor=self.ops[f"{orientation}_scroll_darkcolor"],
4084
+ relief=self.ops[f"{orientation}_scroll_relief"],
4085
+ troughrelief=self.ops[f"{orientation}_scroll_troughrelief"],
4086
+ bordercolor=self.ops[f"{orientation}_scroll_bordercolor"],
4087
+ borderwidth=self.ops[f"{orientation}_scroll_borderwidth"],
4088
+ gripcount=self.ops[f"{orientation}_scroll_gripcount"],
4089
+ arrowsize=self.ops[f"{orientation}_scroll_arrowsize"],
4090
+ )
4091
+ style.map(
4092
+ f"Sheet{self.unique_id}.{orientation.capitalize()}.TScrollbar",
4093
+ foreground=[
4094
+ ("!active", self.ops[f"{orientation}_scroll_not_active_fg"]),
4095
+ ("pressed", self.ops[f"{orientation}_scroll_pressed_fg"]),
4096
+ ("active", self.ops[f"{orientation}_scroll_active_fg"]),
4097
+ ],
4098
+ background=[
4099
+ ("!active", self.ops[f"{orientation}_scroll_not_active_bg"]),
4100
+ ("pressed", self.ops[f"{orientation}_scroll_pressed_bg"]),
4101
+ ("active", self.ops[f"{orientation}_scroll_active_bg"]),
4102
+ ],
4103
+ )
4104
+ return self
4105
+
3849
4106
  def get_cell_options(
3850
4107
  self,
3851
4108
  key: None | str = None,
@@ -3946,6 +4203,570 @@ class Sheet(tk.Frame):
3946
4203
  self.MT.main_table_redraw_grid_and_text(redraw_header=redraw_header, redraw_row_index=redraw_row_index)
3947
4204
  return self
3948
4205
 
4206
+ # Tags
4207
+
4208
+ def tag(
4209
+ self,
4210
+ *key: CreateSpanTypes,
4211
+ tags: Iterator[str] | str = "",
4212
+ ) -> Sheet:
4213
+ span = self.span_from_key(*key)
4214
+ rows, cols = self.ranges_from_span(span)
4215
+ if isinstance(tags, str):
4216
+ tags = (tags,)
4217
+ if span.kind == "cell":
4218
+ for tag in tags:
4219
+ if tag not in self.MT.tagged_cells:
4220
+ self.MT.tagged_cells[tag] = set()
4221
+ for r in rows:
4222
+ for c in cols:
4223
+ self.MT.tagged_cells[tag].add((r, c))
4224
+ elif span.kind == "row":
4225
+ for tag in tags:
4226
+ if tag not in self.MT.tagged_rows:
4227
+ self.MT.tagged_rows[tag] = set()
4228
+ self.MT.tagged_rows[tag].update(set(rows))
4229
+ elif span.kind == "column":
4230
+ for tag in tags:
4231
+ if tag not in self.MT.tagged_columns:
4232
+ self.MT.tagged_columns[tag] = set()
4233
+ self.MT.tagged_columns[tag].update(set(cols))
4234
+ return self
4235
+
4236
+ def tag_cell(
4237
+ self,
4238
+ cell: tuple[int, int],
4239
+ *tags,
4240
+ ) -> Sheet:
4241
+ if (
4242
+ not isinstance(cell, tuple)
4243
+ or not len(cell) == 2
4244
+ or not isinstance(cell[0], int)
4245
+ or not isinstance(cell[1], int)
4246
+ ):
4247
+ raise ValueError("'cell' argument must be tuple[int, int].")
4248
+ for tag in unpack(tags):
4249
+ if tag not in self.MT.tagged_cells:
4250
+ self.MT.tagged_cells[tag] = set()
4251
+ self.MT.tagged_cells[tag].add(cell)
4252
+ return self
4253
+
4254
+ def tag_rows(
4255
+ self,
4256
+ rows: int | Iterator[int],
4257
+ *tags,
4258
+ ) -> Sheet:
4259
+ if isinstance(rows, int):
4260
+ rows = [rows]
4261
+ for tag in unpack(tags):
4262
+ if tag not in self.MT.tagged_rows:
4263
+ self.MT.tagged_rows[tag] = set()
4264
+ self.MT.tagged_rows[tag].update(rows)
4265
+ return self
4266
+
4267
+ def tag_columns(
4268
+ self,
4269
+ columns: int | Iterator[int],
4270
+ *tags,
4271
+ ) -> Sheet:
4272
+ if isinstance(columns, int):
4273
+ columns = [columns]
4274
+ for tag in unpack(tags):
4275
+ if tag not in self.MT.tagged_columns:
4276
+ self.MT.tagged_columns[tag] = set()
4277
+ self.MT.tagged_columns[tag].update(columns)
4278
+ return self
4279
+
4280
+ def untag(
4281
+ self,
4282
+ cell: tuple[int, int] | None = None,
4283
+ rows: int | Iterator[int] | None = None,
4284
+ columns: int | Iterator[int] | None = None,
4285
+ ) -> Sheet:
4286
+ if isinstance(cell, tuple):
4287
+ for tagged in self.MT.tagged_cells.values():
4288
+ tagged.discard(cell)
4289
+ if isinstance(rows, int):
4290
+ rows = (rows,)
4291
+ if is_iterable(rows):
4292
+ for tagged in self.MT.tagged_rows.values():
4293
+ for row in rows:
4294
+ tagged.discard(row)
4295
+ if isinstance(columns, int):
4296
+ columns = (columns,)
4297
+ if is_iterable(columns):
4298
+ for tagged in self.MT.tagged_columns.values():
4299
+ for column in columns:
4300
+ tagged.discard(column)
4301
+ return self
4302
+
4303
+ def tag_del(
4304
+ self,
4305
+ *tags,
4306
+ cells: bool = True,
4307
+ rows: bool = True,
4308
+ columns: bool = True,
4309
+ ) -> Sheet:
4310
+ for tag in unpack(tags):
4311
+ if cells and tag in self.MT.tagged_cells:
4312
+ del self.MT.tagged_cells[tag]
4313
+ if rows and tag in self.MT.tagged_rows:
4314
+ del self.MT.tagged_rows[tag]
4315
+ if columns and tag in self.MT.tagged_columns:
4316
+ del self.MT.tagged_columns[tag]
4317
+ return self
4318
+
4319
+ def tag_has(
4320
+ self,
4321
+ *tags,
4322
+ ) -> DotDict:
4323
+ res = DotDict(
4324
+ cells=set(),
4325
+ rows=set(),
4326
+ columns=set(),
4327
+ )
4328
+ for tag in unpack(tags):
4329
+ res.cells.update(self.MT.tagged_cells[tag] if tag in self.MT.tagged_cells else set())
4330
+ res.rows.update(self.MT.tagged_rows[tag] if tag in self.MT.tagged_rows else set())
4331
+ res.columns.update(self.MT.tagged_columns[tag] if tag in self.MT.tagged_columns else set())
4332
+ return res
4333
+
4334
+ # Treeview Mode
4335
+
4336
+ def tree_build(
4337
+ self,
4338
+ data: list[list[object]],
4339
+ iid_column: int,
4340
+ parent_column: int,
4341
+ ) -> Sheet:
4342
+ tally_of_ids = defaultdict(lambda: -1)
4343
+ ncols = max(map(len, data), default=0)
4344
+ for rn, row in enumerate(data):
4345
+ if ncols > (lnr := len(row)):
4346
+ row += self.MT.get_empty_row_seq(rn, end=ncols, start=lnr)
4347
+ iid, pid = row[iid_column].lower(), row[parent_column].lower()
4348
+ if not iid:
4349
+ continue
4350
+ tally_of_ids[iid] += 1
4351
+ if tally_of_ids[iid] > 0:
4352
+ x = 1
4353
+ while iid in tally_of_ids:
4354
+ new = f"{row[iid_column]}_DUPLICATED_{x}"
4355
+ iid = new.lower()
4356
+ x += 1
4357
+ tally_of_ids[iid] += 1
4358
+ row[iid_column] = new
4359
+ if iid not in self.RI.tree:
4360
+ self.RI.tree[iid] = Node(row[iid_column], iid, "")
4361
+ if iid == pid or self.RI.pid_causes_recursive_loop(iid, pid):
4362
+ row[parent_column] = ""
4363
+ pid = ""
4364
+ if pid:
4365
+ if pid not in self.RI.tree:
4366
+ self.RI.tree[pid] = Node(row[parent_column], pid)
4367
+ self.RI.tree[iid].parent = self.RI.tree[pid]
4368
+ self.RI.tree[pid].children.append(self.RI.tree[iid])
4369
+ else:
4370
+ self.RI.tree[iid].parent = ""
4371
+ self.RI.tree_rns[iid] = rn
4372
+ for n in self.RI.tree.values():
4373
+ if n.parent is None:
4374
+ n.parent = ""
4375
+ newrow = self.MT.get_empty_row_seq(len(data), ncols)
4376
+ newrow[iid_column] = n.text
4377
+ self.RI.tree_rns[n.iid] = len(data)
4378
+ data.append(newrow)
4379
+ self.insert_rows(
4380
+ idx=0,
4381
+ rows=[[self.RI.tree[iid]] + data[self.RI.tree_rns[iid]] for iid in self.get_children()],
4382
+ row_index=True,
4383
+ create_selections=False,
4384
+ fill=False,
4385
+ )
4386
+ self.RI.tree_rns = {n.iid: i for i, n in enumerate(self.MT._row_index)}
4387
+ self.hide_rows(
4388
+ set(self.RI.tree_rns[iid] for iid in self.get_children() if self.RI.tree[iid].parent),
4389
+ deselect_all=True,
4390
+ data_indexes=True,
4391
+ )
4392
+ return self
4393
+
4394
+ def insert(
4395
+ self,
4396
+ parent: str = "",
4397
+ index: None | int | Literal["end"] = None,
4398
+ iid: None | str = None,
4399
+ text: None | str = None,
4400
+ values: None | list = None,
4401
+ create_selections: bool = False,
4402
+ ) -> str:
4403
+ if iid is None:
4404
+ i = 0
4405
+ while (iid := f"{i}") in self.RI.tree:
4406
+ i += 1
4407
+ iid, pid = iid.lower(), parent.lower()
4408
+ if not iid:
4409
+ raise ValueError("iid cannot be empty string.")
4410
+ if iid in self.RI.tree:
4411
+ raise ValueError(f"iid '{iid}' already exists.")
4412
+ if iid == pid:
4413
+ raise ValueError(f"iid '{iid}' cannot be equal to parent '{pid}'.")
4414
+ if pid and pid not in self.RI.tree:
4415
+ raise ValueError(f"parent '{parent}' does not exist.")
4416
+ if text is None:
4417
+ text = iid
4418
+ parent_node = self.RI.tree[pid] if parent else ""
4419
+ self.RI.tree[iid] = Node(text, iid, parent_node)
4420
+ if self.RI.pid_causes_recursive_loop(iid, pid):
4421
+ del self.RI.tree[iid]
4422
+ raise ValueError(f"iid '{iid}' causes a recursive loop with parent '{parent}'.")
4423
+ if parent_node:
4424
+ if isinstance(index, int):
4425
+ idx = self.RI.tree_rns[pid] + index + 1
4426
+ for count, cid in enumerate(self.get_children(pid)):
4427
+ if count >= index:
4428
+ break
4429
+ idx += sum(1 for _ in self.RI.get_iid_descendants(cid))
4430
+ self.RI.tree[pid].children.insert(index, self.RI.tree[iid])
4431
+ else:
4432
+ idx = self.RI.tree_rns[pid] + sum(1 for _ in self.RI.get_iid_descendants(pid)) + 1
4433
+ self.RI.tree[pid].children.append(self.RI.tree[iid])
4434
+ else:
4435
+ if isinstance(index, int):
4436
+ idx = index
4437
+ if index:
4438
+ for count, cid in enumerate(self.get_children("")):
4439
+ if count >= index:
4440
+ break
4441
+ idx += sum(1 for _ in self.RI.get_iid_descendants(cid)) + 1
4442
+ else:
4443
+ idx = len(self.MT._row_index)
4444
+ self.insert_rows(
4445
+ idx=idx,
4446
+ rows=[[self.RI.tree[iid]] + [] if values is None else values],
4447
+ row_index=True,
4448
+ create_selections=create_selections,
4449
+ fill=False,
4450
+ )
4451
+ self.RI.tree_rns[iid] = idx
4452
+ if pid and (pid not in self.RI.tree_open_ids or not self.item_displayed(pid)):
4453
+ self.hide_rows(idx, deselect_all=False, data_indexes=True)
4454
+ return iid
4455
+
4456
+ def item(
4457
+ self,
4458
+ item: str,
4459
+ iid: str | None = None,
4460
+ text: str | None = None,
4461
+ values: list | None = None,
4462
+ open_: bool | None = None,
4463
+ ) -> DotDict:
4464
+ if not (item := item.lower()) or item not in self.RI.tree:
4465
+ raise ValueError(f"Item '{item}' does not exist.")
4466
+ if isinstance(iid, str):
4467
+ if not (iid := iid.lower()):
4468
+ raise ValueError(f"iid '{iid}' does not exist.")
4469
+ if iid in self.RI.tree:
4470
+ raise ValueError(f"Cannot rename '{iid}', it already exists.")
4471
+ iid = iid.lower()
4472
+ self.RI.tree[item].iid = iid
4473
+ self.RI.tree[iid] = self.RI.tree.pop(item)
4474
+ self.RI.tree_rns[iid] = self.RI.tree_rns.pop(item)
4475
+ if iid in self.RI.tree_open_ids:
4476
+ self.RI.tree_open_ids[iid] = self.RI.tree_open_ids.pop(item)
4477
+ if isinstance(text, str):
4478
+ self.RI.tree[item].text = text
4479
+ if isinstance(values, list):
4480
+ self.set_data(self.RI.tree_rns[item], values)
4481
+ if isinstance(open_, bool):
4482
+ if not self.RI.tree[item].children or not open_:
4483
+ self.RI.tree_open_ids.discard(item)
4484
+ if open_:
4485
+ self.RI.tree_open_ids.add(item)
4486
+ self.show_rows(
4487
+ (self.RI.tree_rns[did] for did in self.RI.get_iid_descendants(item, check_open=True)),
4488
+ redraw=False,
4489
+ deselect_all=False,
4490
+ )
4491
+ elif self.RI.tree[item].children:
4492
+ self.hide_rows(
4493
+ (self.RI.tree_rns[did] for did in self.RI.get_iid_descendants(item)),
4494
+ redraw=False,
4495
+ deselect_all=False,
4496
+ data_indexes=True,
4497
+ )
4498
+ self.set_refresh_timer(isinstance(text, str) or isinstance(values, list) or isinstance(open_, bool))
4499
+ return DotDict(
4500
+ text=self.RI.tree[item].text,
4501
+ values=self[self.RI.tree_rns[item]].options(ndim=1).data,
4502
+ open_=item in self.RI.tree_open_ids,
4503
+ )
4504
+
4505
+ def itemrow(self, item: str) -> int:
4506
+ return self.RI.tree_rns[item.lower()]
4507
+
4508
+ def rowitem(self, row: int) -> str | None:
4509
+ if len(self.MT._row_index) > row:
4510
+ return self.MT._row_index[row].iid
4511
+ return None
4512
+
4513
+ def get_children(self, item: None | str = None) -> Generator[str]:
4514
+ if item is None:
4515
+ for n in self.RI.tree.values():
4516
+ if not n.parent:
4517
+ yield n.iid
4518
+ for iid in self.RI.get_iid_descendants(n.iid):
4519
+ yield iid
4520
+ elif item == "":
4521
+ yield from (n.iid for n in self.RI.tree.values() if not n.parent)
4522
+ else:
4523
+ yield from (n.iid for n in self.RI.tree[item].children)
4524
+
4525
+ def reset_tree(self) -> Sheet:
4526
+ self.deselect()
4527
+ self.RI.reset_tree()
4528
+ return self
4529
+
4530
+ def del_items(self, *items) -> Sheet:
4531
+ """
4532
+ Also deletes all descendants of items
4533
+ """
4534
+ rows_to_del = []
4535
+ iids_to_del = []
4536
+ for item in unpack(items):
4537
+ item = item.lower()
4538
+ if item not in self.RI.tree:
4539
+ continue
4540
+ rows_to_del.append(self.RI.tree_rns[item])
4541
+ iids_to_del.append(item)
4542
+ for did in self.RI.get_iid_descendants(item):
4543
+ rows_to_del.append(self.RI.tree_rns[did])
4544
+ iids_to_del.append(did)
4545
+ for item in unpack(items):
4546
+ self.RI.remove_node_from_parents_children(self.RI.tree[item])
4547
+ self.del_rows(rows_to_del)
4548
+ for iid in iids_to_del:
4549
+ self.RI.tree_open_ids.discard(iid)
4550
+ if self.RI.tree[iid].parent and len(self.RI.tree[iid].parent.children) == 1:
4551
+ self.RI.tree_open_ids.discard(self.RI.tree[iid].parent.iid)
4552
+ del self.RI.tree[iid]
4553
+ self.set_refresh_timer(True)
4554
+ return self
4555
+
4556
+ def set_children(self, item: str, *newchildren) -> Sheet:
4557
+ """
4558
+ Moves everything in '*newchildren' under 'item'
4559
+ """
4560
+ if (item := item.lower()) and item not in self.RI.tree:
4561
+ raise ValueError(f"Item '{item}' does not exist.")
4562
+ mapping = {}
4563
+ to_show = []
4564
+ if item:
4565
+ new_parent = self.RI.tree[item]
4566
+ if new_parent.children:
4567
+ ctr = self.RI.tree_rns[new_parent.children[-1].iid] + 1
4568
+ else:
4569
+ ctr = self.RI.tree_rns[new_parent.iid] + 1
4570
+ for cid in unpack(newchildren):
4571
+ if self.RI.pid_causes_recursive_loop(cid, item):
4572
+ raise ValueError(f"iid '{cid}' causes a recursive loop with parent '{item}'.")
4573
+ cid_node = self.RI.tree[cid]
4574
+ mapping[self.RI.tree_rns[cid]] = ctr
4575
+ if item in self.RI.tree_open_ids and self.item_displayed(item):
4576
+ to_show.append(ctr)
4577
+ ctr += 1
4578
+ for did in self.RI.get_iid_descendants(cid):
4579
+ mapping[self.RI.tree_rns[did]] = ctr
4580
+ if to_show and self.RI.ancestors_all_open(did, self.RI.tree[cid].parent):
4581
+ to_show.append(ctr)
4582
+ ctr += 1
4583
+ self.RI.remove_node_from_parents_children(cid_node)
4584
+ cid_node.parent = new_parent
4585
+ new_parent.children.append(cid_node)
4586
+ else:
4587
+ ctr = (
4588
+ len(self.MT._row_index)
4589
+ - len(newchildren)
4590
+ - sum(1 for cid in unpack(newchildren) for _ in self.RI.get_iid_descendants(cid))
4591
+ )
4592
+ for cid in unpack(newchildren):
4593
+ cid_node = self.RI.tree[cid]
4594
+ mapping[self.RI.tree_rns[cid]] = ctr
4595
+ to_show.append(ctr)
4596
+ ctr += 1
4597
+ for did in self.RI.get_iid_descendants(cid):
4598
+ mapping[self.RI.tree_rns[did]] = ctr
4599
+ if self.RI.ancestors_all_open(did, cid_node.parent):
4600
+ to_show.append(ctr)
4601
+ ctr += 1
4602
+ self.RI.remove_node_from_parents_children(cid_node)
4603
+ self.RI.tree[cid].parent = ""
4604
+ self.mapping_move_rows(
4605
+ data_new_idxs=mapping,
4606
+ data_indexes=True,
4607
+ create_selections=False,
4608
+ redraw=False,
4609
+ )
4610
+ if item and (item not in self.RI.tree_open_ids or not self.item_displayed(item)):
4611
+ self.hide_rows(set(mapping.values()), data_indexes=True)
4612
+ self.show_rows(to_show)
4613
+ self.set_refresh_timer(True)
4614
+ return self
4615
+
4616
+ def move(self, item: str, parent: str, index: int = 0) -> Sheet:
4617
+ """
4618
+ Moves item to be under parent as child at index
4619
+ 'parent' can be empty string which will make item a top node
4620
+ """
4621
+ if (item := item.lower()) and item not in self.RI.tree:
4622
+ raise ValueError(f"Item '{item}' does not exist.")
4623
+ if (parent := parent.lower()) and parent not in self.RI.tree:
4624
+ raise ValueError(f"Parent '{parent}' does not exist.")
4625
+ mapping = {}
4626
+ to_show = []
4627
+ item_node = self.RI.tree[item]
4628
+ if parent:
4629
+ if self.RI.pid_causes_recursive_loop(item, parent):
4630
+ raise ValueError(f"iid '{item}' causes a recursive loop with parent '{parent}'.")
4631
+ parent_node = self.RI.tree[parent]
4632
+ if parent_node.children:
4633
+ if len(parent_node.children) < index:
4634
+ index = len(parent_node.children)
4635
+ ctr = self.RI.tree_rns[parent_node.children[index].iid]
4636
+ else:
4637
+ ctr = self.RI.tree_rns[parent_node.iid] + 1
4638
+ mapping[self.RI.tree_rns[item]] = ctr
4639
+ if parent in self.RI.tree_open_ids and self.item_displayed(parent):
4640
+ to_show.append(ctr)
4641
+ ctr += 1
4642
+ for did in self.RI.get_iid_descendants(item):
4643
+ mapping[self.RI.tree_rns[did]] = ctr
4644
+ if to_show and self.RI.ancestors_all_open(did, item_node.parent):
4645
+ to_show.append(ctr)
4646
+ ctr += 1
4647
+ self.RI.remove_node_from_parents_children(item_node)
4648
+ item_node.parent = parent_node
4649
+ parent_node.children.append(item_node)
4650
+ else:
4651
+ if len(self.MT._row_index) < index:
4652
+ index = len(self.MT._row_index)
4653
+ ctr = index
4654
+ mapping[self.RI.tree_rns[item]] = ctr
4655
+ to_show.append(ctr)
4656
+ ctr += 1
4657
+ for did in self.RI.get_iid_descendants(item):
4658
+ mapping[self.RI.tree_rns[did]] = ctr
4659
+ if to_show and self.RI.ancestors_all_open(did, item_node.parent):
4660
+ to_show.append(ctr)
4661
+ ctr += 1
4662
+ self.RI.remove_node_from_parents_children(item_node)
4663
+ self.RI.tree[item].parent = ""
4664
+ self.mapping_move_rows(
4665
+ data_new_idxs=mapping,
4666
+ data_indexes=True,
4667
+ create_selections=False,
4668
+ redraw=False,
4669
+ )
4670
+ if parent and (parent not in self.RI.tree_open_ids or not self.item_displayed(parent)):
4671
+ self.hide_rows(set(mapping.values()), data_indexes=True)
4672
+ self.show_rows(to_show)
4673
+ self.set_refresh_timer(True)
4674
+ return self
4675
+
4676
+ reattach = move
4677
+
4678
+ def exists(self, item: str) -> bool:
4679
+ return item in self.RI.tree
4680
+
4681
+ def parent(self, item: str) -> str:
4682
+ if (item := item.lower()) not in self.RI.tree:
4683
+ raise ValueError(f"Item '{item}' does not exist.")
4684
+ return self.RI.tree[item].parent.iid if self.RI.tree[item].parent else self.RI.tree[item].parent
4685
+
4686
+ def index(self, item: str) -> int:
4687
+ if (item := item.lower()) not in self.RI.tree:
4688
+ raise ValueError(f"Item '{item}' does not exist.")
4689
+ if not self.RI.tree[item].parent:
4690
+ return sorted(self.RI.tree_rns[iid] for iid in self.get_children("")).index(self.RI.tree_rns[item])
4691
+ return self.RI.tree[item].parent.children.index(self.RI.tree[item])
4692
+
4693
+ def item_displayed(self, item: str) -> bool:
4694
+ """
4695
+ Check if an item (row) is currently displayed on the sheet
4696
+ - Does not check if the item is visible to the user
4697
+ """
4698
+ if (item := item.lower()) not in self.RI.tree:
4699
+ raise ValueError(f"Item '{item}' does not exist.")
4700
+ return self.RI.tree_rns[item] in self.MT.displayed_rows
4701
+
4702
+ def display_item(self, item: str) -> Sheet:
4703
+ """
4704
+ Ensure that item is displayed in the tree
4705
+ - Opens all of an item's ancestors
4706
+ - Unlike the ttk treeview 'see' function
4707
+ this function does **NOT** scroll to the item
4708
+ """
4709
+ if (item := item.lower()) not in self.RI.tree:
4710
+ raise ValueError(f"Item '{item}' does not exist.")
4711
+ if self.RI.tree[item].parent:
4712
+ for iid in self.RI.get_iid_ancestors(item):
4713
+ self.item(iid, open_=True)
4714
+
4715
+ def scroll_to_item(self, item: str) -> Sheet:
4716
+ """
4717
+ Scrolls to an item and ensures that it is displayed
4718
+ """
4719
+ if (item := item.lower()) not in self.RI.tree:
4720
+ raise ValueError(f"Item '{item}' does not exist.")
4721
+ self.display_item(item)
4722
+ self.see(row=bisect_left(self.MT.displayed_rows, self.RI.tree_rns[item]), keep_xscroll=True)
4723
+
4724
+ def selection(self) -> list[str]:
4725
+ """
4726
+ Get currently selected item ids
4727
+ - Only includes selected rows
4728
+ """
4729
+ return [self.MT._row_index[self.displayed_row_to_data(rn)].iid for rn in self.get_selected_rows()]
4730
+
4731
+ def selection_set(self, *items) -> Sheet:
4732
+ self.deselect()
4733
+ self.selection_add(*items)
4734
+ return self
4735
+
4736
+ def selection_add(self, *items) -> Sheet:
4737
+ for item in unpack(items):
4738
+ if (item := item.lower()) not in self.RI.tree:
4739
+ raise ValueError(f"Item '{item}' does not exist.")
4740
+ if not self.item_displayed(item):
4741
+ self.display_item(item)
4742
+ self.add_row_selection(bisect_left(self.MT.displayed_rows, self.RI.tree_rns[item]))
4743
+ return self
4744
+
4745
+ def selection_remove(self, *items) -> Sheet:
4746
+ for item in unpack(items):
4747
+ if (item := item.lower()) not in self.RI.tree:
4748
+ raise ValueError(f"Item '{item}' does not exist.")
4749
+ try:
4750
+ self.deselect(bisect_left(self.MT.displayed_rows, self.RI.tree_rns[item]))
4751
+ except Exception:
4752
+ continue
4753
+ return self
4754
+
4755
+ def selection_toggle(self, *items) -> Sheet:
4756
+ selected = set(self.MT._row_index[self.displayed_row_to_data(rn)].iid for rn in self.get_selected_rows())
4757
+ add = []
4758
+ remove = []
4759
+ for item in unpack(items):
4760
+ if (item := item.lower()) not in self.RI.tree:
4761
+ continue
4762
+ if item in selected:
4763
+ remove.append(item)
4764
+ else:
4765
+ add.append(item)
4766
+ self.selection_remove(*remove)
4767
+ self.selection_add(*add)
4768
+ return self
4769
+
3949
4770
  # Functions not in docs
3950
4771
 
3951
4772
  def emit_event(
@@ -3983,10 +4804,10 @@ class Sheet(tk.Frame):
3983
4804
  table, index, header = span.table, span.index, span.header
3984
4805
  # index header
3985
4806
  if header and span.kind in ("cell", "column"):
3986
- self.CH.destroy_opened_dropdown_window()
4807
+ self.CH.hide_dropdown_window()
3987
4808
  del_from_options(self.CH.cell_options, key, cols)
3988
4809
  if index and span.kind in ("cell", "row"):
3989
- self.RI.destroy_opened_dropdown_window()
4810
+ self.RI.hide_dropdown_window()
3990
4811
  del_from_options(self.RI.cell_options, key, rows)
3991
4812
  # table
3992
4813
  if table and span.kind == "cell":
@@ -4001,7 +4822,7 @@ class Sheet(tk.Frame):
4001
4822
  # ########## TABLE ##########
4002
4823
 
4003
4824
  def del_cell_options_dropdown(self, datarn: int, datacn: int) -> None:
4004
- self.MT.destroy_opened_dropdown_window()
4825
+ self.MT.hide_dropdown_window()
4005
4826
  if (datarn, datacn) in self.MT.cell_options and "dropdown" in self.MT.cell_options[(datarn, datacn)]:
4006
4827
  del self.MT.cell_options[(datarn, datacn)]["dropdown"]
4007
4828
 
@@ -4014,7 +4835,7 @@ class Sheet(tk.Frame):
4014
4835
  self.del_cell_options_checkbox(datarn, datacn)
4015
4836
 
4016
4837
  def del_row_options_dropdown(self, datarn: int) -> None:
4017
- self.MT.destroy_opened_dropdown_window()
4838
+ self.MT.hide_dropdown_window()
4018
4839
  if datarn in self.MT.row_options and "dropdown" in self.MT.row_options[datarn]:
4019
4840
  del self.MT.row_options[datarn]["dropdown"]
4020
4841
 
@@ -4027,7 +4848,7 @@ class Sheet(tk.Frame):
4027
4848
  self.del_row_options_checkbox(datarn)
4028
4849
 
4029
4850
  def del_column_options_dropdown(self, datacn: int) -> None:
4030
- self.MT.destroy_opened_dropdown_window()
4851
+ self.MT.hide_dropdown_window()
4031
4852
  if datacn in self.MT.col_options and "dropdown" in self.MT.col_options[datacn]:
4032
4853
  del self.MT.col_options[datacn]["dropdown"]
4033
4854
 
@@ -4042,7 +4863,7 @@ class Sheet(tk.Frame):
4042
4863
  # ########## INDEX ##########
4043
4864
 
4044
4865
  def del_index_cell_options_dropdown(self, datarn: int) -> None:
4045
- self.RI.destroy_opened_dropdown_window(datarn=datarn)
4866
+ self.RI.hide_dropdown_window()
4046
4867
  if datarn in self.RI.cell_options and "dropdown" in self.RI.cell_options[datarn]:
4047
4868
  del self.RI.cell_options[datarn]["dropdown"]
4048
4869
 
@@ -4057,7 +4878,7 @@ class Sheet(tk.Frame):
4057
4878
  # ########## HEADER ##########
4058
4879
 
4059
4880
  def del_header_cell_options_dropdown(self, datacn: int) -> None:
4060
- self.CH.destroy_opened_dropdown_window(datacn=datacn)
4881
+ self.CH.hide_dropdown_window()
4061
4882
  if datacn in self.CH.cell_options and "dropdown" in self.CH.cell_options[datacn]:
4062
4883
  del self.CH.cell_options[datacn]["dropdown"]
4063
4884
 
@@ -4390,13 +5211,11 @@ class Sheet(tk.Frame):
4390
5211
 
4391
5212
  def dehighlight_rows(
4392
5213
  self,
4393
- rows: list | str = [],
5214
+ rows: list[int] | Literal["all"] = [],
4394
5215
  redraw: bool = True,
4395
5216
  ) -> None:
4396
5217
  if isinstance(rows, int):
4397
5218
  rows = [rows]
4398
- else:
4399
- rows = rows
4400
5219
  if not rows or rows == "all":
4401
5220
  for r in self.MT.row_options:
4402
5221
  if "highlight" in self.MT.row_options[r]:
@@ -4417,11 +5236,13 @@ class Sheet(tk.Frame):
4417
5236
  pass
4418
5237
  self.set_refresh_timer(redraw)
4419
5238
 
4420
- def dehighlight_columns(self, columns: list | str = [], redraw: bool = True) -> None:
5239
+ def dehighlight_columns(
5240
+ self,
5241
+ columns: list[int] | Literal["all"] = [],
5242
+ redraw: bool = True,
5243
+ ) -> None:
4421
5244
  if isinstance(columns, int):
4422
5245
  columns = [columns]
4423
- else:
4424
- columns = columns
4425
5246
  if not columns or columns == "all":
4426
5247
  for c in self.MT.col_options:
4427
5248
  if "highlight" in self.MT.col_options[c]:
@@ -4444,7 +5265,7 @@ class Sheet(tk.Frame):
4444
5265
 
4445
5266
  def highlight_rows(
4446
5267
  self,
4447
- rows: list = [],
5268
+ rows: Iterator[int] | int,
4448
5269
  bg: None | str = None,
4449
5270
  fg: None | str = None,
4450
5271
  highlight_index: bool = True,
@@ -4462,7 +5283,7 @@ class Sheet(tk.Frame):
4462
5283
 
4463
5284
  def highlight_columns(
4464
5285
  self,
4465
- columns: list = [],
5286
+ columns: Iterator[int] | int,
4466
5287
  bg: bool | None | str = False,
4467
5288
  fg: bool | None | str = False,
4468
5289
  highlight_header: bool = True,
@@ -4924,26 +5745,17 @@ class Sheet(tk.Frame):
4924
5745
  return self
4925
5746
 
4926
5747
  def get_checkboxes(self) -> dict:
4927
- d = {
5748
+ return {
4928
5749
  **{k: v["checkbox"] for k, v in self.MT.cell_options.items() if "checkbox" in v},
4929
5750
  **{k: v["checkbox"] for k, v in self.MT.row_options.items() if "checkbox" in v},
4930
5751
  **{k: v["checkbox"] for k, v in self.MT.col_options.items() if "checkbox" in v},
4931
5752
  }
4932
- if "checkbox" in self.MT.options:
4933
- return {**d, "checkbox": self.MT.options["checkbox"]}
4934
- return d
4935
5753
 
4936
5754
  def get_header_checkboxes(self) -> dict:
4937
- d = {k: v["checkbox"] for k, v in self.CH.cell_options.items() if "checkbox" in v}
4938
- if "checkbox" in self.CH.options:
4939
- return {**d, "checkbox": self.CH.options["checkbox"]}
4940
- return d
5755
+ return {k: v["checkbox"] for k, v in self.CH.cell_options.items() if "checkbox" in v}
4941
5756
 
4942
5757
  def get_index_checkboxes(self) -> dict:
4943
- d = {k: v["checkbox"] for k, v in self.RI.cell_options.items() if "checkbox" in v}
4944
- if "checkbox" in self.RI.options:
4945
- return {**d, "checkbox": self.RI.options["checkbox"]}
4946
- return d
5758
+ return {k: v["checkbox"] for k, v in self.RI.cell_options.items() if "checkbox" in v}
4947
5759
 
4948
5760
  def create_dropdown(
4949
5761
  self,
@@ -5190,9 +6002,8 @@ class Sheet(tk.Frame):
5190
6002
  set_value: object = None,
5191
6003
  ) -> Sheet:
5192
6004
  if set_existing_dropdown:
5193
- if self.MT.existing_dropdown_window is not None:
5194
- r_ = self.MT.existing_dropdown_window.r
5195
- c_ = self.MT.existing_dropdown_window.c
6005
+ if self.MT.dropdown.open:
6006
+ r_, c_ = self.MT.dropdown.get_coords()
5196
6007
  else:
5197
6008
  raise Exception("No dropdown box is currently open")
5198
6009
  else:
@@ -5200,16 +6011,12 @@ class Sheet(tk.Frame):
5200
6011
  c_ = c
5201
6012
  kwargs = self.MT.get_cell_kwargs(r, c, key="dropdown")
5202
6013
  kwargs["values"] = values
5203
- if kwargs["window"] != "no dropdown open":
5204
- kwargs["window"].values(values)
6014
+ if self.MT.dropdown.open:
6015
+ self.MT.dropdown.window.values(values)
5205
6016
  if set_value is not None:
5206
6017
  self.set_cell_data(r_, c_, set_value)
5207
- if (
5208
- kwargs["window"] != "no dropdown open"
5209
- and self.MT.text_editor_loc is not None
5210
- and self.MT.text_editor is not None
5211
- ):
5212
- self.MT.text_editor.set_text(set_value)
6018
+ if self.MT.dropdown.open:
6019
+ self.MT.text_editor.window.set_text(set_value)
5213
6020
  return self
5214
6021
 
5215
6022
  def set_header_dropdown_values(
@@ -5220,8 +6027,8 @@ class Sheet(tk.Frame):
5220
6027
  set_value: object = None,
5221
6028
  ) -> Sheet:
5222
6029
  if set_existing_dropdown:
5223
- if self.CH.existing_dropdown_window is not None:
5224
- c_ = self.CH.existing_dropdown_window.c
6030
+ if self.CH.dropdown.open:
6031
+ c_ = self.CH.dropdown.get_coords()
5225
6032
  else:
5226
6033
  raise Exception("No dropdown box is currently open")
5227
6034
  else:
@@ -5229,10 +6036,11 @@ class Sheet(tk.Frame):
5229
6036
  kwargs = self.CH.get_cell_kwargs(c_, key="dropdown")
5230
6037
  if kwargs:
5231
6038
  kwargs["values"] = values
5232
- if kwargs["window"] != "no dropdown open":
5233
- kwargs["window"].values(values)
6039
+ if self.CH.dropdown.open:
6040
+ self.CH.dropdown.window.values(values)
5234
6041
  if set_value is not None:
5235
6042
  self.MT.headers(newheaders=set_value, index=c_)
6043
+
5236
6044
  return self
5237
6045
 
5238
6046
  def set_index_dropdown_values(
@@ -5243,8 +6051,8 @@ class Sheet(tk.Frame):
5243
6051
  set_value: object = None,
5244
6052
  ) -> Sheet:
5245
6053
  if set_existing_dropdown:
5246
- if self.RI.existing_dropdown_window is not None:
5247
- r_ = self.RI.existing_dropdown_window.r
6054
+ if self.RI.current_dropdown_window is not None:
6055
+ r_ = self.RI.current_dropdown_window.r
5248
6056
  else:
5249
6057
  raise Exception("No dropdown box is currently open")
5250
6058
  else:
@@ -5252,10 +6060,11 @@ class Sheet(tk.Frame):
5252
6060
  kwargs = self.RI.get_cell_kwargs(r_, key="dropdown")
5253
6061
  if kwargs:
5254
6062
  kwargs["values"] = values
5255
- if kwargs["window"] != "no dropdown open":
5256
- kwargs["window"].values(values)
6063
+ if self.RI.current_dropdown_window is not None:
6064
+ self.RI.current_dropdown_window.values(values)
5257
6065
  if set_value is not None:
5258
6066
  self.MT.row_index(newindex=set_value, index=r_)
6067
+ # here
5259
6068
  return self
5260
6069
 
5261
6070
  def get_dropdown_values(self, r: int = 0, c: int = 0) -> None | list:
@@ -5469,7 +6278,7 @@ class Dropdown(Sheet):
5469
6278
  parent: tk.Misc,
5470
6279
  r: int,
5471
6280
  c: int,
5472
- colors: dict[str, str],
6281
+ ops: dict,
5473
6282
  outline_color: str,
5474
6283
  width: int | None = None,
5475
6284
  height: int | None = None,
@@ -5481,7 +6290,9 @@ class Dropdown(Sheet):
5481
6290
  arrowkey_RIGHT: Callable | None = None,
5482
6291
  arrowkey_LEFT: Callable | None = None,
5483
6292
  align: str = "w",
5484
- # False for using r, c "r" for r "c" for c
6293
+ # False for using r, c
6294
+ # "r" for r
6295
+ # "c" for c
5485
6296
  single_index: str | bool = False,
5486
6297
  ) -> None:
5487
6298
  Sheet.__init__(
@@ -5489,7 +6300,7 @@ class Dropdown(Sheet):
5489
6300
  parent=parent,
5490
6301
  outline_thickness=outline_thickness,
5491
6302
  outline_color=outline_color,
5492
- table_grid_fg=colors["fg"],
6303
+ table_grid_fg=ops.popup_menu_fg,
5493
6304
  show_horizontal_grid=True,
5494
6305
  show_vertical_grid=False,
5495
6306
  show_header=False,
@@ -5503,24 +6314,23 @@ class Dropdown(Sheet):
5503
6314
  horizontal_grid_to_end_of_window=True,
5504
6315
  set_cell_sizes_on_zoom=True,
5505
6316
  show_selected_cells_border=False,
5506
- table_selected_cells_border_fg=colors["fg"],
5507
- table_selected_cells_bg=colors["highlight_bg"],
5508
- table_selected_rows_border_fg=colors["fg"],
5509
- table_selected_rows_bg=colors["highlight_bg"],
5510
- table_selected_rows_fg=colors["highlight_fg"],
6317
+ table_selected_cells_border_fg=ops.popup_menu_fg,
6318
+ table_selected_cells_bg=ops.popup_menu_highlight_bg,
6319
+ table_selected_rows_border_fg=ops.popup_menu_fg,
6320
+ table_selected_rows_bg=ops.popup_menu_highlight_bg,
6321
+ table_selected_rows_fg=ops.popup_menu_highlight_fg,
5511
6322
  width=width,
5512
6323
  height=height,
5513
6324
  font=font if font else self.ops.table_font,
5514
- table_fg=colors["fg"],
5515
- table_bg=colors["bg"],
6325
+ table_fg=ops.popup_menu_fg,
6326
+ table_bg=ops.popup_menu_bg,
6327
+ **{k: ops[k] for k in scrollbar_options_keys},
5516
6328
  )
5517
6329
  self.parent = parent
5518
6330
  self.close_dropdown_window = close_dropdown_window
5519
6331
  self.search_function = search_function
5520
6332
  self.arrowkey_RIGHT = arrowkey_RIGHT
5521
6333
  self.arrowkey_LEFT = arrowkey_LEFT
5522
- self.h_ = height
5523
- self.w_ = width
5524
6334
  self.r = r
5525
6335
  self.c = c
5526
6336
  self.row = -1
@@ -5599,6 +6409,13 @@ class Dropdown(Sheet):
5599
6409
  else:
5600
6410
  self.close_dropdown_window(self.r, self.c, self.get_cell_data(row, 0))
5601
6411
 
6412
+ def get_coords(self) -> int | tuple[int, int]:
6413
+ if self.single_index == "r":
6414
+ return self.r
6415
+ elif self.single_index == "c":
6416
+ return self.c
6417
+ return self.r, self.c
6418
+
5602
6419
  def values(self, values: list = [], redraw: bool = True) -> None:
5603
6420
  self.set_sheet_data(
5604
6421
  [[v] for v in values],