Skip to content

Commit

Permalink
add "normal" dropdown autocomplete, tidy some code
Browse files Browse the repository at this point in the history
  • Loading branch information
ragardner committed Nov 16, 2024
1 parent 73f019f commit e06b6f8
Show file tree
Hide file tree
Showing 7 changed files with 138 additions and 106 deletions.
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Version 7.2.22
#### Added:
- Autocomplete for `"normal"` state dropdown boxes
- Python `3.13` support badge
- `"disabled"` state for dropdown boxes
- docstrings for enable/disable bindings and extra bindings functions to help with arguments
Expand Down
53 changes: 31 additions & 22 deletions tksheet/column_headers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import tkinter as tk
from collections import defaultdict
from collections.abc import (
Callable,
Hashable,
Sequence,
)
Expand Down Expand Up @@ -2004,13 +2003,34 @@ def get_dropdown_height_anchor(

def dropdown_text_editor_modified(
self,
dd_window: object,
event: dict,
modified_func: Callable | None,
event: tk.Misc,
) -> None:
if modified_func:
modified_func(event)
dd_window.search_and_see(event)
c = self.dropdown.get_coords()
event_data = event_dict(
name="table_dropdown_modified",
sheet=self.PAR.name,
value=self.text_editor.get(),
loc=c,
row=0,
column=c,
boxes=self.MT.get_boxes(),
selected=self.MT.selected,
)
try_binding(self.dropdown.window.modified_function, event_data)
val = self.dropdown.window.search_and_see(event_data)
# return to tk.Text action if control/command is held down
# or keysym was not a character
if (hasattr(event, "state") and event.state & (0x0004 | 0x00000010)) or (
hasattr(event, "keysym") and len(event.keysym) > 2
):
return
self.text_editor.tktext.unbind("<KeyRelease>")
self.text_editor.autocomplete(val)
self.text_editor.tktext.bind(
"<KeyRelease>",
self.dropdown_text_editor_modified,
)
return "break"

def open_dropdown_window(self, c: int, event: object = None) -> None:
self.hide_text_editor()
Expand All @@ -2032,6 +2052,8 @@ def open_dropdown_window(self, c: int, event: object = None) -> None:
"outline_color": self.PAR.ops.header_selected_columns_bg,
"align": self.get_cell_align(c),
"values": kwargs["values"],
"search_function": kwargs["search_function"],
"modified_function": kwargs["modified_function"],
}
if self.dropdown.window:
self.dropdown.window.reset(**reset_kwargs)
Expand All @@ -2044,7 +2066,6 @@ def open_dropdown_window(self, c: int, event: object = None) -> None:
**reset_kwargs,
single_index="c",
close_dropdown_window=self.close_dropdown_window,
search_function=kwargs["search_function"],
arrowkey_RIGHT=self.MT.arrowkey_RIGHT,
arrowkey_LEFT=self.MT.arrowkey_LEFT,
)
Expand All @@ -2055,20 +2076,8 @@ def open_dropdown_window(self, c: int, event: object = None) -> None:
)
if kwargs["state"] == "normal":
self.text_editor.tktext.bind(
"<<TextModified>>",
lambda _x: self.dropdown_text_editor_modified(
self.dropdown.window,
event_dict(
name="header_dropdown_modified",
sheet=self.PAR.name,
value=self.text_editor.get(),
loc=c,
column=c,
boxes=self.MT.get_boxes(),
selected=self.MT.selected,
),
kwargs["modified_function"],
),
"<KeyRelease>",
self.dropdown_text_editor_modified,
)
self.update_idletasks()
try:
Expand Down
6 changes: 6 additions & 0 deletions tksheet/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from itertools import islice, repeat
from typing import Literal

from .colors import color_map
from .formatters import (
to_bool,
)
Expand Down Expand Up @@ -435,6 +436,11 @@ def box_is_single_cell(
return r2 - r1 == 1 and c2 - c1 == 1


def color_tup(color: str) -> tuple[int, int, int]:
res = color if color.startswith("#") else color_map[color]
return int(res[1:3], 16), int(res[3:5], 16), int(res[5:], 16)


def down_cell_within_box(
r: int,
c: int,
Expand Down
101 changes: 41 additions & 60 deletions tksheet/main_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
b_index,
box_is_single_cell,
cell_right_within_box,
color_tup,
consecutive_ranges,
diff_gen,
diff_list,
Expand All @@ -73,9 +74,9 @@
mod_span_widget,
move_elements_by_mapping,
new_tk_event,
stored_event_dict,
rounded_box_coords,
span_idxs_post_move,
stored_event_dict,
try_binding,
unpickle_obj,
)
Expand Down Expand Up @@ -5652,24 +5653,9 @@ def main_table_redraw_grid_and_text(
)
if redraw_table:
selections = self.get_redraw_selections(text_start_row, grid_end_row, text_start_col, grid_end_col)
sel_cells_bg = (
self.PAR.ops.table_selected_cells_bg
if self.PAR.ops.table_selected_cells_bg.startswith("#")
else color_map[self.PAR.ops.table_selected_cells_bg]
)
sel_cells_bg = (int(sel_cells_bg[1:3], 16), int(sel_cells_bg[3:5], 16), int(sel_cells_bg[5:], 16))
sel_cols_bg = (
self.PAR.ops.table_selected_columns_bg
if self.PAR.ops.table_selected_columns_bg.startswith("#")
else color_map[self.PAR.ops.table_selected_columns_bg]
)
sel_cols_bg = (int(sel_cols_bg[1:3], 16), int(sel_cols_bg[3:5], 16), int(sel_cols_bg[5:], 16))
sel_rows_bg = (
self.PAR.ops.table_selected_rows_bg
if self.PAR.ops.table_selected_rows_bg.startswith("#")
else color_map[self.PAR.ops.table_selected_rows_bg]
)
sel_rows_bg = (int(sel_rows_bg[1:3], 16), int(sel_rows_bg[3:5], 16), int(sel_rows_bg[5:], 16))
sel_cells_bg = color_tup(self.PAR.ops.table_selected_cells_bg)
sel_cols_bg = color_tup(self.PAR.ops.table_selected_columns_bg)
sel_rows_bg = color_tup(self.PAR.ops.table_selected_rows_bg)
if self.selected:
current_loc = (self.selected.row, self.selected.column)
else:
Expand All @@ -5689,25 +5675,11 @@ def main_table_redraw_grid_and_text(
dont_blend = tuple()

if not self.PAR.ops.show_selected_cells_border:
current_cell_blend = (
self.PAR.ops.table_selected_cells_fg
if self.PAR.ops.table_selected_cells_fg.startswith("#")
else color_map[self.PAR.ops.table_selected_cells_fg]
)
current_cell_blend = (int(current_cell_blend[1:3], 16), int(current_cell_blend[3:5], 16), int(current_cell_blend[5:], 16))
current_col_blend = (
self.PAR.ops.table_selected_columns_fg
if self.PAR.ops.table_selected_columns_fg.startswith("#")
else color_map[self.PAR.ops.table_selected_columns_fg]
)
current_col_blend = (int(current_col_blend[1:3], 16), int(current_col_blend[3:5], 16), int(current_col_blend[5:], 16))
current_row_blend = (
self.PAR.ops.table_selected_rows_fg
if self.PAR.ops.table_selected_rows_fg.startswith("#")
else color_map[self.PAR.ops.table_selected_rows_fg]
)
current_row_blend = (int(current_row_blend[1:3], 16), int(current_row_blend[3:5], 16), int(current_row_blend[5:], 16))
override = (current_cell_blend, current_col_blend, current_row_blend)
override = (
color_tup(self.PAR.ops.table_selected_cells_fg),
color_tup(self.PAR.ops.table_selected_columns_fg),
color_tup(self.PAR.ops.table_selected_rows_fg),
)
else:
override = tuple()

Expand Down Expand Up @@ -7076,13 +7048,34 @@ def get_dropdown_height_anchor(self, r: int, c: int, text_editor_h: int | None =

def dropdown_text_editor_modified(
self,
dd_window: object,
event: dict,
modified_func: Callable | None,
event: tk.Misc,
) -> None:
if modified_func:
modified_func(event)
dd_window.search_and_see(event)
r, c = self.dropdown.get_coords()
event_data = event_dict(
name="table_dropdown_modified",
sheet=self.PAR.name,
value=self.text_editor.get(),
loc=Loc(r, c),
row=r,
column=c,
boxes=self.get_boxes(),
selected=self.selected,
)
try_binding(self.dropdown.window.modified_function, event_data)
val = self.dropdown.window.search_and_see(event_data)
# return to tk.Text action if control/command is held down
# or keysym was not a character
if (hasattr(event, "state") and event.state & (0x0004 | 0x00000010)) or (
hasattr(event, "keysym") and len(event.keysym) > 2
):
return
self.text_editor.tktext.unbind("<KeyRelease>")
self.text_editor.autocomplete(val)
self.text_editor.tktext.bind(
"<KeyRelease>",
self.dropdown_text_editor_modified,
)
return "break"

# c is displayed col
def open_dropdown_window(
Expand Down Expand Up @@ -7119,6 +7112,8 @@ def open_dropdown_window(
"outline_color": self.get_selected_box_bg_fg(type_="cells")[1],
"align": self.get_cell_align(r, c),
"values": kwargs["values"],
"search_function": kwargs["search_function"],
"modified_function": kwargs["modified_function"],
}
if self.dropdown.window:
self.dropdown.window.reset(**reset_kwargs)
Expand All @@ -7130,7 +7125,6 @@ def open_dropdown_window(
self.winfo_toplevel(),
**reset_kwargs,
close_dropdown_window=self.close_dropdown_window,
search_function=kwargs["search_function"],
arrowkey_RIGHT=self.arrowkey_RIGHT,
arrowkey_LEFT=self.arrowkey_LEFT,
)
Expand All @@ -7141,22 +7135,9 @@ def open_dropdown_window(
)
if kwargs["state"] == "normal":
self.text_editor.tktext.bind(
"<<TextModified>>",
lambda _: self.dropdown.window.search_and_see(
event_dict(
name="table_dropdown_modified",
sheet=self.PAR.name,
value=self.text_editor.get(),
loc=Loc(r, c),
row=r,
column=c,
boxes=self.get_boxes(),
selected=self.selected,
)
),
"<KeyRelease>",
self.dropdown_text_editor_modified,
)
if kwargs["modified_function"] is not None:
self.dropdown.window.modified_function = kwargs["modified_function"]
self.update_idletasks()
try:
self.after(1, lambda: self.text_editor.tktext.focus())
Expand Down
19 changes: 19 additions & 0 deletions tksheet/other_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,25 @@ def get(self) -> str:
if self.window:
return self.window.get()
return ""

def set(self, value: str) -> None:
if not self.window:
return
self.window.set_text(value)

def highlight_from(self, r: int | str, c: int | str) -> None:
index = self.window.tktext.index(f"{r}.{c}")
self.window.tktext.tag_add('sel', index, 'end')
self.window.tktext.mark_set('insert', f"{r}.{c}")

def autocomplete(self, value: str | None) -> None:
current_val = self.get()
if not value or len(current_val) >= len(value) or current_val != value[:len(current_val)]:
return
cursor_pos = self.tktext.index('insert')
line, column = cursor_pos.split('.')
self.window.set_text(value)
self.highlight_from(line, column)

@property
def tktext(self) -> object:
Expand Down
53 changes: 31 additions & 22 deletions tksheet/row_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import tkinter as tk
from collections import defaultdict
from collections.abc import (
Callable,
Generator,
Hashable,
Iterator,
Expand Down Expand Up @@ -2147,13 +2146,34 @@ def get_dropdown_height_anchor(self, r: int, text_editor_h: None | int = None) -

def dropdown_text_editor_modified(
self,
dd_window: object,
event: dict,
modified_func: Callable | None,
event: tk.Misc,
) -> None:
if modified_func:
modified_func(event)
dd_window.search_and_see(event)
r = self.dropdown.get_coords()
event_data = event_dict(
name="table_dropdown_modified",
sheet=self.PAR.name,
value=self.text_editor.get(),
loc=r,
row=r,
column=0,
boxes=self.MT.get_boxes(),
selected=self.MT.selected,
)
try_binding(self.dropdown.window.modified_function, event_data)
val = self.dropdown.window.search_and_see(event_data)
# return to tk.Text action if control/command is held down
# or keysym was not a character
if (hasattr(event, "state") and event.state & (0x0004 | 0x00000010)) or (
hasattr(event, "keysym") and len(event.keysym) > 2
):
return
self.text_editor.tktext.unbind("<KeyRelease>")
self.text_editor.autocomplete(val)
self.text_editor.tktext.bind(
"<KeyRelease>",
self.dropdown_text_editor_modified,
)
return "break"

# r is displayed row
def open_dropdown_window(self, r: int, event: object = None) -> None:
Expand Down Expand Up @@ -2183,6 +2203,8 @@ def open_dropdown_window(self, r: int, event: object = None) -> None:
"outline_color": self.PAR.ops.index_selected_rows_bg,
"align": self.get_cell_align(r),
"values": kwargs["values"],
"search_function": kwargs["search_function"],
"modified_function": kwargs["modified_function"],
}
if self.dropdown.window:
self.dropdown.window.reset(**reset_kwargs)
Expand All @@ -2195,7 +2217,6 @@ def open_dropdown_window(self, r: int, event: object = None) -> None:
**reset_kwargs,
single_index="r",
close_dropdown_window=self.close_dropdown_window,
search_function=kwargs["search_function"],
arrowkey_RIGHT=self.MT.arrowkey_RIGHT,
arrowkey_LEFT=self.MT.arrowkey_LEFT,
)
Expand All @@ -2206,20 +2227,8 @@ def open_dropdown_window(self, r: int, event: object = None) -> None:
)
if kwargs["state"] == "normal":
self.text_editor.tktext.bind(
"<<TextModified>>",
lambda _x: self.dropdown_text_editor_modified(
self.dropdown.window,
event_dict(
name="index_dropdown_modified",
sheet=self.PAR.name,
value=self.text_editor.get(),
loc=r,
row=r,
boxes=self.MT.get_boxes(),
selected=self.MT.selected,
),
kwargs["modified_function"],
),
"<KeyRelease>",
self.dropdown_text_editor_modified,
)
self.update_idletasks()
try:
Expand Down
Loading

0 comments on commit e06b6f8

Please sign in to comment.