bauiv1lib.confirm

Provides ConfirmWindow base class and commonly used derivatives.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Provides ConfirmWindow base class and commonly used derivatives."""
  4
  5from __future__ import annotations
  6
  7from typing import TYPE_CHECKING
  8import logging
  9
 10import bauiv1 as bui
 11
 12if TYPE_CHECKING:
 13    from typing import Any, Callable
 14
 15
 16class ConfirmWindow:
 17    """Window for answering simple yes/no questions."""
 18
 19    def __init__(
 20        self,
 21        text: str | bui.Lstr = 'Are you sure?',
 22        action: Callable[[], Any] | None = None,
 23        width: float = 360.0,
 24        height: float = 100.0,
 25        cancel_button: bool = True,
 26        cancel_is_selected: bool = False,
 27        color: tuple[float, float, float] = (1, 1, 1),
 28        text_scale: float = 1.0,
 29        ok_text: str | bui.Lstr | None = None,
 30        cancel_text: str | bui.Lstr | None = None,
 31        origin_widget: bui.Widget | None = None,
 32    ):
 33        # pylint: disable=too-many-locals
 34        if ok_text is None:
 35            ok_text = bui.Lstr(resource='okText')
 36        if cancel_text is None:
 37            cancel_text = bui.Lstr(resource='cancelText')
 38        height += 40
 39        width = max(width, 360)
 40        self._action = action
 41
 42        # if they provided an origin-widget, scale up from that
 43        self._transition_out: str | None
 44        scale_origin: tuple[float, float] | None
 45        if origin_widget is not None:
 46            self._transition_out = 'out_scale'
 47            scale_origin = origin_widget.get_screen_space_center()
 48            transition = 'in_scale'
 49        else:
 50            self._transition_out = None
 51            scale_origin = None
 52            transition = 'in_right'
 53
 54        assert bui.app.classic is not None
 55        uiscale = bui.app.ui_v1.uiscale
 56        self.root_widget = bui.containerwidget(
 57            size=(width, height),
 58            transition=transition,
 59            toolbar_visibility='menu_minimal_no_back',
 60            parent=bui.get_special_widget('overlay_stack'),
 61            scale=(
 62                2.1
 63                if uiscale is bui.UIScale.SMALL
 64                else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
 65            ),
 66            scale_origin_stack_offset=scale_origin,
 67        )
 68
 69        bui.textwidget(
 70            parent=self.root_widget,
 71            position=(width * 0.5, height - 5 - (height - 75) * 0.5),
 72            size=(0, 0),
 73            h_align='center',
 74            v_align='center',
 75            text=text,
 76            scale=text_scale,
 77            color=color,
 78            maxwidth=width * 0.9,
 79            max_height=height - 75,
 80        )
 81
 82        cbtn: bui.Widget | None
 83        if cancel_button:
 84            cbtn = btn = bui.buttonwidget(
 85                parent=self.root_widget,
 86                autoselect=True,
 87                position=(20, 20),
 88                size=(150, 50),
 89                label=cancel_text,
 90                on_activate_call=self._cancel,
 91            )
 92            bui.containerwidget(edit=self.root_widget, cancel_button=btn)
 93            ok_button_h = width - 175
 94        else:
 95            # if they don't want a cancel button, we still want back presses to
 96            # be able to dismiss the window; just wire it up to do the ok
 97            # button
 98            ok_button_h = width * 0.5 - 75
 99            cbtn = None
100        btn = bui.buttonwidget(
101            parent=self.root_widget,
102            autoselect=True,
103            position=(ok_button_h, 20),
104            size=(150, 50),
105            label=ok_text,
106            on_activate_call=self._ok,
107        )
108
109        # if they didn't want a cancel button, we still want to be able to hit
110        # cancel/back/etc to dismiss the window
111        if not cancel_button:
112            bui.containerwidget(
113                edit=self.root_widget, on_cancel_call=btn.activate
114            )
115
116        bui.containerwidget(
117            edit=self.root_widget,
118            selected_child=(
119                cbtn if cbtn is not None and cancel_is_selected else btn
120            ),
121            start_button=btn,
122        )
123
124    def _cancel(self) -> None:
125        bui.containerwidget(
126            edit=self.root_widget,
127            transition=(
128                'out_right'
129                if self._transition_out is None
130                else self._transition_out
131            ),
132        )
133
134    def _ok(self) -> None:
135        if not self.root_widget:
136            return
137        bui.containerwidget(
138            edit=self.root_widget,
139            transition=(
140                'out_left'
141                if self._transition_out is None
142                else self._transition_out
143            ),
144        )
145        if self._action is not None:
146            self._action()
147
148
149class QuitWindow:
150    """Popup window to confirm quitting."""
151
152    def __init__(
153        self,
154        quit_type: bui.QuitType | None = None,
155        swish: bool = False,
156        origin_widget: bui.Widget | None = None,
157    ):
158        classic = bui.app.classic
159        assert classic is not None
160        ui = bui.app.ui_v1
161        app = bui.app
162        self._quit_type = quit_type
163
164        # If there's already one of us up somewhere, kill it.
165        if ui.quit_window is not None:
166            ui.quit_window.delete()
167            ui.quit_window = None
168        if swish:
169            bui.getsound('swish').play()
170
171        if app.classic is None:
172            if bui.do_once():
173                logging.warning(
174                    'QuitWindow needs to be updated to work without classic.'
175                )
176            quit_resource = 'exitGameText'
177        else:
178            quit_resource = (
179                'quitGameText'
180                if app.classic.platform == 'mac'
181                else 'exitGameText'
182            )
183        self._root_widget = ui.quit_window = ConfirmWindow(
184            bui.Lstr(
185                resource=quit_resource,
186                subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
187            ),
188            lambda: (
189                bui.quit(confirm=False, quit_type=self._quit_type)
190                if self._quit_type is not None
191                else bui.quit(confirm=False)
192            ),
193            origin_widget=origin_widget,
194        ).root_widget
class ConfirmWindow:
 17class ConfirmWindow:
 18    """Window for answering simple yes/no questions."""
 19
 20    def __init__(
 21        self,
 22        text: str | bui.Lstr = 'Are you sure?',
 23        action: Callable[[], Any] | None = None,
 24        width: float = 360.0,
 25        height: float = 100.0,
 26        cancel_button: bool = True,
 27        cancel_is_selected: bool = False,
 28        color: tuple[float, float, float] = (1, 1, 1),
 29        text_scale: float = 1.0,
 30        ok_text: str | bui.Lstr | None = None,
 31        cancel_text: str | bui.Lstr | None = None,
 32        origin_widget: bui.Widget | None = None,
 33    ):
 34        # pylint: disable=too-many-locals
 35        if ok_text is None:
 36            ok_text = bui.Lstr(resource='okText')
 37        if cancel_text is None:
 38            cancel_text = bui.Lstr(resource='cancelText')
 39        height += 40
 40        width = max(width, 360)
 41        self._action = action
 42
 43        # if they provided an origin-widget, scale up from that
 44        self._transition_out: str | None
 45        scale_origin: tuple[float, float] | None
 46        if origin_widget is not None:
 47            self._transition_out = 'out_scale'
 48            scale_origin = origin_widget.get_screen_space_center()
 49            transition = 'in_scale'
 50        else:
 51            self._transition_out = None
 52            scale_origin = None
 53            transition = 'in_right'
 54
 55        assert bui.app.classic is not None
 56        uiscale = bui.app.ui_v1.uiscale
 57        self.root_widget = bui.containerwidget(
 58            size=(width, height),
 59            transition=transition,
 60            toolbar_visibility='menu_minimal_no_back',
 61            parent=bui.get_special_widget('overlay_stack'),
 62            scale=(
 63                2.1
 64                if uiscale is bui.UIScale.SMALL
 65                else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
 66            ),
 67            scale_origin_stack_offset=scale_origin,
 68        )
 69
 70        bui.textwidget(
 71            parent=self.root_widget,
 72            position=(width * 0.5, height - 5 - (height - 75) * 0.5),
 73            size=(0, 0),
 74            h_align='center',
 75            v_align='center',
 76            text=text,
 77            scale=text_scale,
 78            color=color,
 79            maxwidth=width * 0.9,
 80            max_height=height - 75,
 81        )
 82
 83        cbtn: bui.Widget | None
 84        if cancel_button:
 85            cbtn = btn = bui.buttonwidget(
 86                parent=self.root_widget,
 87                autoselect=True,
 88                position=(20, 20),
 89                size=(150, 50),
 90                label=cancel_text,
 91                on_activate_call=self._cancel,
 92            )
 93            bui.containerwidget(edit=self.root_widget, cancel_button=btn)
 94            ok_button_h = width - 175
 95        else:
 96            # if they don't want a cancel button, we still want back presses to
 97            # be able to dismiss the window; just wire it up to do the ok
 98            # button
 99            ok_button_h = width * 0.5 - 75
100            cbtn = None
101        btn = bui.buttonwidget(
102            parent=self.root_widget,
103            autoselect=True,
104            position=(ok_button_h, 20),
105            size=(150, 50),
106            label=ok_text,
107            on_activate_call=self._ok,
108        )
109
110        # if they didn't want a cancel button, we still want to be able to hit
111        # cancel/back/etc to dismiss the window
112        if not cancel_button:
113            bui.containerwidget(
114                edit=self.root_widget, on_cancel_call=btn.activate
115            )
116
117        bui.containerwidget(
118            edit=self.root_widget,
119            selected_child=(
120                cbtn if cbtn is not None and cancel_is_selected else btn
121            ),
122            start_button=btn,
123        )
124
125    def _cancel(self) -> None:
126        bui.containerwidget(
127            edit=self.root_widget,
128            transition=(
129                'out_right'
130                if self._transition_out is None
131                else self._transition_out
132            ),
133        )
134
135    def _ok(self) -> None:
136        if not self.root_widget:
137            return
138        bui.containerwidget(
139            edit=self.root_widget,
140            transition=(
141                'out_left'
142                if self._transition_out is None
143                else self._transition_out
144            ),
145        )
146        if self._action is not None:
147            self._action()

Window for answering simple yes/no questions.

ConfirmWindow( text: str | babase._language.Lstr = 'Are you sure?', action: Optional[Callable[[], Any]] = None, width: float = 360.0, height: float = 100.0, cancel_button: bool = True, cancel_is_selected: bool = False, color: tuple[float, float, float] = (1, 1, 1), text_scale: float = 1.0, ok_text: str | babase._language.Lstr | None = None, cancel_text: str | babase._language.Lstr | None = None, origin_widget: _bauiv1.Widget | None = None)
 20    def __init__(
 21        self,
 22        text: str | bui.Lstr = 'Are you sure?',
 23        action: Callable[[], Any] | None = None,
 24        width: float = 360.0,
 25        height: float = 100.0,
 26        cancel_button: bool = True,
 27        cancel_is_selected: bool = False,
 28        color: tuple[float, float, float] = (1, 1, 1),
 29        text_scale: float = 1.0,
 30        ok_text: str | bui.Lstr | None = None,
 31        cancel_text: str | bui.Lstr | None = None,
 32        origin_widget: bui.Widget | None = None,
 33    ):
 34        # pylint: disable=too-many-locals
 35        if ok_text is None:
 36            ok_text = bui.Lstr(resource='okText')
 37        if cancel_text is None:
 38            cancel_text = bui.Lstr(resource='cancelText')
 39        height += 40
 40        width = max(width, 360)
 41        self._action = action
 42
 43        # if they provided an origin-widget, scale up from that
 44        self._transition_out: str | None
 45        scale_origin: tuple[float, float] | None
 46        if origin_widget is not None:
 47            self._transition_out = 'out_scale'
 48            scale_origin = origin_widget.get_screen_space_center()
 49            transition = 'in_scale'
 50        else:
 51            self._transition_out = None
 52            scale_origin = None
 53            transition = 'in_right'
 54
 55        assert bui.app.classic is not None
 56        uiscale = bui.app.ui_v1.uiscale
 57        self.root_widget = bui.containerwidget(
 58            size=(width, height),
 59            transition=transition,
 60            toolbar_visibility='menu_minimal_no_back',
 61            parent=bui.get_special_widget('overlay_stack'),
 62            scale=(
 63                2.1
 64                if uiscale is bui.UIScale.SMALL
 65                else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
 66            ),
 67            scale_origin_stack_offset=scale_origin,
 68        )
 69
 70        bui.textwidget(
 71            parent=self.root_widget,
 72            position=(width * 0.5, height - 5 - (height - 75) * 0.5),
 73            size=(0, 0),
 74            h_align='center',
 75            v_align='center',
 76            text=text,
 77            scale=text_scale,
 78            color=color,
 79            maxwidth=width * 0.9,
 80            max_height=height - 75,
 81        )
 82
 83        cbtn: bui.Widget | None
 84        if cancel_button:
 85            cbtn = btn = bui.buttonwidget(
 86                parent=self.root_widget,
 87                autoselect=True,
 88                position=(20, 20),
 89                size=(150, 50),
 90                label=cancel_text,
 91                on_activate_call=self._cancel,
 92            )
 93            bui.containerwidget(edit=self.root_widget, cancel_button=btn)
 94            ok_button_h = width - 175
 95        else:
 96            # if they don't want a cancel button, we still want back presses to
 97            # be able to dismiss the window; just wire it up to do the ok
 98            # button
 99            ok_button_h = width * 0.5 - 75
100            cbtn = None
101        btn = bui.buttonwidget(
102            parent=self.root_widget,
103            autoselect=True,
104            position=(ok_button_h, 20),
105            size=(150, 50),
106            label=ok_text,
107            on_activate_call=self._ok,
108        )
109
110        # if they didn't want a cancel button, we still want to be able to hit
111        # cancel/back/etc to dismiss the window
112        if not cancel_button:
113            bui.containerwidget(
114                edit=self.root_widget, on_cancel_call=btn.activate
115            )
116
117        bui.containerwidget(
118            edit=self.root_widget,
119            selected_child=(
120                cbtn if cbtn is not None and cancel_is_selected else btn
121            ),
122            start_button=btn,
123        )
root_widget
class QuitWindow:
150class QuitWindow:
151    """Popup window to confirm quitting."""
152
153    def __init__(
154        self,
155        quit_type: bui.QuitType | None = None,
156        swish: bool = False,
157        origin_widget: bui.Widget | None = None,
158    ):
159        classic = bui.app.classic
160        assert classic is not None
161        ui = bui.app.ui_v1
162        app = bui.app
163        self._quit_type = quit_type
164
165        # If there's already one of us up somewhere, kill it.
166        if ui.quit_window is not None:
167            ui.quit_window.delete()
168            ui.quit_window = None
169        if swish:
170            bui.getsound('swish').play()
171
172        if app.classic is None:
173            if bui.do_once():
174                logging.warning(
175                    'QuitWindow needs to be updated to work without classic.'
176                )
177            quit_resource = 'exitGameText'
178        else:
179            quit_resource = (
180                'quitGameText'
181                if app.classic.platform == 'mac'
182                else 'exitGameText'
183            )
184        self._root_widget = ui.quit_window = ConfirmWindow(
185            bui.Lstr(
186                resource=quit_resource,
187                subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
188            ),
189            lambda: (
190                bui.quit(confirm=False, quit_type=self._quit_type)
191                if self._quit_type is not None
192                else bui.quit(confirm=False)
193            ),
194            origin_widget=origin_widget,
195        ).root_widget

Popup window to confirm quitting.

QuitWindow( quit_type: babase._mgen.enums.QuitType | None = None, swish: bool = False, origin_widget: _bauiv1.Widget | None = None)
153    def __init__(
154        self,
155        quit_type: bui.QuitType | None = None,
156        swish: bool = False,
157        origin_widget: bui.Widget | None = None,
158    ):
159        classic = bui.app.classic
160        assert classic is not None
161        ui = bui.app.ui_v1
162        app = bui.app
163        self._quit_type = quit_type
164
165        # If there's already one of us up somewhere, kill it.
166        if ui.quit_window is not None:
167            ui.quit_window.delete()
168            ui.quit_window = None
169        if swish:
170            bui.getsound('swish').play()
171
172        if app.classic is None:
173            if bui.do_once():
174                logging.warning(
175                    'QuitWindow needs to be updated to work without classic.'
176                )
177            quit_resource = 'exitGameText'
178        else:
179            quit_resource = (
180                'quitGameText'
181                if app.classic.platform == 'mac'
182                else 'exitGameText'
183            )
184        self._root_widget = ui.quit_window = ConfirmWindow(
185            bui.Lstr(
186                resource=quit_resource,
187                subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
188            ),
189            lambda: (
190                bui.quit(confirm=False, quit_type=self._quit_type)
191                if self._quit_type is not None
192                else bui.quit(confirm=False)
193            ),
194            origin_widget=origin_widget,
195        ).root_widget