Source code for ahkpy.message_box

import dataclasses as dc
import functools
from typing import Optional

from .flow import ahk_call

__all__ = [
    "MessageBox",
    "message_box",
]


MESSAGE_BOX_BUTTONS = {
    "ok": 0x00000000,
    "ok_cancel": 0x00000001,
    "abort_retry_ignore": 0x00000002,
    "yes_no_cancel": 0x00000003,
    "yes_no": 0x00000004,
    "retry_cancel": 0x00000005,
    "cancel_try_continue": 0x00000006,
}

MESSAGE_BOX_ICON = {
    None: 0x00000000,
    "hand": 0x00000010,
    "question": 0x00000020,
    "exclamation": 0x00000030,
    "asterisk": 0x00000040,
    "warning": 0x00000030,  # exclamation
    "error": 0x00000010,  # hand
    "information": 0x00000040,  # asterisk
    "info": 0x00000040,  # asterisk
    "stop": 0x00000010,  # hand
}

MESSAGE_BOX_DEFAULT_BUTTON = {
    1: 0x00000000,
    2: 0x00000100,
    3: 0x00000200,
}

MESSAGE_BOX_OPTIONS = {
    "default_desktop_only": 0x00020000,
    "right": 0x00080000,
    "rtl_reading": 0x00100000,
    "service_notification": 0x00200000,
}


[docs]@dc.dataclass class MessageBox: """MessageBox(text=None, title=None, buttons="ok", icon=None, default_button=1, options=[], timeout=None) The utility object to reuse and show message boxes. For information about the arguments refer to :func:`message_box`. The object can be used by setting the message box attributes and calling the :meth:`show` method:: mb = ahkpy.MessageBox(text="hello") # Doesn't show the message box yet mb.text = "hello from attribute" mb.show() # Shows a message box with the text "hello from attribute" mb.show(text="hello from keyword argument") # ^^ Shows a message box with the text "hello from keyword argument" Also, the class can be used by calling its static methods:: ahkpy.MessageBox.info("hello from the static method") # ^^ Shows a message box with the "info" icon """ # Inspired by Python's tkinter.messagebox module and Qt's QMessageBox class. text: Optional[str] = None title: Optional[str] = None buttons: str = "ok" icon: Optional[str] = None default_button: int = 1 options: list = dc.field(default_factory=list) timeout: Optional[int] = None
[docs] def show(self, text=None, title=None, **attrs): """Show the message box with the given attributes.""" attrs["text"] = text if text is not None else self.text attrs["title"] = title if title is not None else self.title if attrs: self = dc.replace(self, **attrs) # MessageBox().show() must act exactly as message_box(). return message_box( self.text, self.title, buttons=self.buttons, icon=self.icon, default_button=self.default_button, options=self.options, timeout=self.timeout, )
[docs] @staticmethod def info(text, title=None, *, buttons="ok", default_button=1, options=[], timeout=None) -> Optional[str]: """info(text, title=None, *, buttons="ok", default_button=1, **attrs) Show an info message. """ return _message_box(text, title, buttons, "info", default_button, options, timeout)
[docs] @staticmethod def warning(text, title=None, *, buttons="ok", default_button=1, options=[], timeout=None) -> Optional[str]: """warning(text, title=None, *, buttons="ok", default_button=1, **attrs) Show a warning message. """ return _message_box(text, title, buttons, "warning", default_button, options, timeout)
[docs] @staticmethod def error(text, title=None, *, buttons="ok", default_button=1, options=[], timeout=None) -> Optional[str]: """error(text, title=None, *, buttons="ok", default_button=1, **attrs) Show an error message. """ return _message_box(text, title, buttons, "error", default_button, options, timeout)
[docs] @staticmethod def ok_cancel(text, title=None, *, icon="info", default_button=1, options=[], timeout=None) -> Optional[bool]: """ok_cancel(text, title=None, *, icon="info", default_button=1, **attrs) Ask if operation should proceed; return ``True`` if the answer is ok. """ # Not using the "question" icon because it's no longer recommended. # https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-messagebox result = _message_box(text, title, "ok_cancel", icon, default_button, options, timeout) if result is None: return None return result == "ok"
[docs] @staticmethod def yes_no(text, title=None, *, icon="info", default_button=1, options=[], timeout=None) -> Optional[bool]: """yes_no(text, title=None, *, icon="info", default_button=1, **attrs) Ask a question; return ``True`` if the answer is yes. """ result = _message_box(text, title, "yes_no", icon, default_button, options, timeout) if result is None: return None return result == "yes"
[docs] @staticmethod def yes_no_cancel(text, title=None, *, icon="info", default_button=1, options=[], timeout=None) -> Optional[str]: """yes_no_cancel(text, title=None, *, icon="info", default_button=1, **attrs) Ask a question; return ``"yes"``, ``"no"``, or ``"cancel"``. """ return _message_box(text, title, "yes_no_cancel", icon, default_button, options, timeout)
[docs] @staticmethod def retry_cancel(text, title=None, *, icon="warning", default_button=1, options=[], timeout=None) -> Optional[bool]: """retry_cancel(text, title=None, *, icon="warning", default_button=1, **attrs) Ask if operation should be retried; return ``True`` if the answer is yes. """ result = _message_box(text, title, "retry_cancel", icon, default_button, options, timeout) if result is None: return None return result == "retry"
[docs] @staticmethod def cancel_try_continue(text, title=None, *, icon="warning", default_button=2, options=[], timeout=None) -> Optional[str]: """cancel_try_continue(text, title=None, *, icon="warning", default_button=2, **attrs) Ask a question; return ``"cancel"``, ``"try"``, or ``"continue"``. """ # Using "cancel_try_continue" instead of "abort_retry_cancel" because # it's more user-friendly. return _message_box(text, title, "cancel_try_continue", icon, default_button, options, timeout)
[docs]def message_box(text=None, title=None, *, buttons="ok", icon=None, default_button=1, options=[], timeout=None) -> Optional[str]: """Display the specified *text* in a small window containing one or more buttons. :param str text: the text to display in the message box. Defaults to "Press OK to continue.". :param str title: the title of the message box window. Defaults to the name of the AHK script (without path), that is, "Python.ahk". :param str buttons: the buttons to display in the message box. Defaults to OK button. Takes one of the following values: - ``"ok"`` - ``"ok_cancel"`` - ``"yes_no_cancel"`` - ``"yes_no"`` - ``"retry_cancel"`` - ``"cancel_try_continue"`` :param str icon: the icon to display. Defaults to no icon. Takes one of the following values: - ``None`` – no icon - ``"info"``, ``"information"``, ``"asterisk"`` – a symbol consisting of a lowercase letter *i* in a circle - ``"warning"``, ``"exclamation"`` – a symbol consisting of an exclamation point in a triangle with a yellow background - ``"error"``, ``"hand"``, ``"stop"`` – a symbol consisting of a white X in a circle with a red background :param int default_button: which button should be focused when the message box is shown. Defaults to the first button in the reading order. Takes integer values from 1 to 3. :param list[str] options: a list of zero or many of the following options: - ``"right"`` – the message box text is right-aligned - ``"rtl_reading"`` – specifies that the message box text is displayed with right to left reading order - ``"service_notification"`` – the message box is displayed on the active desktop - ``"default_desktop_only"`` – the message box is displayed on the active desktop. This is similar to ``"service_notification"``, except that the system displays the message box only on the default desktop of the interactive window station :param float timeout: specifies time in seconds to wait for user's response. After the timeout elapses, the message box will be automatically closed. If *timeout* is not specified or ``None``, there is no limit to the wait time. :return: ``None`` if the timeout has elapsed, or one of the following values that signify the button the user has pressed: - ``"ok"`` - ``"yes"`` - ``"no"`` - ``"cancel"`` - ``"abort"`` - ``"ignore"`` - ``"retry"`` - ``"continue"`` - ``"try_again"`` :command: `MsgBox <https://www.autohotkey.com/docs/commands/MsgBox.htm>`_ """ if text is None: if buttons == "ok" and icon is None: text = "Press OK to continue." else: text = "" return _message_box(text, title, buttons, icon, default_button, options, timeout)
def _message_box(text, title=None, buttons="ok", icon=None, default_button=1, options=[], timeout=None): buttons = MESSAGE_BOX_BUTTONS[buttons] icon = MESSAGE_BOX_ICON[icon] default_button = MESSAGE_BOX_DEFAULT_BUTTON[default_button] def option_reducer(result, option): return result | MESSAGE_BOX_OPTIONS[option] options = functools.reduce(option_reducer, options, 0) result = ahk_call( "MsgBox", buttons | icon | default_button | options, str(title) if title is not None else "", str(text), timeout, ) if result == "timeout": return None return result