Files
openvino/tools/deployment_manager/deployman/ui.py
2022-01-19 01:07:49 +03:00

289 lines
10 KiB
Python

"""
Copyright (c) 2018-2022 Intel Corporation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import os
class Button:
def __init__(self, shortcut: str, message: str, action):
self.shortcut = str(shortcut)
self.message = message
self.action = action
def press(self, *args):
self.action(*args)
def draw(self):
print("\t{}. {}".format(self.shortcut, self.message))
class ButtonFactory:
@staticmethod
def create_button(shortcut, message, action):
return globals()["Button"](shortcut, message, action)
class Controls:
def __init__(self, button_map):
self.controls = []
for btn in button_map:
self.controls.append(
ButtonFactory.create_button(shortcut=btn["shortcut"],
message=btn["message"],
action=btn["action"]))
def update_button(self, btn, attr, value):
for _btn in self.controls:
_btn: Button
if btn == _btn.shortcut:
setattr(_btn, attr, value)
def get_controls(self):
return self.controls
# view for User Interface
class ConsoleMenu:
def __init__(self, control_buttons: Controls, user_input_msg: str, hdrs: list, targets=False):
self.control_buttons = control_buttons
self.targets = targets
self.ui_msg = user_input_msg
self.headers = hdrs
@staticmethod
def clear():
_ = os.system('clear' if os.name == 'posix' else 'cls')
@staticmethod
def print_msg(messages):
print("\n".join(messages))
@staticmethod
def br(num: int = 1):
print("\n"*num)
def sync(self, attr, value):
setattr(self, attr, value)
print(getattr(self, attr))
def draw(self):
self.clear()
self.print_msg(self.headers)
if self.targets:
for target in self.targets:
print("\t{}. [{}] {}\n".format(self.targets.index(target) + 1,
'x' if target.selected else ' ',
target.ui_name))
self.br()
for btn in self.control_buttons.get_controls():
btn: Button
btn.draw()
return input(self.ui_msg)
# class that operating with User Interface
class UserInterface:
def __init__(self, version, args, targets, logger):
self.args = args
self.available_targets = targets
self.is_running = True
self.separator = '-' * 80
self.user_input = ''
self._active_menu = ''
self._active_controls = ''
self.us_buttons = ''
self.fn_buttons = ''
self.version = version
self.logger = logger
def get_selected_targets_uinames(self):
return [t.ui_name for t in self.available_targets if t.selected]
def get_selected_targets(self):
return [t for t in self.available_targets if t.selected]
@staticmethod
def print_msg(messages):
print("\n".join(messages))
def print_selections(self):
for target in self.available_targets:
print("\t{}. [{}] {}\n".format(self.available_targets.index(target) + 1,
'x' if target.selected else ' ',
target.ui_name))
def apply_value_to_targets(self, attr, value):
for target in self.available_targets:
target.set_value(attr, value)
def select_deselect_all(self):
if any(not target.selected for target in self.available_targets):
self.apply_value_to_targets('selected', True)
else:
self.apply_value_to_targets('selected', False)
def switch_menu(self, menu: ConsoleMenu, controls):
self._active_menu = menu
self._active_controls = controls
def process_user_input(self, buttons):
if self.user_input == '':
self.user_input = 'g'
for button in buttons:
if self.user_input == button.shortcut:
button.press()
def update_output_dir(self):
try:
import readline
readline.parse_and_bind("tab: complete")
readline.set_completer_delims(' \t\n`~!@#$%^&*()-=+[{]}\\|;:\'",<>?')
except ImportError:
# Module readline is not available
pass
self.args.output_dir = input("Please type the full path to the output directory:")
self.fn_buttons: Controls
self.fn_buttons.update_button('o', 'message', "Change output directory [ {} ] ".format(
self.args.output_dir))
def update_user_data(self):
try:
import readline
readline.parse_and_bind("tab: complete")
readline.set_completer_delims(' \t\n`~!@#$%^&*()-=+[{]}\\|;:\'",<>?')
except ImportError:
# Module readline is not available
pass
self.args.user_data = input("Please type the full path to the folder with user data:")
self.fn_buttons: Controls
self.fn_buttons.update_button('u', 'message', "Provide(or change) path to folder with user "
"data\n\t (IRs, models, your application,"
" and associated dependencies) "
"[ {} ]".format(self.args.user_data))
def update_archive_name(self):
self.args.archive_name = input("Please type name of archive without extension:")
self.fn_buttons: Controls
self.fn_buttons.update_button('t', 'message', "Change archive name "
"[ {} ]".format(self.args.archive_name))
def dynamic_fn_header_update(self):
return ["Deployment Manager\nVersion " + self.version,
self.separator, "Review the targets below that will be added "
"into the deployment package.\n"
"If needed, change the output directory or "
"add additional user data from the specific folder.\n",
self.separator, "",
"\nSelected targets:\n\t - {}".format(
"\n\t - ".join(self.get_selected_targets_uinames())), "\n" * 2]
def stop(self):
self.is_running = False
def run(self):
user_selection_map = [
{
"shortcut": "a",
"message": "Select/deselect all\n",
"action": self.select_deselect_all,
},
{
"shortcut": "q",
"message": "Cancel and exit",
"action": exit
}
]
finalization_map = [
{
"shortcut": "b",
"message": "Back to selection dialog",
"action": '',
},
{
"shortcut": "o",
"message": "Change output directory [ {} ] ".format(
os.path.realpath(self.args.output_dir)),
"action": self.update_output_dir,
},
{
"shortcut": "u",
"message": "Provide(or change) path to folder with user data\n\t (IRs, models, "
"your application, and associated dependencies) "
"[ {} ]".format(self.args.user_data),
"action": self.update_user_data,
},
{
"shortcut": "t",
"message": "Change archive name [ {} ]".format(self.args.archive_name),
"action": self.update_archive_name,
},
{
"shortcut": "g",
"message": "Generate package with current selection [ default ]",
"action": self.stop,
},
{
"shortcut": "q",
"message": "Cancel and exit",
"action": exit
}
]
us_hdrs = ["Deployment Manager\nVersion " + self.version,
self.separator]
self.us_buttons = Controls(user_selection_map)
us_imsg = "\nAdd or remove items by typing the number and hitting \"Enter\"\n" \
"Press \"Enter\" to continue.\n" + self.separator + "\n"
fn_hdrs = self.dynamic_fn_header_update()
self.fn_buttons = Controls(finalization_map)
fn_imsg = self.separator + "\nPlease type a selection or press \"Enter\" "
selection_menu = ConsoleMenu(self.us_buttons, us_imsg, us_hdrs, self.available_targets)
finalization_menu = ConsoleMenu(self.fn_buttons, fn_imsg, fn_hdrs)
checkboxes = []
for target in self.available_targets:
checkboxes.append(
ButtonFactory.create_button(shortcut=self.available_targets.index(target) + 1,
message='',
action=target.invert_selection))
def switch_fmenu():
if len(self.get_selected_targets()) > 0:
finalization_menu.sync('headers', self.dynamic_fn_header_update())
self.switch_menu(finalization_menu, self.fn_buttons.get_controls())
else:
self.logger.error("Unable to generate package. No components selected.")
switch_usmenu()
next_btn = Button('g', '', switch_fmenu)
def switch_usmenu():
self.switch_menu(selection_menu,
self.us_buttons.get_controls() + checkboxes + [next_btn])
self.fn_buttons.update_button('b', 'action', switch_usmenu)
self._active_menu = selection_menu
self._active_controls = self.us_buttons.get_controls() + checkboxes + [next_btn]
while self.is_running:
self.user_input = self._active_menu.draw().lower()
self.process_user_input(self._active_controls)
return self.available_targets, self.args