Some refinements to the Menu infraestructure (#962)

* Correct definition of btrfs standard layout

* Solve issue #936

* make ask_for_a_timezone as synonym to ask_timezone

* Some refining in GeneralMenu
secret is now a general function

* Revert "Some refining in GeneralMenu"

This reverts commit e6e131cb19.

* New version of the FlexibleMenu
* Added new functionality to Selector
* Created a GeneralMenu class
* GlobalMenu is made a child of GeneralMenu

* Some refining in GeneralMenu
secret is now a general function

* log is invoked in GeneralMenu directly

* Materialize again _setup_selection_menu_options. Gives more room to play

* Callbacks converted as methods
Synch() (data area and menu) decoupled from enable()
and made general before any run

* Only_hd gets a new implementation of the menu
flake8 corrections

* New version of the FlexibleMenu
* Added new functionality to Selector
* Created a GeneralMenu class
* GlobalMenu is made a child of GeneralMenu

* changes from the rebase left dangling

* Adapt to PR #874

* Adapted to nationalization framework (PR 893).
String still NOT adapted

* flake8 complains

* Use of archinstall.output_config instead of local copy at swiss.py

* Problems with the last merge

* git complains

* Menu admits now preset values and cursor positioning

* Now GeneralMenu moves to the next entry after each selection

* flake8 complains

* Control of limits for cursor position at GeneralMenu

* Make auto cursor positioning optional at GeneralMenu.
True for GlobalMenu

* Code cleanup after rebase, and flake8 complains
This commit is contained in:
Werner Llácer 2022-02-11 13:22:35 +01:00 committed by GitHub
parent 18e033d2f0
commit 5990491292
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 8 deletions

View File

@ -7,7 +7,7 @@ import sys
import logging import logging
class Menu(TerminalMenu): class Menu(TerminalMenu):
def __init__(self, title, p_options, skip=True, multi=False, default_option=None, sort=True): def __init__(self, title, p_options, skip=True, multi=False, default_option=None, sort=True, preset_values=None, cursor_index=None):
""" """
Creates a new menu Creates a new menu
@ -29,6 +29,12 @@ class Menu(TerminalMenu):
:param sort: Indicate if the options should be sorted alphabetically before displaying :param sort: Indicate if the options should be sorted alphabetically before displaying
:type sort: bool :type sort: bool
:param preset_values: Predefined value(s) of the menu. In a multi menu, it selects the options included therein. If the selection is simple, moves the cursor to the position of the value
:type preset_values: str or list
:param cursor_index: The position where the cursor will be located. If it is not in range (number of elements of the menu) it goes to the first position
:type cursor_index: int
""" """
# we guarantee the inmutability of the options outside the class. # we guarantee the inmutability of the options outside the class.
# an unknown number of iterables (.keys(),.values(),generator,...) can't be directly copied, in this case # an unknown number of iterables (.keys(),.values(),generator,...) can't be directly copied, in this case
@ -61,6 +67,7 @@ class Menu(TerminalMenu):
self.skip = skip self.skip = skip
self.default_option = default_option self.default_option = default_option
self.multi = multi self.multi = multi
self.preselection(preset_values,cursor_index)
menu_title = f'\n{title}\n\n' menu_title = f'\n{title}\n\n'
@ -86,7 +93,9 @@ class Menu(TerminalMenu):
cycle_cursor=True, cycle_cursor=True,
clear_screen=True, clear_screen=True,
multi_select=multi, multi_select=multi,
show_search_hint=True show_search_hint=True,
preselected_entries=self.preset_values,
cursor_index=self.cursor_index
) )
def _show(self): def _show(self):
@ -114,3 +123,36 @@ class Menu(TerminalMenu):
return self.run() return self.run()
return ret return ret
def set_cursor_pos(self,pos :int):
if pos and 0 < pos < len(self._menu_entries):
self._view.active_menu_index = pos
else:
self._view.active_menu_index = 0 # we define a default
def set_cursor_pos_entry(self,value :str):
pos = self._menu_entries.index(value)
self.set_cursor_pos(pos)
def preselection(self,preset_values :list = [],cursor_index :int = None):
def from_preset_to_cursor():
if preset_values:
if isinstance(preset_values,str):
self.cursor_index = self.menu_options.index(preset_values)
else: # should return an error, but this is smoother
self.cursor_index = self.menu_options.index(preset_values[0])
self.preset_values = preset_values
self.cursor_index = cursor_index
if preset_values and cursor_index is None:
from_preset_to_cursor()
if preset_values and not self.multi: # Not supported by the infraestructure
self.preset_values = None
from_preset_to_cursor()
if self.default_option and self.multi:
if isinstance(preset_values,str) and self.default_option == preset_values:
self.preset_values = f"{preset_values} (default)"
elif isinstance(preset_values,(list,tuple)) and self.default_option in preset_values:
idx = preset_values.index(self.default_option)
self.preset_values[idx] = f"{preset_values[idx]} (default)"

View File

@ -1,6 +1,7 @@
from __future__ import annotations from __future__ import annotations
import sys import sys
import logging import logging
from typing import Callable, Any, List, Iterator from typing import Callable, Any, List, Iterator
from .menu import Menu from .menu import Menu
@ -32,7 +33,6 @@ from ..user_interaction import select_profile
from ..user_interaction import select_archinstall_language from ..user_interaction import select_archinstall_language
from ..translation import Translation from ..translation import Translation
class Selector: class Selector:
def __init__( def __init__(
self, self,
@ -165,19 +165,22 @@ class Selector:
if status and not self.is_enabled(): if status and not self.is_enabled():
self.set_enabled(True) self.set_enabled(True)
class GeneralMenu: class GeneralMenu:
def __init__(self, data_store :dict = None): def __init__(self, data_store :dict = None, auto_cursor=False):
""" """
Create a new selection menu. Create a new selection menu.
:param data_store: Area (Dict) where the resulting data will be held. At least an entry for each option. Default area is self._data_store (not preset in the call, due to circular references :param data_store: Area (Dict) where the resulting data will be held. At least an entry for each option. Default area is self._data_store (not preset in the call, due to circular references
:type data_store: Dict :type data_store: Dict
:param auto_cursor: Boolean which determines if the cursor stays on the first item (false) or steps each invocation of a selection entry (true)
:type auto_cursor: bool
""" """
self._translation = Translation.load_nationalization() self._translation = Translation.load_nationalization()
self.is_context_mgr = False self.is_context_mgr = False
self._data_store = data_store if data_store is not None else {} self._data_store = data_store if data_store is not None else {}
self.auto_cursor = auto_cursor
self._menu_options = {} self._menu_options = {}
self._setup_selection_menu_options() self._setup_selection_menu_options()
@ -247,14 +250,18 @@ class GeneralMenu:
# we synch all the options just in case # we synch all the options just in case
for item in self.list_options(): for item in self.list_options():
self.synch(item) self.synch(item)
cursor_pos = None
while True: while True:
# Before continuing, set the preferred keyboard layout/language in the current terminal. # Before continuing, set the preferred keyboard layout/language in the current terminal.
# This will just help the user with the next following questions. # This will just help the user with the next following questions.
self._set_kb_language() self._set_kb_language()
enabled_menus = self._menus_to_enable() enabled_menus = self._menus_to_enable()
menu_text = [m.text for m in enabled_menus.values()] menu_text = [m.text for m in enabled_menus.values()]
selection = Menu('Set/Modify the below options', menu_text, sort=False).run() selection = Menu('Set/Modify the below options', menu_text, sort=False, cursor_index=cursor_pos).run()
if selection: if selection and self.auto_cursor:
cursor_pos = menu_text.index(selection) + 1 # before the strip otherwise fails
if cursor_pos >= len(menu_text):
cursor_pos = len(menu_text) - 1
selection = selection.strip() selection = selection.strip()
if selection: if selection:
# if this calls returns false, we exit the menu. We allow for an callback for special processing on realeasing control # if this calls returns false, we exit the menu. We allow for an callback for special processing on realeasing control
@ -294,6 +301,7 @@ class GeneralMenu:
result = None result = None
if selector.func: if selector.func:
# TODO insert code to allow selector functions with preset value
result = selector.func() result = selector.func()
self._menu_options[selector_name].set_current_selection(result) self._menu_options[selector_name].set_current_selection(result)
self._data_store[selector_name] = result self._data_store[selector_name] = result
@ -399,7 +407,7 @@ class GeneralMenu:
class GlobalMenu(GeneralMenu): class GlobalMenu(GeneralMenu):
def __init__(self,data_store): def __init__(self,data_store):
super().__init__(data_store=data_store) super().__init__(data_store=data_store, auto_cursor=True)
def _setup_selection_menu_options(self): def _setup_selection_menu_options(self):
self._menu_options['archinstall-language'] = \ self._menu_options['archinstall-language'] = \

View File

@ -1,3 +1,4 @@
import logging import logging
import os import os
import pathlib import pathlib