1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
|
"""This module implements a base class for popups"""
from collections import defaultdict
from abc import abstractmethod
from asciimatics.event import KeyboardEvent, MouseEvent
from asciimatics.exceptions import InvalidFields
from asciimatics.screen import Screen
from asciimatics.widgets.frame import Frame
class _TempPopup(Frame):
"""
An internal Frame for creating a temporary pop-up for a Widget in another Frame.
"""
def __init__(self, screen, parent, x, y, w, h):
"""
:param screen: The Screen being used for this pop-up.
:param parent: The widget that spawned this pop-up.
:param x: The X coordinate for the desired pop-up.
:param y: The Y coordinate for the desired pop-up.
:param w: The width of the desired pop-up.
:param h: The height of the desired pop-up.
"""
# Construct the Frame
super().__init__(
screen, h, w, x=x, y=y, has_border=True, can_scroll=False, is_modal=True)
# Set up the new palette for this Frame
self.palette = defaultdict(lambda: parent.frame.palette["focus_field"])
self.palette["selected_field"] = parent.frame.palette["selected_field"]
self.palette["selected_focus_field"] = parent.frame.palette["selected_focus_field"]
self.palette["invalid"] = parent.frame.palette["invalid"]
# Internal state for the pop-up
self._parent = parent
def process_event(self, event):
# Look for events that will close the pop-up - e.g. clicking outside the Frame or Enter key.
cancelled = False
if event is not None:
if isinstance(event, KeyboardEvent):
if event.key_code in [Screen.ctrl("M"), Screen.ctrl("J"), ord(" ")]:
event = None
elif event.key_code == Screen.KEY_ESCAPE:
event = None
cancelled = True
elif isinstance(event, MouseEvent) and event.buttons != 0:
if self._outside_frame(event):
event = None
# Remove this pop-up if we're done; otherwise bubble up the event.
if event is None:
try:
self.close(cancelled)
except InvalidFields:
# Nothing to do as we've already prevented the Effect from being removed.
pass
return super().process_event(event)
def close(self, cancelled=False):
"""
Close this temporary pop-up.
:param cancelled: Whether the pop-up was cancelled (e.g. by pressing Esc).
"""
self._on_close(cancelled)
self._scene.remove_effect(self)
@abstractmethod
def _on_close(self, cancelled):
"""
Method to handle any communication back to the parent widget on closure of this pop-up.
:param cancelled: Whether the pop-up was cancelled (e.g. by pressing Esc).
This method can raise an InvalidFields exception to indicate that the current selection is
invalid and so the pop-up cannot be dismissed.
"""
|