| # Copyright 2022 The Pigweed Authors |
| # |
| # 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 |
| # |
| # https://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. |
| """LogPane Info Toolbar classes.""" |
| |
| from __future__ import annotations |
| import functools |
| import logging |
| from typing import TYPE_CHECKING |
| |
| from prompt_toolkit.data_structures import Point |
| from prompt_toolkit.key_binding import KeyBindings, KeyPressEvent |
| from prompt_toolkit.filters import Condition |
| from prompt_toolkit.layout import ( |
| ConditionalContainer, |
| FormattedTextControl, |
| HSplit, |
| Window, |
| WindowAlign, |
| ) |
| |
| import pw_console.widgets.border |
| import pw_console.widgets.checkbox |
| import pw_console.widgets.mouse_handlers |
| |
| if TYPE_CHECKING: |
| from pw_console.console_app import ConsoleApp |
| |
| _LOG = logging.getLogger(__package__) |
| |
| |
| class QuitDialog(ConditionalContainer): |
| """Confirmation quit dialog box.""" |
| |
| DIALOG_HEIGHT = 2 |
| |
| def __init__(self, application: ConsoleApp): |
| self.application = application |
| self.show_dialog = False |
| # Tracks the last focused container, to enable restoring focus after |
| # closing the dialog. |
| self.last_focused_pane = None |
| |
| # Quit keybindings are active when this dialog is in focus |
| key_bindings = KeyBindings() |
| register = self.application.prefs.register_keybinding |
| |
| @register('quit-dialog.yes', key_bindings) |
| def _quit(_event: KeyPressEvent) -> None: |
| """Close save as bar.""" |
| self.quit_action() |
| |
| @register('quit-dialog.no', key_bindings) |
| def _cancel(_event: KeyPressEvent) -> None: |
| """Close save as bar.""" |
| self.close_dialog() |
| |
| self.exit_message = 'Quit? y/n ' |
| |
| action_bar_control = FormattedTextControl( |
| self.get_action_fragments, |
| show_cursor=True, |
| focusable=True, |
| key_bindings=key_bindings, |
| # Cursor will appear after the exit_message |
| get_cursor_position=lambda: Point(len(self.exit_message), 0), |
| ) |
| |
| action_bar_window = Window(content=action_bar_control, |
| height=QuitDialog.DIALOG_HEIGHT, |
| align=WindowAlign.LEFT, |
| dont_extend_width=False) |
| |
| super().__init__( |
| pw_console.widgets.border.create_border( |
| HSplit( |
| [action_bar_window], |
| height=QuitDialog.DIALOG_HEIGHT, |
| style='class:quit-dialog', |
| ), |
| QuitDialog.DIALOG_HEIGHT, |
| border_style='class:quit-dialog-border', |
| left_margin_columns=1, |
| ), |
| filter=Condition(lambda: self.show_dialog), |
| ) |
| |
| def focus_self(self): |
| self.application.layout.focus(self) |
| |
| def close_dialog(self): |
| """Close this dialog box.""" |
| self.show_dialog = False |
| # Restore original focus if possible. |
| if self.last_focused_pane: |
| self.application.layout.focus(self.last_focused_pane) |
| else: |
| # Fallback to focusing on the main menu. |
| self.application.focus_main_menu() |
| |
| def open_dialog(self): |
| self.show_dialog = True |
| self.last_focused_pane = self.application.focused_window() |
| self.focus_self() |
| self.application.redraw_ui() |
| |
| def quit_action(self): |
| self.application.application.exit() |
| |
| def get_action_fragments(self): |
| """Return FormattedText with action buttons.""" |
| |
| # Mouse handlers |
| focus = functools.partial(pw_console.widgets.mouse_handlers.on_click, |
| self.focus_self) |
| cancel = functools.partial(pw_console.widgets.mouse_handlers.on_click, |
| self.close_dialog) |
| quit_action = functools.partial( |
| pw_console.widgets.mouse_handlers.on_click, self.quit_action) |
| |
| # Separator should have the focus mouse handler so clicking on any |
| # whitespace focuses the input field. |
| separator_text = ('', ' ', focus) |
| |
| # Default button style |
| button_style = 'class:toolbar-button-inactive' |
| |
| fragments = [('', self.exit_message), separator_text] |
| fragments.append(('', '\n')) |
| |
| # Cancel button |
| fragments.extend( |
| pw_console.widgets.checkbox.to_keybind_indicator( |
| key='n / Ctrl-c', |
| description='Cancel', |
| mouse_handler=cancel, |
| base_style=button_style, |
| )) |
| |
| # Two space separator |
| fragments.append(separator_text) |
| |
| # Save button |
| fragments.extend( |
| pw_console.widgets.checkbox.to_keybind_indicator( |
| key='y / Ctrl-d', |
| description='Quit', |
| mouse_handler=quit_action, |
| base_style=button_style, |
| )) |
| |
| # One space separator |
| fragments.append(('', ' ', focus)) |
| |
| return fragments |