Skip to content

Fix vertical selection of neighbors #152

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: v0.1.5-develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified docs/assets/recoverpy-demo.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
98 changes: 46 additions & 52 deletions py_cui/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def __init__(self, num_rows: int, num_cols: int, auto_focus_buttons: bool=True,
"""

self._title = 'PyCUI Window'

# When this is not set, the escape character delay
# is too long for exiting focus mode
os.environ.setdefault('ESCDELAY', '25')
Expand Down Expand Up @@ -211,7 +211,7 @@ def set_on_draw_update_func(self, update_function: Callable[[],Any]):
self._on_draw_update_func = update_function


def set_widget_cycle_key(self, forward_cycle_key: int=None, reverse_cycle_key: int=None) -> None:
def set_widget_cycle_key(self, forward_cycle_key: int=None, reverse_cycle_key: int=None) -> None:
"""Assigns a key for automatically cycling through widgets in both focus and overview modes

Parameters
Expand Down Expand Up @@ -437,12 +437,12 @@ def set_widget_border_characters(self, upper_left_corner: str, upper_right_corne
self._logger.debug(f'Set border_characters to {self._border_characters}')


def get_widgets(self) -> Dict[int,Optional['py_cui.widgets.Widget']]:
def get_widgets(self) -> Dict[int,Optional['py_cui.widgets.Widget']]:
"""Function that gets current set of widgets

Returns
-------
widgets : dict of int -> widget
widgets : dict of int -> widget
dictionary mapping widget IDs to object instances
"""

Expand Down Expand Up @@ -784,7 +784,7 @@ def add_button(self, title: str, row: int, column: int, row_span: int = 1, colum
self._logger.info(f'Adding widget {title} w/ ID {id} of type {str(type(new_button))}')
return new_button


def add_slider(self, title: str, row: int, column: int, row_span: int=1,
column_span: int=1, padx: int=1, pady: int=0,
min_val: int=0, max_val: int=100, step: int=1, init_val: int=0) -> 'py_cui.controls.slider.SliderWidget':
Expand Down Expand Up @@ -850,7 +850,7 @@ def forget_widget(self, widget : 'py_cui.widgets.Widget') -> None:
----------
widget : py_cui.widgets.Widget
Widget to remove from the UI

Raises
------
TypeError
Expand All @@ -865,7 +865,7 @@ def forget_widget(self, widget : 'py_cui.widgets.Widget') -> None:
raise KeyError(f'Widget with id {widget.get_id()} has already been removed from the UI!')
else:
self.get_widgets()[widget.get_id()] = None


def get_element_at_position(self, x: int, y: int) -> Optional['py_cui.ui.UIElement']:
"""Returns containing widget for character position
Expand All @@ -888,10 +888,10 @@ def get_element_at_position(self, x: int, y: int) -> Optional['py_cui.ui.UIEleme

elif self._popup is None:
for widget_id in self.get_widgets().keys():
widget = self.get_widgets()[widget_id]
widget = self.get_widgets()[widget_id]
if widget is not None:
if widget._contains_position(x, y):
return widget
return widget
return None


Expand Down Expand Up @@ -959,34 +959,28 @@ def _get_vertical_neighbors(self, widget: 'py_cui.widgets.Widget', direction: in
A list of the neighbor widget ids
"""

if not direction in py_cui.keys.ARROW_KEYS:
if direction not in (py_cui.keys.KEY_UP_ARROW,py_cui.keys.KEY_DOWN_ARROW):
return None

num_rows, _ = self._grid.get_dimensions()
row_start, col_start = widget.get_grid_cell()
row_span, col_span = widget.get_grid_cell_spans()
row_span, _ = widget.get_grid_cell_spans()
id_list = []

if direction == py_cui.keys.KEY_UP_ARROW:
row_range_start = 0
row_range_stop = row_start
scope = range(row_start - 1, -1, -1)
else:
row_range_start = row_start + row_span
row_range_stop = num_rows
scope = range(row_start + row_span, num_rows)

for row in range(row_range_start, row_range_stop):
for col in range(col_start, col_start + col_span):
for widget_id in self.get_widgets().keys():
item_value = self.get_widgets()[widget_id]
if item_value is not None:
if item_value._is_row_col_inside(row, col) and widget_id not in id_list:
id_list.append(widget_id)
widgets = self.get_widgets()
ids = widgets.keys()

if direction == py_cui.keys.KEY_UP_ARROW:
id_list.reverse()
for row in scope:
row_items = [w for w in ids if widgets[w]._row == row and widgets[w].is_selectable()]
sorted_items = sorted(row_items, key=lambda x: abs(col_start - widgets[x]._column))
id_list.extend(sorted_items)

self._logger.debug(f'Neighbors with ids {id_list} for cell \
{row_start},{col_start} span {row_span},{col_span}')
self._logger.debug(f'Neighbors with ids {id_list} for cell {row_start},{col_start}')

return id_list

Expand All @@ -1005,7 +999,7 @@ def _check_if_neighbor_exists(self, direction: int) -> Optional[int]:

Returns
-------
widget_id : int
widget_id : int
The widget neighbor ID if found, None otherwise
"""

Expand Down Expand Up @@ -1048,7 +1042,7 @@ def set_selected_widget(self, widget_id: int) -> None:

Parameters
----------
widget_id : int
widget_id : int
the id of the widget to select
"""

Expand Down Expand Up @@ -1135,8 +1129,8 @@ def _cycle_widgets(self, reverse: bool=False) -> None:

current_widget_id: int = current_widget_num
next_widget_id: int = next_widget_num
current_widget = self.get_widgets()[current_widget_id]
next_widget = self.get_widgets()[next_widget_id]
current_widget = self.get_widgets()[current_widget_id]
next_widget = self.get_widgets()[next_widget_id]
if current_widget and next_widget is not None: #pls check again
if self._in_focused_mode and cycle_key in current_widget._key_commands.keys():
# In the event that we are focusing on a widget with that key defined, we do not cycle.
Expand Down Expand Up @@ -1332,14 +1326,14 @@ def show_form_popup(self, title: str, fields: List[str], passwd_fields: List[str
If not none, fired after loading is completed. Must be a no-arg function
"""

self._popup = py_cui.dialogs.form.FormPopup(self,
fields,
passwd_fields,
required,
{},
title,
py_cui.WHITE_ON_BLACK,
self._renderer,
self._popup = py_cui.dialogs.form.FormPopup(self,
fields,
passwd_fields,
required,
{},
title,
py_cui.WHITE_ON_BLACK,
self._renderer,
self._logger)

if callback is not None:
Expand Down Expand Up @@ -1368,14 +1362,14 @@ def show_filedialog_popup(self, popup_type: str='openfile', initial_dir: str ='.
Only show files with extensions in this list if not empty. Default, []
"""

self._popup = py_cui.dialogs.filedialog.FileDialogPopup(self,
callback,
initial_dir,
popup_type,
ascii_icons,
limit_extensions,
py_cui.WHITE_ON_BLACK,
self._renderer,
self._popup = py_cui.dialogs.filedialog.FileDialogPopup(self,
callback,
initial_dir,
popup_type,
ascii_icons,
limit_extensions,
py_cui.WHITE_ON_BLACK,
self._renderer,
self._logger)

self._logger.debug(f'Opened {str(type(self._popup))} popup with type {popup_type}')
Expand Down Expand Up @@ -1412,7 +1406,7 @@ def close_popup(self) -> None:

def _refresh_height_width(self) -> None:
"""Function that updates the height and width of the CUI based on terminal window size."""

if self._simulated_terminal is None:
if self._stdscr is None:
term_size = shutil.get_terminal_size()
Expand All @@ -1426,7 +1420,7 @@ def _refresh_height_width(self) -> None:
width = self._simulated_terminal[1]

height = height - self.title_bar.get_height() - self.status_bar.get_height() - 2

self._logger.debug(f'Resizing CUI to new dimensions {height} by {width}')

self._height = height
Expand Down Expand Up @@ -1460,7 +1454,7 @@ def _draw_widgets(self) -> None:

for widget_id in self.get_widgets().keys():
if widget_id != self._selected_widget:
widget = self.get_widgets()[widget_id]
widget = self.get_widgets()[widget_id]
if widget is not None:
widget._draw()

Expand Down Expand Up @@ -1587,7 +1581,7 @@ def _handle_key_presses(self, key_pressed: int) -> None:
self._popup._handle_key_press(key_pressed)


def _draw(self, stdscr) -> None:
def _draw(self, stdscr) -> None:
"""Main CUI draw loop called by start()

Parameters
Expand All @@ -1609,7 +1603,7 @@ def _draw(self, stdscr) -> None:
# Initialization functions. Generates colors and renderer
self._initialize_colors()
self._initialize_widget_renderer()

# If user specified a refresh timeout, apply it here
if self._refresh_timeout > 0:
self._stdscr.timeout(self._refresh_timeout)
Expand Down Expand Up @@ -1647,7 +1641,7 @@ def _draw(self, stdscr) -> None:
# Here we handle mouse click events globally, or pass them to the UI element to handle
elif key_pressed == curses.KEY_MOUSE:
self._logger.info('Detected mouse click')

valid_mouse_event = True
try:
id, x, y, _, mouse_event = curses.getmouse()
Expand Down