blob: b466580ebf5c034078f2f84f5f0abcddf70b89fb [file] [log] [blame]
# 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
import sys
from typing import Optional, Callable, 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,
on_quit: Optional[Callable] = None):
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
self.on_quit_function = (on_quit if on_quit else
self._default_on_quit_function)
# 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 _default_on_quit_function(self):
if hasattr(self.application, 'application'):
self.application.application.exit()
else:
sys.exit()
def quit_action(self):
self.on_quit_function()
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