87 lines
3.4 KiB
Python
87 lines
3.4 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
"""This module implements a base class for popups"""
|
||
|
from __future__ import division
|
||
|
from __future__ import absolute_import
|
||
|
from __future__ import print_function
|
||
|
from __future__ import unicode_literals
|
||
|
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(_TempPopup, self).__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:
|
||
|
origin = self._canvas.origin
|
||
|
if event.y < origin[1] or event.y >= origin[1] + self._canvas.height:
|
||
|
event = None
|
||
|
elif event.x < origin[0] or event.x >= origin[0] + self._canvas.width:
|
||
|
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(_TempPopup, self).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.
|
||
|
"""
|