Skip to content
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

Features with border tight #41

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
48 changes: 38 additions & 10 deletions cursesmenu/curses_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@ class CursesMenu(object):
currently_active_menu = None
stdscr = None

def __init__(self, title=None, subtitle=None, show_exit_option=True):
def __init__(self, title=None, subtitle=None, show_exit_option=True, with_border=True, tight=False):
"""
:ivar str title: The title of the menu
:ivar str subtitle: The subtitle of the menu
:ivar bool show_exit_option: Whether this menu should show an exit item by default. Can be overridden \
when the menu is started
:ivar bool with_border: Whether a border should be drawn around the menu.
:ivar bool tight: Whether to save screen space by not inserting some blanks and newlines as spacing.
:ivar items: The list of MenuItems that the menu will display
:vartype items: list[:class:`MenuItem<cursesmenu.items.MenuItem>`]
:ivar CursesMenu parent: The parent of this menu
Expand All @@ -42,6 +44,8 @@ def __init__(self, title=None, subtitle=None, show_exit_option=True):
self.title = title
self.subtitle = subtitle
self.show_exit_option = show_exit_option
self.with_border = with_border
self.tight = tight

self.items = list()

Expand Down Expand Up @@ -196,27 +200,51 @@ def draw(self):
"""
Redraws the menu and refreshes the screen. Should be called whenever something changes that needs to be redrawn.
"""

self.screen.border(0)
origin_line = 0
origin_col = 0
if(self.with_border):
self.screen.border(0)
origin_line += 1
origin_col += 1
if(not self.tight):
origin_col += 1

title_line = origin_line
title_col = origin_col
if self.title is not None:
self.screen.addstr(2, 2, self.title, curses.A_STANDOUT)
if(not self.tight):
title_line += 1
self.screen.addstr(title_line, title_col, self.title, curses.A_STANDOUT)
subtitle_line = title_line
subtitle_col = origin_col
if self.subtitle is not None:
self.screen.addstr(4, 2, self.subtitle, curses.A_BOLD)

# if there is no subtitle, the value is the same as for the title
subtitle_line += 1
if(not self.tight):
subtitle_line += 1
self.screen.addstr(subtitle_line, subtitle_col, self.subtitle, curses.A_BOLD)

items_start_line = subtitle_line + 1
items_start_col = origin_col
if(not self.tight):
items_start_col += 2
for index, item in enumerate(self.items):
if self.current_option == index:
text_style = self.highlight
else:
text_style = self.normal
self.screen.addstr(5 + index, 4, item.show(index), text_style)
self.screen.addstr(items_start_line + index, items_start_col, item.show(index), text_style)

screen_rows, screen_cols = CursesMenu.stdscr.getmaxyx()
# in case the menu does not fit on the screen, scroll the 'viewport'
top_row = 0
if 6 + len(self.items) > screen_rows:
if screen_rows + self.current_option < 6 + len(self.items):
# if the last item is outside the screen...
if items_start_line + 1 + len(self.items) > screen_rows:
# and if
if items_start_line + 1 + len(self.items) - self.current_option > screen_rows:
top_row = self.current_option
else:
top_row = 6 + len(self.items) - screen_rows
top_row = items_start_line + 1 + len(self.items) - screen_rows

self.screen.refresh(top_row, 0, 0, 0, screen_rows - 1, screen_cols - 1)

Expand Down
6 changes: 4 additions & 2 deletions cursesmenu/selection_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ class SelectionMenu(CursesMenu):
A menu that simplifies item creation, just give it a list of strings and it builds the menu for you
"""

def __init__(self, strings, title=None, subtitle=None, show_exit_option=True):
def __init__(self, strings, title=None, subtitle=None, show_exit_option=True,
with_border=True, tight=False):
"""
:ivar list[str] strings: The list of strings this menu should be built from
"""
super(SelectionMenu, self).__init__(title, subtitle, show_exit_option)
super(SelectionMenu, self).__init__(title, subtitle, show_exit_option,
with_border, tight)
for index, item in enumerate(strings):
self.append_item(SelectionItem(item, index, self))

Expand Down
12 changes: 12 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,15 @@ Which is equivalent to::
menu.join()

selection = menu.selected_option

If you want to avoid wasting space, maybe because your screen is really small, you can disable the border
drawn around the menu using the argument `with_border=False`.

menu = CursesMenu("This is a menu!", "It has a subtitle too!", with_border=False)

Furthermore some spacings, like between title and subtitle and in front of menu items, will not appear
when the `tight=True` is passed to the menu constructors.

menu = CursesMenu("This is a menu!", "It has a subtitle too!", tight=True)

These two options are also available for :py:class:`~cursesmenu.SelectionMenu`.
10 changes: 7 additions & 3 deletions examples/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@


def main():
menu = CursesMenu("Root Menu", "Root Menu Subtitle")
with_border = True
tight = False
menu = CursesMenu("Root Menu", "Root Menu Subtitle", with_border=with_border, tight=tight)
item1 = MenuItem("Item 1", menu)
function_item = FunctionItem("Fun item", input, ["Enter an input: "])
command_item = CommandItem("Command", "python examples/example.py")
submenu = SelectionMenu(["item1", "item2", "item3"])

submenu = SelectionMenu(["item1", "item2", "item3"], with_border=with_border, tight=tight)
submenu_item = SubmenuItem("Submenu item", submenu=submenu)
submenu_item.set_menu(menu)
submenu_2 = CursesMenu("Submenu Title", "Submenu subtitle")

submenu_2 = CursesMenu("Submenu Title", "Submenu subtitle", with_border=with_border, tight=tight)
function_item_2 = FunctionItem("Fun item", input, ["Enter an input"])
item2 = MenuItem("Another Item")
submenu_2.append_item(function_item_2)
Expand Down