Source code for pyplanet.views.generics.alert

import asyncio
import re

from pyplanet.apps.core.maniaplanet.models import Player
from pyplanet.views import TemplateView


[docs]class AlertView(TemplateView): """ The AlertView can be used to show several generic alerts to a player. You can use 3 different sizes, and adjust the message text. The 3 sizes: sm, md and lg. """ template_name = 'core.views/generics/alert.xml' SIZES = dict( sm={ 'top__pos': '0 17', 'top__size': '126.5 8', 'box__size': '120 25', 'bottom__pos': '0 -12', 'bottom__size': '120 2', 'text__pos': '-47.5 6.25', 'text__size': '100 4', 'button_0__pos__left': -32, 'button_0__pos__top': -4, 'button_1__pos__left': 32, 'button_1__pos__top': -4, }, md={ 'top__pos': '0 30', 'top__size': '156.5 8', 'box__size': '150 50', 'bottom__pos': '0 -24', 'bottom__size': '150 2', 'text__pos': '-67.5 6.25', 'text__size': '135 24', 'button_0__pos__left': -32, 'button_0__pos__top': -14, 'button_1__pos__left': 32, 'button_1__pos__top': -14, }, lg={ 'top__pos': '0 55', 'top__size': '206.5 8', 'box__size': '200 100', 'bottom__pos': '0 -50', 'bottom__size': '200 2', 'text__pos': '-92.5 6.25', 'text__size': '185 74', 'button_0__pos__left': -52, 'button_0__pos__top': -40, 'button_1__pos__left': 52, 'button_1__pos__top': -40, }, )
[docs] def __init__( self, message, size='md', buttons=None, manager=None, target=None, **data ): """ Create an AlertView instance. :param message: The message to display to the end-user, Use ``\\n`` for new lines. You can use symbols from FontAwesome by using Unicode escaped strings. :param size: Size to use, this parameter should be a string, and one of the following choices: 'sm', 'md' or 'lg. Defaults to 'md'. :param buttons: Buttons to display, Should be an array with dictionary which contain: name. :param manager: UI Manager to use, You should always keep this undefined unless you know what your doing! :param target: Target coroutine method called as handle of button clicks. :type message: str :type title: str :type size: str :type buttons: list :type manager: pyplanet.core.ui._BaseUIManager """ from pyplanet.core import Controller super().__init__(manager or Controller.instance.ui_manager) self.disable_alt_menu = True sizes = self.SIZES[size] if not buttons: buttons = [{'name': 'OK'}] self.target = target self.response_future = asyncio.Future() self.data = dict( message=message, buttons=buttons, sizes=sizes, ) self.data.update(data)
[docs] async def wait_for_reaction(self): # pragma: no cover """ Wait for reaction or input and return it. :return: Returns the button clicked or the input value string of the user. """ return await self.response_future
async def handle(self, player, action, values, **kwargs): # pragma: no cover await self.close(player) # Try to parse the button id instead of the whole action string. button = action try: match = re.search('button_([0-9]+)$', action) if len(match.groups()) == 1: button = match.group(1) except: pass if not self.response_future.done(): self.response_future.set_result(button) if self.target: await self.target(player, action, values, **kwargs)
[docs] async def close(self, player, **kwargs): # pragma: no cover """ Close the alert. """ await self.hide(player_logins=[player.login])
[docs]class PromptView(AlertView): """ The PromptView is like the AlertView but can ask for a text entry. The 3 sizes: sm, md and lg. You can listen for the results of the players input with the ``wait_for_input()`` async handler (future). Example: .. code-block:: python prompt = PromptView('Please enter your name') await prompt.display(['login']) user_input = await prompt.wait_for_input() print(user_input) You can do validations before it's okay with giving a function to the argument ``validator``. Example: .. code-block:: python def my_validator(value): try: int(value) return True, None except: return False, 'Value should be an integer!' prompt = PromptView('Please enter your name', validator=my_validator) await prompt.display(['login']) user_input = await prompt.wait_for_input() print(user_input) """ template_name = 'core.views/generics/prompt.xml' SIZES = dict( sm={ 'top__pos': '0 24', 'top__size': '126.5 8', 'box__size': '120 40', 'bottom__pos': '0 -20', 'bottom__size': '120 2', 'text__pos': '-47.5 11', 'text__size': '100 4', 'input__pos': '0 0', 'input__size': '100 7', 'button_0__pos__left': -32, 'button_0__pos__top': -12, 'button_1__pos__left': 32, 'button_1__pos__top': -12, }, md={ 'top__pos': '0 38', 'top__size': '156.5 8', 'box__size': '150 67', 'bottom__pos': '0 -34', 'bottom__size': '150 2', 'text__pos': '-67.5 11', 'text__size': '135 24', 'input__pos': '0 -10', 'input__size': '135 7', 'button_0__pos__left': -32, 'button_0__pos__top': -24, 'button_1__pos__left': 32, 'button_1__pos__top': -24, }, lg={ 'top__pos': '0 67', 'top__size': '206.5 8', 'box__size': '200 125', 'bottom__pos': '0 -62', 'bottom__size': '200 2', 'text__pos': '-92.5 11', 'text__size': '185 74', 'input__pos': '0 -40', 'input__size': '185 7', 'button_0__pos__left': -52, 'button_0__pos__top': -52, 'button_1__pos__left': 52, 'button_1__pos__top': -52, }, )
[docs] def __init__(self, message, size='md', buttons=None, manager=None, default='', validator=None): super().__init__(message, size, buttons, manager) self.disable_alt_menu = True self.default = default self.validator = validator or self.validate_input self.data['default'] = self.default
[docs] async def wait_for_input(self): # pragma: no cover """ Wait for input and return it. :return: Returns the string value of the user. """ return await self.response_future
def validate_input(self, value): # pragma: no cover if not value or len(value) == 0: return False, 'Empty value given!' return True, None async def handle(self, player, action, values, **kwargs): # pragma: no cover self.data['errors'] = '' value = self.default if 'prompt_value' in values: value = values['prompt_value'] valid, message = self.validator(value) if valid: await self.close(player) if not self.response_future.done(): self.response_future.set_result(value) return self.data['errors'] = message await self.display([player.login])
# Util methods.
[docs]async def ask_confirmation(player, message, size='md', buttons=None): # pragma: no cover """ Ask the player for confirmation and return the button number (0 is first button). :param player: Player login or instance. :param message: Message to display. :param size: Size, could be 'sm', 'md', or 'lg'. :param buttons: Buttons, optional, default is yes and no. :return: Number of button that is clicked. """ default_buttons_displayed = buttons is None buttons = buttons or [{'name': 'Yes'}, {'name': 'No'}] view = AlertView(message, size, buttons) if isinstance(player, Player): player = player.login await view.display(player_logins=[player]) reaction = await view.wait_for_reaction() try: reaction = int(reaction) except: # If another action is clicked without completing the alert view, the action name (= string) is returned as reaction. # To ensure no action is taken without confirmation, 1 (= No) should be returned if the casting causes an exception. # If custom buttons are used, None will be returned. reaction = 1 if default_buttons_displayed else None del view return reaction
[docs]async def ask_input(player, message, size='md', buttons=None, default=None, validator=None): # pragma: no cover """ Ask the player a question and prompt for input. :param player: Player login or instance. :param message: Message to display. :param size: Size, could be 'sm', 'md', or 'lg' :param buttons: Buttons, optional, default is ok. :param default: The default and pre-filled value. Default empty. :param validator: Validator method, default is only checking if the input isn't empty. :return: Input given by the user. """ buttons = buttons or [{'name': 'OK'}] view = PromptView(message, size, buttons, default=default, validator=validator) if isinstance(player, Player): player = player.login await view.display(player_logins=[player]) output = await view.wait_for_input() del view return output
[docs]async def show_alert(player, message, size='md', buttons=None): # pragma: no cover """ Show an alert to the player with given details. This is a shortcut method for the class itself. :param player: Player login or instance. :param message: Message in string. :param size: Size, could be 'sm', 'md', or 'lg'. :param buttons: Buttons, optional, default is 'OK'. :return: Number of the clicked button. (in Future). """ buttons = buttons or [{'name': 'OK'}] view = AlertView(message, size, buttons) if isinstance(player, Player): player = player.login await view.display(player_logins=[player]) reaction = await view.wait_for_reaction() try: reaction = int(reaction) except: reaction = None del view return reaction