From d911a2ad7a1b833d1510ca3fe84851a2c8d0c0d3 Mon Sep 17 00:00:00 2001 From: ragardner Date: Thu, 1 Aug 2024 15:01:45 +0100 Subject: [PATCH] 7.2.12 -> 7.2.13 #### Fixed: - [245](https://github.com/ragardner/tksheet/issues/245) #### Changed: - Moved variable `default_index` to sheet options as `default_row_index` - Moved variable `default_header` to sheet options #### Improved: - Documentation --- docs/CHANGELOG.md | 11 ++++++ docs/DOCUMENTATION.md | 17 ++++++++- pyproject.toml | 2 +- tksheet/__init__.py | 1 + tksheet/column_headers.py | 3 +- tksheet/functions.py | 11 +++++- tksheet/main_table.py | 4 +- tksheet/row_index.py | 80 ++++++++++++++++++++++----------------- tksheet/sheet.py | 42 +++++++++++++------- tksheet/sheet_options.py | 2 + tksheet/text_editor.py | 2 +- 11 files changed, 118 insertions(+), 57 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index a5c03f4..ecc7d6f 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,3 +1,14 @@ +### Version 7.2.13 +#### Fixed: +- [245](https://github.com/ragardner/tksheet/issues/245) + +#### Changed: +- Moved variable `default_index` to sheet options as `default_row_index` +- Moved variable `default_header` to sheet options + +#### Improved: +- Documentation + ### Version 7.2.12 #### Pull Requests: - [237](https://github.com/ragardner/tksheet/pull/237) diff --git a/docs/DOCUMENTATION.md b/docs/DOCUMENTATION.md index ee0bcec..9f8f3ea 100644 --- a/docs/DOCUMENTATION.md +++ b/docs/DOCUMENTATION.md @@ -3941,9 +3941,15 @@ get_column_alignments() -> dict --- # **Getting Selected Cells** +All selected cell/box getting functions return or generate **displayed** cell coordinates. +- Displayed cell coordinates ignore hidden rows/columns when indexing cells. +- Data cell coordinates include hidden rows/columns in indexing cells. + #### **Get the currently selected cell** -This is always a single cell, the one, for example, in which the cell text editor opens when making single edits. +This is always a single cell of displayed indices. If you have hidden rows or columns you can change the integers to data indices using the following functions: +- [Change a row](https://github.com/ragardner/tksheet/wiki/Version-7#displayed-row-index-to-data) +- [Change a column](https://github.com/ragardner/tksheet/wiki/Version-7#displayed-column-index-to-data) ```python get_currently_selected() -> tuple | Selected @@ -3982,6 +3988,7 @@ get_selected_rows( return_tuple: bool = False, ) -> tuple[int] | tuple[tuple[int, int]] | set[int] | set[tuple[int, int]] ``` +- Returns displayed indexes. ___ @@ -3994,6 +4001,7 @@ get_selected_columns( return_tuple: bool = False, ) -> tuple[int] | tuple[tuple[int, int]] | set[int] | set[tuple[int, int]] ``` +- Returns displayed indexes. ___ @@ -4007,6 +4015,7 @@ get_selected_cells( sort_by_column: bool = False, ) -> list[tuple[int, int]] | set[tuple[int, int]] ``` +- Returns displayed coordinates. ___ @@ -4018,6 +4027,7 @@ gen_selected_cells( get_columns: bool = False, ) -> Generator[tuple[int, int]] ``` +- Generates displayed coordinates. ___ @@ -4026,6 +4036,7 @@ ___ ```python get_all_selection_boxes() -> tuple[tuple[int, int, int, int]] ``` +- Returns displayed coordinates. ___ @@ -4118,6 +4129,10 @@ get_selected_min_max() -> tuple[int, int, int, int] | tuple[None, None, None, No --- # **Modifying Selected Cells** +All selected cell/box setting functions use **displayed** cell coordinates. +- Displayed cell coordinates ignore hidden rows/columns when indexing cells. +- Data cell coordinates include hidden rows/columns in indexing cells. + ```python set_currently_selected(row: int | None = None, column: int | None = None) -> Sheet ``` diff --git a/pyproject.toml b/pyproject.toml index b7bdddd..1b359cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "tksheet" description = "Tkinter table / sheet widget" readme = "README.md" -version = "7.2.12" +version = "7.2.13" authors = [{ name = "ragardner", email = "github@ragardner.simplelogin.com" }] requires-python = ">=3.8" license = {file = "LICENSE.txt"} diff --git a/tksheet/__init__.py b/tksheet/__init__.py index 2cfbdee..7102283 100644 --- a/tksheet/__init__.py +++ b/tksheet/__init__.py @@ -37,6 +37,7 @@ alpha2num, consecutive_chunks, consecutive_ranges, + convert_align, data_to_displayed_idxs, displayed_to_data_idxs, dropdown_search_function, diff --git a/tksheet/column_headers.py b/tksheet/column_headers.py index c9a442f..24fe76d 100644 --- a/tksheet/column_headers.py +++ b/tksheet/column_headers.py @@ -128,7 +128,6 @@ def __init__(self, *args, **kwargs): self.hidd_checkbox = {} self.hidd_boxes = set() - self.default_header = kwargs["default_header"].lower() self.align = kwargs["header_align"] self.basic_bindings() @@ -2270,7 +2269,7 @@ def get_valid_cell_data_as_str(self, datacn: int, fix: bool = True) -> str: except Exception: value = "" if not value and self.PAR.ops.show_default_header_for_empty: - value = get_n2a(datacn, self.default_header) + value = get_n2a(datacn, self.PAR.ops.default_header) return value def get_value_for_empty_cell(self, datacn: int, c_ops: bool = True) -> object: diff --git a/tksheet/functions.py b/tksheet/functions.py index d661ee4..8671cf4 100644 --- a/tksheet/functions.py +++ b/tksheet/functions.py @@ -37,8 +37,17 @@ def get_csv_str_dialect(s: str, delimiters: str) -> csv.Dialect: + if len(s) > 6000: + try: + _upto = next( + match.start() + 1 for i, match in enumerate(re.finditer("\n", s), 1) if i == 300 or match.start() > 6000 + ) + except Exception: + _upto = len(s) + else: + _upto = len(s) try: - return csv.Sniffer().sniff(s[:5000] if len(s) > 5000 else s, delimiters=delimiters) + return csv.Sniffer().sniff(s[:_upto] if len(s) > 6000 else s, delimiters=delimiters) except Exception: return csv.excel_tab diff --git a/tksheet/main_table.py b/tksheet/main_table.py index 1479c1a..608eb70 100644 --- a/tksheet/main_table.py +++ b/tksheet/main_table.py @@ -6345,7 +6345,7 @@ def get_selected_rows( for r in range(box.coords.from_r, box.coords.upto_r) } if get_cells_as_rows: - return s | set(tup[0] for tup in self.get_selected_cells()) + return s | set(map(itemgetter(0), self.gen_selected_cells())) return s def get_selected_cols( @@ -6369,7 +6369,7 @@ def get_selected_cols( for c in range(box.coords.from_c, box.coords.upto_c) } if get_cells_as_cols: - return s | set(tup[1] for tup in self.get_selected_cells()) + return s | set(map(itemgetter(1), self.gen_selected_cells())) return s def get_selected_cells( diff --git a/tksheet/row_index.py b/tksheet/row_index.py index a51b878..61352d2 100644 --- a/tksheet/row_index.py +++ b/tksheet/row_index.py @@ -140,7 +140,6 @@ def __init__(self, *args, **kwargs): self.hidd_boxes = set() self.align = kwargs["row_index_align"] - self.default_index = kwargs["default_row_index"].lower() self.tree_reset() self.basic_bindings() @@ -1200,11 +1199,11 @@ def set_height_of_all_rows( def auto_set_index_width(self, end_row: int, only_rows: list) -> bool: if not isinstance(self.MT._row_index, int) and not self.MT._row_index: - if self.default_index == "letters": + if self.PAR.ops.default_row_index == "letters": new_w = self.MT.get_txt_w(f"{num2alpha(end_row)}") + 20 - elif self.default_index == "numbers": + elif self.PAR.ops.default_row_index == "numbers": new_w = self.MT.get_txt_w(f"{end_row}") + 20 - elif self.default_index == "both": + elif self.PAR.ops.default_row_index == "both": new_w = self.MT.get_txt_w(f"{end_row + 1} {num2alpha(end_row)}") + 20 elif self.PAR.ops.auto_resize_row_index is True: new_w = self.get_index_text_width(only_rows=only_rows) @@ -1336,33 +1335,44 @@ def redraw_tree_arrow( fill: str, tag: str | tuple[str], indent: float, + has_children: bool = False, open_: bool = False, ) -> None: mod = (self.MT.index_txt_height - 1) if self.MT.index_txt_height % 2 else self.MT.index_txt_height small_mod = int(mod / 5) mid_y = floor(self.MT.min_row_height / 2) - # up arrow - if open_: - points = ( - # the left hand downward point - x1 + 5 + indent, - y1 + mid_y + small_mod, - # the middle upward point - x1 + 5 + indent + small_mod + small_mod, - y1 + mid_y - small_mod, - # the right hand downward point - x1 + 5 + indent + small_mod + small_mod + small_mod + small_mod, - y1 + mid_y + small_mod, - ) - # right pointing arrow + if has_children: + # up arrow + if open_: + points = ( + # the left hand downward point + x1 + 5 + indent, + y1 + mid_y + small_mod, + # the middle upward point + x1 + 5 + indent + small_mod + small_mod, + y1 + mid_y - small_mod, + # the right hand downward point + x1 + 5 + indent + small_mod + small_mod + small_mod + small_mod, + y1 + mid_y + small_mod, + ) + # right pointing arrow + else: + points = ( + # the upper point + x1 + 5 + indent + small_mod + small_mod, + y1 + mid_y - small_mod - small_mod, + # the middle point + x1 + 5 + indent + small_mod + small_mod + small_mod + small_mod, + y1 + mid_y, + # the bottom point + x1 + 5 + indent + small_mod + small_mod, + y1 + mid_y + small_mod + small_mod, + ) else: points = ( # the upper point x1 + 5 + indent + small_mod + small_mod, y1 + mid_y - small_mod - small_mod, - # the middle point - x1 + 5 + indent + small_mod + small_mod + small_mod + small_mod, - y1 + mid_y, # the bottom point x1 + 5 + indent + small_mod + small_mod, y1 + mid_y + small_mod + small_mod, @@ -1371,14 +1381,14 @@ def redraw_tree_arrow( t, sh = self.hidd_tree_arrow.popitem() self.coords(t, points) if sh: - self.itemconfig(t, fill=fill) + self.itemconfig(t, fill=fill if has_children else self.PAR.ops.index_grid_fg) else: - self.itemconfig(t, fill=fill, tag=tag, state="normal") + self.itemconfig(t, fill=fill if has_children else self.PAR.ops.index_grid_fg, tag=tag, state="normal") self.lift(t) else: t = self.create_line( points, - fill=fill, + fill=fill if has_children else self.PAR.ops.index_grid_fg, tag=tag, width=2, capstyle=tk.ROUND, @@ -1689,16 +1699,16 @@ def redraw_grid_and_text( draw_x += self.MT.index_txt_height + 3 indent = self.get_treeview_indent(iid) draw_x += indent + 5 - if self.tree[iid].children: - self.redraw_tree_arrow( - 2, - rtopgridln, - r=r, - fill=tree_arrow_fg, - tag="ta", - indent=indent, - open_=self.MT._row_index[datarn].iid in self.tree_open_ids, - ) + self.redraw_tree_arrow( + 2, + rtopgridln, + r=r, + fill=tree_arrow_fg, + tag="ta", + indent=indent, + has_children=bool(self.tree[iid].children), + open_=self.MT._row_index[datarn].iid in self.tree_open_ids, + ) lns = self.get_valid_cell_data_as_str(datarn, fix=False) if not lns: continue @@ -2388,7 +2398,7 @@ def get_valid_cell_data_as_str(self, datarn: int, fix: bool = True) -> str: except Exception: value = "" if not value and self.PAR.ops.show_default_index_for_empty: - value = get_n2a(datarn, self.default_index) + value = get_n2a(datarn, self.PAR.ops.default_row_index) return value def get_value_for_empty_cell(self, datarn: int, r_ops: bool = True) -> object: diff --git a/tksheet/sheet.py b/tksheet/sheet.py index b75db7f..8cfe59e 100644 --- a/tksheet/sheet.py +++ b/tksheet/sheet.py @@ -339,11 +339,9 @@ def __init__( row_index_align=( convert_align(row_index_align) if row_index_align is not None else convert_align(index_align) ), - default_row_index=default_row_index, ) self.CH = ColumnHeaders( parent=self, - default_header=default_header, header_align=convert_align(header_align), ) self.MT = MainTable( @@ -1502,6 +1500,8 @@ def reset( if displayed_rows: self.MT.displayed_rows = [] self.MT.all_rows_displayed = True + if selections: + self.MT.deselect(redraw=False) if row_heights: self.MT.saved_row_heights = {} self.MT.set_row_positions([]) @@ -1514,8 +1514,6 @@ def reset( self.MT.reset_tags() if undo_stack: self.reset_undos() - if selections: - self.MT.deselect(redraw=False) if sheet_options: self.ops = new_sheet_options() self.change_theme(redraw=False) @@ -2924,7 +2922,7 @@ def header_font(self, newfont: tuple[str, int, str] | None = None) -> tuple[str, def table_align( self, - align: str = None, + align: str | None = None, redraw: bool = True, ) -> str | Sheet: if align is None: @@ -2937,7 +2935,7 @@ def table_align( def header_align( self, - align: str = None, + align: str | None = None, redraw: bool = True, ) -> str | Sheet: if align is None: @@ -2950,7 +2948,7 @@ def header_align( def row_index_align( self, - align: str = None, + align: str | None = None, redraw: bool = True, ) -> str | Sheet: if align is None: @@ -3461,6 +3459,17 @@ def get_row_heights(self, canvas_positions: bool = False) -> list[float]: return self.MT.row_positions return self.MT.get_row_heights() + def get_safe_row_heights(self) -> list[int]: + default_h = self.MT.get_default_row_height() + return [0 if e == default_h else e for e in self.MT.gen_row_heights()] + + def set_safe_row_heights(self, heights: list[int]) -> Sheet: + default_h = self.MT.get_default_row_height() + self.MT.row_positions = list( + accumulate(chain([0], (self.valid_row_height(e) if e else default_h for e in heights))) + ) + return self + def get_row_text_height( self, row: int, @@ -3823,8 +3832,14 @@ def displayed_column_to_data(self, c: int) -> int: return c if self.MT.all_columns_displayed else self.MT.displayed_columns[c] data_c = displayed_column_to_data + datacn = displayed_column_to_data dcol = displayed_column_to_data + def data_column_to_displayed(self, c: int) -> int: + return self.MT.dispcn(c) + + dispcn = data_column_to_displayed + def display_columns( self, columns: None | Literal["all"] | Iterator[int] = None, @@ -3951,8 +3966,14 @@ def displayed_row_to_data(self, r: int) -> int: return r if self.MT.all_rows_displayed else self.MT.displayed_rows[r] data_r = displayed_row_to_data + datarn = displayed_row_to_data drow = displayed_row_to_data + def data_row_to_displayed(self, r: int) -> int: + return self.MT.disprn(r) + + disprn = data_row_to_displayed + def display_rows( self, rows: None | Literal["all"] | Iterator[int] = None, @@ -4297,10 +4318,6 @@ def set_options(self, redraw: bool = True, **kwargs) -> Sheet: ) if "default_row_height" in kwargs: self.default_row_height(kwargs["default_row_height"]) - if "default_header" in kwargs: - self.CH.default_header = kwargs["default_header"].lower() - if "default_row_index" in kwargs: - self.RI.default_index = kwargs["default_row_index"].lower() if "max_column_width" in kwargs: self.MT.max_column_width = float(kwargs["max_column_width"]) if "max_row_height" in kwargs: @@ -6675,9 +6692,6 @@ def get_index_dropdown_value(self, r: int = 0) -> object: if self.RI.get_cell_kwargs(r, key="dropdown"): return self.MT._row_index[r] - def delete_all_formatting(self, clear_values: bool = False) -> None: - self.MT.delete_all_formatting(clear_values=clear_values) - def format_cell( self, r: int | Literal["all"], diff --git a/tksheet/sheet_options.py b/tksheet/sheet_options.py index 1f37808..d67260d 100644 --- a/tksheet/sheet_options.py +++ b/tksheet/sheet_options.py @@ -217,6 +217,8 @@ def new_sheet_options() -> DotDict: "default_row_height": "1", "default_column_width": 120, "default_row_index_width": 70, + "default_row_index": "numbers", + "default_header": "letters", "page_up_down_select_row": True, "paste_can_expand_x": False, "paste_can_expand_y": False, diff --git a/tksheet/text_editor.py b/tksheet/text_editor.py index 1eaed31..97a0c53 100644 --- a/tksheet/text_editor.py +++ b/tksheet/text_editor.py @@ -63,7 +63,7 @@ def reset( state=state, ) self.align = align - self.rc_popup_menu.delete(0, None) + self.rc_popup_menu.delete(0, "end") self.rc_popup_menu.add_command( label=sheet_ops.select_all_label, accelerator=sheet_ops.select_all_accelerator,