diff --git a/jtop/gui/jtopgui.py b/jtop/gui/jtopgui.py index 6548aef0..c2bf5e52 100644 --- a/jtop/gui/jtopgui.py +++ b/jtop/gui/jtopgui.py @@ -33,7 +33,7 @@ # In according with: https://gist.github.com/alanjcastonguay/25e4db0edd3534ab732d6ff615ca9fc1 ABC = abc.ABCMeta('ABC', (object,), {}) # Gui refresh rate -GUI_REFRESH = 1000 // 20 +GUI_REFRESH = 20 # 1000 // 20 # Copyright small COPYRIGHT_SMALL_RE = re.compile(r""".*__cr__ = ["'](.*?)['"]""", re.S) @@ -44,6 +44,7 @@ def __init__(self, name, stdscr, jetson): self.name = name self.stdscr = stdscr self.jetson = jetson + self.dialog_window = None def setcontroller(self, controller): self.controller = controller @@ -57,6 +58,9 @@ def size_page(self): first = 1 return height, width, first + def register_dialog_window(self, dialog_window_object): + self.dialog_window = dialog_window_object + @abc.abstractmethod @check_curses def draw(self, key, mouse): @@ -125,42 +129,28 @@ def run(self, loop, seconds): old = datetime.now() # Here is the loop of our program, we keep clearing and redrawing in this loop while not self.events() and self.jetson.ok(spin=True): + # Get page selected + page = self.pages[self.n_page] + # Check if dialog window is open and disable mouse event on main pages + record_mouse = self.mouse + if page.dialog_window and page.dialog_window.enable_dialog_window: + self.mouse = () # Draw pages - self.draw() + self.draw(page) + self.mouse = record_mouse + # Draw dialog window if it exists + if page.dialog_window: + page.dialog_window.show(self.stdscr, self.key, self.mouse) # Increase page automatically if loop enabled if loop and datetime.now() - old >= timedelta(seconds=seconds): self.increase(loop=True) old = datetime.now() - def dialog_window(self): - height, width = self.stdscr.getmaxyx() - - dialog_height, dialog_width = 10, 46 - dialog_y, dialog_x = (height - dialog_height) // 2, (width - dialog_width) // 2 - dialog_win = curses.newwin(dialog_height, dialog_width, dialog_y, dialog_x) - # Add a border around the window - dialog_win.border() - - # Add text to the dialog window - dialog_win.addstr(1, 2, "System reboot is required to apply changes", curses.A_BOLD) - dialog_win.addstr(3, 1, "1. Option 1") - dialog_win.addstr(4, 1, "2. Option 2") - dialog_win.addstr(5, 1, "3. Option 3") - dialog_win.addstr(7, 1, "Press 'q' to exit") - - # Refresh the window to show the changes - - dialog_win.refresh() - - dialog_win.timeout(GUI_REFRESH * 2) - - def draw(self): + def draw(self, page): # First, clear the screen self.stdscr.erase() # Write head of the jtop self.header() - # Get page selected - page = self.pages[self.n_page] # Draw the page page.draw(self.key, self.mouse) # Draw menu @@ -169,8 +159,6 @@ def draw(self): self.stdscr.refresh() # Set a timeout and read keystroke self.stdscr.timeout(GUI_REFRESH) - - self.dialog_window() def increase(self, loop=False): # check reset diff --git a/jtop/gui/lib/dialog_window.py b/jtop/gui/lib/dialog_window.py new file mode 100644 index 00000000..a001a0fc --- /dev/null +++ b/jtop/gui/lib/dialog_window.py @@ -0,0 +1,71 @@ +# -*- coding: UTF-8 -*- +# This file is part of the jetson_stats package (https://github.com/rbonghi/jetson_stats or http://rnext.it). +# Copyright (c) 2019-2023 Raffaello Bonghi. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +import curses +from .smallbutton import SmallButton, ButtonList +# Gui refresh rate +GUI_REFRESH = 1000 // 20 + + +class DialogWindow(object): + def __init__(self, title, text, on_click, buttons, width=44, height=6): + self.dialog_width = width + self.dialog_height = height + self.title = title + self.text = text + self.on_click = on_click + self.buttons = buttons + self.enable_dialog_window = False + self._dialog_win = None + self.info = {} + + def enable(self, title="", info={}): + if title: + self.title = title + self.info = info + self.enable_dialog_window = True + + def disable(self): + self.enable_dialog_window = False + + def show(self, stdscr, key, mouse): + if self.enable_dialog_window: + self._draw(stdscr, key, mouse) + + def _draw(self, stdscr, key, mouse): + # Refresh the window to show the changes + height, width = stdscr.getmaxyx() + dialog_y, dialog_x = (height - self.dialog_height) // 2, (width - self.dialog_width) // 2 + self._dialog_win = curses.newwin(self.dialog_height, self.dialog_width, dialog_y, dialog_x) + # Create a list of buttons + self._buttons_profile = ButtonList(self._dialog_win, self._on_click, self.buttons, info=self.info, linear=True) + # Add a border around the window + self._dialog_win.border() + # Add the title and the text + self._dialog_win.addstr(1, 2, self.title, curses.A_BOLD) + self._dialog_win.addstr(2, 2, self.text) + # Add the buttons + align_mouse = (mouse[0] - dialog_x, mouse[1] - dialog_y) if mouse else () + self._buttons_profile.update(4, 2, key, align_mouse, "") + # Refresh the window to show the changes + self._dialog_win.refresh() + self._dialog_win.timeout(GUI_REFRESH) + + def _on_click(self, info, selected): + self.on_click(info, selected) + self.enable_dialog_window = False +# EOF diff --git a/jtop/gui/lib/smallbutton.py b/jtop/gui/lib/smallbutton.py index 31fbd770..1960cfef 100644 --- a/jtop/gui/lib/smallbutton.py +++ b/jtop/gui/lib/smallbutton.py @@ -110,12 +110,13 @@ def update(self, y, x, label='', key=None, mouse=None, color=None): class ButtonList: - def __init__(self, stdscr, on_click, buttons=[], info={}): + def __init__(self, stdscr, on_click, buttons=[], info={}, linear=False): self.buttons = [] self.on_click = on_click self.stdscr = stdscr self.info = info self._selected = '' + self.linear = linear # Load all buttons for button in buttons: self.add_button(button) @@ -133,8 +134,13 @@ def update(self, y, x, key, mouse, selected_button, colors=[]): if not colors: colors = [None] * len(self.buttons) # Show all buttons + counter_space = 0 for i, (button, color) in enumerate(zip(self.buttons, colors)): name = button.get_label() button.set_selected(self._selected == name) - button.update(y + i, x, key=key, mouse=mouse, color=color) + if self.linear: + button.update(y, x + counter_space, key=key, mouse=mouse, color=color) + counter_space += len(name) + 3 + else: + button.update(y + i, x, key=key, mouse=mouse, color=color) # EOF diff --git a/jtop/gui/pcontrol.py b/jtop/gui/pcontrol.py index 785e65d3..fc277b24 100644 --- a/jtop/gui/pcontrol.py +++ b/jtop/gui/pcontrol.py @@ -23,6 +23,7 @@ from .lib.colors import NColors from .lib.chart import Chart from .lib.smallbutton import SmallButton, ButtonList +from .lib.dialog_window import DialogWindow FAN_STEP = 10 PROFILE_STR = "Profiles:" @@ -139,6 +140,12 @@ def __init__(self, stdscr, jetson): self._nvpmodel_profile = ButtonList(stdscr, self.action_nvpmodels, self.jetson.nvpmodel.models) self._nvpmodel_increase = SmallButton(stdscr, self.action_nvp_increase, trigger_key='+') self._nvpmodel_decrease = SmallButton(stdscr, self.action_nvp_decrease, trigger_key='-') + # Initialize dialog window + self._dialog_window = DialogWindow("NVP Model", + "Required a reboot to apply this change", + self.dialog_window_nvpmodel, + ["Force and reboot", "Force", "Skip"]) + self.register_dialog_window(self._dialog_window) def action_fan_profile(self, info, selected): # Set new fan profile @@ -172,7 +179,17 @@ def action_jetson_clocks_boot(self, info, selected): def action_nvpmodels(self, info, selected): # Set new nvpmodel - self.jetson.nvpmodel = info['label'] + model_index = self.jetson.nvpmodel.models.index(info['label']) + if not self.jetson.nvpmodel.status[model_index]: + self._dialog_window.enable("NVP model {model_name}".format(model_name=info['label']), info={'name': info['label']}) + else: + self.jetson.nvpmodel = info['label'] + + def dialog_window_nvpmodel(self, info, selected): + if info['label'] == "Force and reboot": + self.jetson.nvpmodel.set_nvpmodel_name(info['name'], force=True, reboot=True) + elif info['label'] == "Force": + self.jetson.nvpmodel.set_nvpmodel_name(info['name'], force=True) def action_nvp_increase(self, info, selected): # NVPmodel controller @@ -195,7 +212,7 @@ def update_chart(self, jetson, name): return { 'value': [speed], } - + def control_jetson_clocks(self, pos_y, pos_x, key, mouse): # Show jetson_clocks try: