bastd.ui.settings.plugins

Plugin Window UI.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Plugin Window UI."""
  4
  5from __future__ import annotations
  6
  7from typing import TYPE_CHECKING
  8
  9import ba
 10
 11if TYPE_CHECKING:
 12    pass
 13
 14
 15class PluginWindow(ba.Window):
 16    """Window for configuring plugins."""
 17
 18    def __init__(
 19        self,
 20        transition: str = 'in_right',
 21        origin_widget: ba.Widget | None = None,
 22    ):
 23        # pylint: disable=too-many-locals
 24        # pylint: disable=too-many-statements
 25        app = ba.app
 26
 27        # If they provided an origin-widget, scale up from that.
 28        scale_origin: tuple[float, float] | None
 29        if origin_widget is not None:
 30            self._transition_out = 'out_scale'
 31            scale_origin = origin_widget.get_screen_space_center()
 32            transition = 'in_scale'
 33        else:
 34            self._transition_out = 'out_right'
 35            scale_origin = None
 36
 37        uiscale = ba.app.ui.uiscale
 38        self._width = 870.0 if uiscale is ba.UIScale.SMALL else 670.0
 39        x_inset = 100 if uiscale is ba.UIScale.SMALL else 0
 40        self._height = (
 41            390.0
 42            if uiscale is ba.UIScale.SMALL
 43            else 450.0
 44            if uiscale is ba.UIScale.MEDIUM
 45            else 520.0
 46        )
 47        top_extra = 10 if uiscale is ba.UIScale.SMALL else 0
 48        super().__init__(
 49            root_widget=ba.containerwidget(
 50                size=(self._width, self._height + top_extra),
 51                transition=transition,
 52                toolbar_visibility='menu_minimal',
 53                scale_origin_stack_offset=scale_origin,
 54                scale=(
 55                    2.06
 56                    if uiscale is ba.UIScale.SMALL
 57                    else 1.4
 58                    if uiscale is ba.UIScale.MEDIUM
 59                    else 1.0
 60                ),
 61                stack_offset=(0, -25)
 62                if uiscale is ba.UIScale.SMALL
 63                else (0, 0),
 64            )
 65        )
 66
 67        self._scroll_width = self._width - (100 + 2 * x_inset)
 68        self._scroll_height = self._height - 115.0
 69        self._sub_width = self._scroll_width * 0.95
 70        self._sub_height = 724.0
 71
 72        if app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
 73            ba.containerwidget(
 74                edit=self._root_widget, on_cancel_call=self._do_back
 75            )
 76            self._back_button = None
 77        else:
 78            self._back_button = ba.buttonwidget(
 79                parent=self._root_widget,
 80                position=(53 + x_inset, self._height - 60),
 81                size=(140, 60),
 82                scale=0.8,
 83                autoselect=True,
 84                label=ba.Lstr(resource='backText'),
 85                button_type='back',
 86                on_activate_call=self._do_back,
 87            )
 88            ba.containerwidget(
 89                edit=self._root_widget, cancel_button=self._back_button
 90            )
 91
 92        self._title_text = ba.textwidget(
 93            parent=self._root_widget,
 94            position=(0, self._height - 52),
 95            size=(self._width, 25),
 96            text=ba.Lstr(resource='pluginsText'),
 97            color=app.ui.title_color,
 98            h_align='center',
 99            v_align='top',
100        )
101
102        if self._back_button is not None:
103            ba.buttonwidget(
104                edit=self._back_button,
105                button_type='backSmall',
106                size=(60, 60),
107                label=ba.charstr(ba.SpecialChar.BACK),
108            )
109        settings_button_x = 670 if uiscale is ba.UIScale.SMALL else 570
110        self._settings_button = ba.buttonwidget(
111            parent=self._root_widget,
112            position=(settings_button_x, self._height - 60),
113            size=(40, 40),
114            label='',
115            on_activate_call=self._open_settings,
116        )
117
118        ba.imagewidget(
119            parent=self._root_widget,
120            position=(settings_button_x + 3, self._height - 60),
121            size=(35, 35),
122            texture=ba.gettexture('settingsIcon'),
123        )
124
125        ba.widget(
126            edit=self._settings_button,
127            up_widget=self._settings_button,
128            right_widget=self._settings_button,
129        )
130
131        self._scrollwidget = ba.scrollwidget(
132            parent=self._root_widget,
133            position=(50 + x_inset, 50),
134            simple_culling_v=20.0,
135            highlight=False,
136            size=(self._scroll_width, self._scroll_height),
137            selection_loops_to_parent=True,
138            claims_left_right=True,
139        )
140        ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget)
141
142        if ba.app.meta.scanresults is None:
143            ba.screenmessage(
144                'Still scanning plugins; please try again.', color=(1, 0, 0)
145            )
146            ba.playsound(ba.getsound('error'))
147        pluglist = ba.app.plugins.potential_plugins
148        plugstates: dict[str, dict] = ba.app.config.setdefault('Plugins', {})
149        assert isinstance(plugstates, dict)
150
151        plug_line_height = 50
152        sub_width = self._scroll_width
153        sub_height = len(pluglist) * plug_line_height
154        self._subcontainer = ba.containerwidget(
155            parent=self._scrollwidget,
156            size=(sub_width, sub_height),
157            background=False,
158        )
159
160        for i, availplug in enumerate(pluglist):
161            plugin = ba.app.plugins.active_plugins.get(availplug.class_path)
162            active = plugin is not None
163
164            plugstate = plugstates.setdefault(availplug.class_path, {})
165            checked = plugstate.get('enabled', False)
166            assert isinstance(checked, bool)
167
168            item_y = sub_height - (i + 1) * plug_line_height
169            check = ba.checkboxwidget(
170                parent=self._subcontainer,
171                text=availplug.display_name,
172                autoselect=True,
173                value=checked,
174                maxwidth=self._scroll_width - 200,
175                position=(10, item_y),
176                size=(self._scroll_width - 40, 50),
177                on_value_change_call=ba.Call(
178                    self._check_value_changed, availplug
179                ),
180                textcolor=(
181                    (0.8, 0.3, 0.3)
182                    if not availplug.available
183                    else (0, 1, 0)
184                    if active
185                    else (0.6, 0.6, 0.6)
186                ),
187            )
188            if plugin is not None and plugin.has_settings_ui():
189                button = ba.buttonwidget(
190                    parent=self._subcontainer,
191                    label=ba.Lstr(resource='mainMenu.settingsText'),
192                    autoselect=True,
193                    size=(100, 40),
194                    position=(sub_width - 130, item_y + 6),
195                )
196                ba.buttonwidget(
197                    edit=button,
198                    on_activate_call=ba.Call(plugin.show_settings_ui, button),
199                )
200            else:
201                button = None
202
203            # Allow getting back to back button.
204            if i == 0:
205                ba.widget(
206                    edit=check,
207                    up_widget=self._back_button,
208                    left_widget=self._back_button,
209                    right_widget=self._settings_button,
210                )
211                if button is not None:
212                    ba.widget(edit=button, up_widget=self._back_button)
213
214            # Make sure we scroll all the way to the end when using
215            # keyboard/button nav.
216            ba.widget(edit=check, show_buffer_top=40, show_buffer_bottom=40)
217
218        ba.containerwidget(
219            edit=self._root_widget, selected_child=self._scrollwidget
220        )
221
222        self._restore_state()
223
224    def _check_value_changed(
225        self, plug: ba.PotentialPlugin, value: bool
226    ) -> None:
227        ba.screenmessage(
228            ba.Lstr(resource='settingsWindowAdvanced.mustRestartText'),
229            color=(1.0, 0.5, 0.0),
230        )
231        plugstates: dict[str, dict] = ba.app.config.setdefault('Plugins', {})
232        assert isinstance(plugstates, dict)
233        plugstate = plugstates.setdefault(plug.class_path, {})
234        plugstate['enabled'] = value
235        ba.app.config.commit()
236
237    def _open_settings(self) -> None:
238        # pylint: disable=cyclic-import
239        from bastd.ui.settings.pluginsettings import PluginSettingsWindow
240
241        ba.playsound(ba.getsound('swish'))
242
243        ba.containerwidget(edit=self._root_widget, transition='out_left')
244        ba.app.ui.set_main_menu_window(
245            PluginSettingsWindow(transition='in_right').get_root_widget()
246        )
247
248    def _save_state(self) -> None:
249        pass
250
251    def _restore_state(self) -> None:
252        pass
253
254    def _do_back(self) -> None:
255        # pylint: disable=cyclic-import
256        from bastd.ui.settings.advanced import AdvancedSettingsWindow
257
258        self._save_state()
259        ba.containerwidget(
260            edit=self._root_widget, transition=self._transition_out
261        )
262        ba.app.ui.set_main_menu_window(
263            AdvancedSettingsWindow(transition='in_left').get_root_widget()
264        )
class PluginWindow(ba.ui.Window):
 16class PluginWindow(ba.Window):
 17    """Window for configuring plugins."""
 18
 19    def __init__(
 20        self,
 21        transition: str = 'in_right',
 22        origin_widget: ba.Widget | None = None,
 23    ):
 24        # pylint: disable=too-many-locals
 25        # pylint: disable=too-many-statements
 26        app = ba.app
 27
 28        # If they provided an origin-widget, scale up from that.
 29        scale_origin: tuple[float, float] | None
 30        if origin_widget is not None:
 31            self._transition_out = 'out_scale'
 32            scale_origin = origin_widget.get_screen_space_center()
 33            transition = 'in_scale'
 34        else:
 35            self._transition_out = 'out_right'
 36            scale_origin = None
 37
 38        uiscale = ba.app.ui.uiscale
 39        self._width = 870.0 if uiscale is ba.UIScale.SMALL else 670.0
 40        x_inset = 100 if uiscale is ba.UIScale.SMALL else 0
 41        self._height = (
 42            390.0
 43            if uiscale is ba.UIScale.SMALL
 44            else 450.0
 45            if uiscale is ba.UIScale.MEDIUM
 46            else 520.0
 47        )
 48        top_extra = 10 if uiscale is ba.UIScale.SMALL else 0
 49        super().__init__(
 50            root_widget=ba.containerwidget(
 51                size=(self._width, self._height + top_extra),
 52                transition=transition,
 53                toolbar_visibility='menu_minimal',
 54                scale_origin_stack_offset=scale_origin,
 55                scale=(
 56                    2.06
 57                    if uiscale is ba.UIScale.SMALL
 58                    else 1.4
 59                    if uiscale is ba.UIScale.MEDIUM
 60                    else 1.0
 61                ),
 62                stack_offset=(0, -25)
 63                if uiscale is ba.UIScale.SMALL
 64                else (0, 0),
 65            )
 66        )
 67
 68        self._scroll_width = self._width - (100 + 2 * x_inset)
 69        self._scroll_height = self._height - 115.0
 70        self._sub_width = self._scroll_width * 0.95
 71        self._sub_height = 724.0
 72
 73        if app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
 74            ba.containerwidget(
 75                edit=self._root_widget, on_cancel_call=self._do_back
 76            )
 77            self._back_button = None
 78        else:
 79            self._back_button = ba.buttonwidget(
 80                parent=self._root_widget,
 81                position=(53 + x_inset, self._height - 60),
 82                size=(140, 60),
 83                scale=0.8,
 84                autoselect=True,
 85                label=ba.Lstr(resource='backText'),
 86                button_type='back',
 87                on_activate_call=self._do_back,
 88            )
 89            ba.containerwidget(
 90                edit=self._root_widget, cancel_button=self._back_button
 91            )
 92
 93        self._title_text = ba.textwidget(
 94            parent=self._root_widget,
 95            position=(0, self._height - 52),
 96            size=(self._width, 25),
 97            text=ba.Lstr(resource='pluginsText'),
 98            color=app.ui.title_color,
 99            h_align='center',
100            v_align='top',
101        )
102
103        if self._back_button is not None:
104            ba.buttonwidget(
105                edit=self._back_button,
106                button_type='backSmall',
107                size=(60, 60),
108                label=ba.charstr(ba.SpecialChar.BACK),
109            )
110        settings_button_x = 670 if uiscale is ba.UIScale.SMALL else 570
111        self._settings_button = ba.buttonwidget(
112            parent=self._root_widget,
113            position=(settings_button_x, self._height - 60),
114            size=(40, 40),
115            label='',
116            on_activate_call=self._open_settings,
117        )
118
119        ba.imagewidget(
120            parent=self._root_widget,
121            position=(settings_button_x + 3, self._height - 60),
122            size=(35, 35),
123            texture=ba.gettexture('settingsIcon'),
124        )
125
126        ba.widget(
127            edit=self._settings_button,
128            up_widget=self._settings_button,
129            right_widget=self._settings_button,
130        )
131
132        self._scrollwidget = ba.scrollwidget(
133            parent=self._root_widget,
134            position=(50 + x_inset, 50),
135            simple_culling_v=20.0,
136            highlight=False,
137            size=(self._scroll_width, self._scroll_height),
138            selection_loops_to_parent=True,
139            claims_left_right=True,
140        )
141        ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget)
142
143        if ba.app.meta.scanresults is None:
144            ba.screenmessage(
145                'Still scanning plugins; please try again.', color=(1, 0, 0)
146            )
147            ba.playsound(ba.getsound('error'))
148        pluglist = ba.app.plugins.potential_plugins
149        plugstates: dict[str, dict] = ba.app.config.setdefault('Plugins', {})
150        assert isinstance(plugstates, dict)
151
152        plug_line_height = 50
153        sub_width = self._scroll_width
154        sub_height = len(pluglist) * plug_line_height
155        self._subcontainer = ba.containerwidget(
156            parent=self._scrollwidget,
157            size=(sub_width, sub_height),
158            background=False,
159        )
160
161        for i, availplug in enumerate(pluglist):
162            plugin = ba.app.plugins.active_plugins.get(availplug.class_path)
163            active = plugin is not None
164
165            plugstate = plugstates.setdefault(availplug.class_path, {})
166            checked = plugstate.get('enabled', False)
167            assert isinstance(checked, bool)
168
169            item_y = sub_height - (i + 1) * plug_line_height
170            check = ba.checkboxwidget(
171                parent=self._subcontainer,
172                text=availplug.display_name,
173                autoselect=True,
174                value=checked,
175                maxwidth=self._scroll_width - 200,
176                position=(10, item_y),
177                size=(self._scroll_width - 40, 50),
178                on_value_change_call=ba.Call(
179                    self._check_value_changed, availplug
180                ),
181                textcolor=(
182                    (0.8, 0.3, 0.3)
183                    if not availplug.available
184                    else (0, 1, 0)
185                    if active
186                    else (0.6, 0.6, 0.6)
187                ),
188            )
189            if plugin is not None and plugin.has_settings_ui():
190                button = ba.buttonwidget(
191                    parent=self._subcontainer,
192                    label=ba.Lstr(resource='mainMenu.settingsText'),
193                    autoselect=True,
194                    size=(100, 40),
195                    position=(sub_width - 130, item_y + 6),
196                )
197                ba.buttonwidget(
198                    edit=button,
199                    on_activate_call=ba.Call(plugin.show_settings_ui, button),
200                )
201            else:
202                button = None
203
204            # Allow getting back to back button.
205            if i == 0:
206                ba.widget(
207                    edit=check,
208                    up_widget=self._back_button,
209                    left_widget=self._back_button,
210                    right_widget=self._settings_button,
211                )
212                if button is not None:
213                    ba.widget(edit=button, up_widget=self._back_button)
214
215            # Make sure we scroll all the way to the end when using
216            # keyboard/button nav.
217            ba.widget(edit=check, show_buffer_top=40, show_buffer_bottom=40)
218
219        ba.containerwidget(
220            edit=self._root_widget, selected_child=self._scrollwidget
221        )
222
223        self._restore_state()
224
225    def _check_value_changed(
226        self, plug: ba.PotentialPlugin, value: bool
227    ) -> None:
228        ba.screenmessage(
229            ba.Lstr(resource='settingsWindowAdvanced.mustRestartText'),
230            color=(1.0, 0.5, 0.0),
231        )
232        plugstates: dict[str, dict] = ba.app.config.setdefault('Plugins', {})
233        assert isinstance(plugstates, dict)
234        plugstate = plugstates.setdefault(plug.class_path, {})
235        plugstate['enabled'] = value
236        ba.app.config.commit()
237
238    def _open_settings(self) -> None:
239        # pylint: disable=cyclic-import
240        from bastd.ui.settings.pluginsettings import PluginSettingsWindow
241
242        ba.playsound(ba.getsound('swish'))
243
244        ba.containerwidget(edit=self._root_widget, transition='out_left')
245        ba.app.ui.set_main_menu_window(
246            PluginSettingsWindow(transition='in_right').get_root_widget()
247        )
248
249    def _save_state(self) -> None:
250        pass
251
252    def _restore_state(self) -> None:
253        pass
254
255    def _do_back(self) -> None:
256        # pylint: disable=cyclic-import
257        from bastd.ui.settings.advanced import AdvancedSettingsWindow
258
259        self._save_state()
260        ba.containerwidget(
261            edit=self._root_widget, transition=self._transition_out
262        )
263        ba.app.ui.set_main_menu_window(
264            AdvancedSettingsWindow(transition='in_left').get_root_widget()
265        )

Window for configuring plugins.

PluginWindow( transition: str = 'in_right', origin_widget: _ba.Widget | None = None)
 19    def __init__(
 20        self,
 21        transition: str = 'in_right',
 22        origin_widget: ba.Widget | None = None,
 23    ):
 24        # pylint: disable=too-many-locals
 25        # pylint: disable=too-many-statements
 26        app = ba.app
 27
 28        # If they provided an origin-widget, scale up from that.
 29        scale_origin: tuple[float, float] | None
 30        if origin_widget is not None:
 31            self._transition_out = 'out_scale'
 32            scale_origin = origin_widget.get_screen_space_center()
 33            transition = 'in_scale'
 34        else:
 35            self._transition_out = 'out_right'
 36            scale_origin = None
 37
 38        uiscale = ba.app.ui.uiscale
 39        self._width = 870.0 if uiscale is ba.UIScale.SMALL else 670.0
 40        x_inset = 100 if uiscale is ba.UIScale.SMALL else 0
 41        self._height = (
 42            390.0
 43            if uiscale is ba.UIScale.SMALL
 44            else 450.0
 45            if uiscale is ba.UIScale.MEDIUM
 46            else 520.0
 47        )
 48        top_extra = 10 if uiscale is ba.UIScale.SMALL else 0
 49        super().__init__(
 50            root_widget=ba.containerwidget(
 51                size=(self._width, self._height + top_extra),
 52                transition=transition,
 53                toolbar_visibility='menu_minimal',
 54                scale_origin_stack_offset=scale_origin,
 55                scale=(
 56                    2.06
 57                    if uiscale is ba.UIScale.SMALL
 58                    else 1.4
 59                    if uiscale is ba.UIScale.MEDIUM
 60                    else 1.0
 61                ),
 62                stack_offset=(0, -25)
 63                if uiscale is ba.UIScale.SMALL
 64                else (0, 0),
 65            )
 66        )
 67
 68        self._scroll_width = self._width - (100 + 2 * x_inset)
 69        self._scroll_height = self._height - 115.0
 70        self._sub_width = self._scroll_width * 0.95
 71        self._sub_height = 724.0
 72
 73        if app.ui.use_toolbars and uiscale is ba.UIScale.SMALL:
 74            ba.containerwidget(
 75                edit=self._root_widget, on_cancel_call=self._do_back
 76            )
 77            self._back_button = None
 78        else:
 79            self._back_button = ba.buttonwidget(
 80                parent=self._root_widget,
 81                position=(53 + x_inset, self._height - 60),
 82                size=(140, 60),
 83                scale=0.8,
 84                autoselect=True,
 85                label=ba.Lstr(resource='backText'),
 86                button_type='back',
 87                on_activate_call=self._do_back,
 88            )
 89            ba.containerwidget(
 90                edit=self._root_widget, cancel_button=self._back_button
 91            )
 92
 93        self._title_text = ba.textwidget(
 94            parent=self._root_widget,
 95            position=(0, self._height - 52),
 96            size=(self._width, 25),
 97            text=ba.Lstr(resource='pluginsText'),
 98            color=app.ui.title_color,
 99            h_align='center',
100            v_align='top',
101        )
102
103        if self._back_button is not None:
104            ba.buttonwidget(
105                edit=self._back_button,
106                button_type='backSmall',
107                size=(60, 60),
108                label=ba.charstr(ba.SpecialChar.BACK),
109            )
110        settings_button_x = 670 if uiscale is ba.UIScale.SMALL else 570
111        self._settings_button = ba.buttonwidget(
112            parent=self._root_widget,
113            position=(settings_button_x, self._height - 60),
114            size=(40, 40),
115            label='',
116            on_activate_call=self._open_settings,
117        )
118
119        ba.imagewidget(
120            parent=self._root_widget,
121            position=(settings_button_x + 3, self._height - 60),
122            size=(35, 35),
123            texture=ba.gettexture('settingsIcon'),
124        )
125
126        ba.widget(
127            edit=self._settings_button,
128            up_widget=self._settings_button,
129            right_widget=self._settings_button,
130        )
131
132        self._scrollwidget = ba.scrollwidget(
133            parent=self._root_widget,
134            position=(50 + x_inset, 50),
135            simple_culling_v=20.0,
136            highlight=False,
137            size=(self._scroll_width, self._scroll_height),
138            selection_loops_to_parent=True,
139            claims_left_right=True,
140        )
141        ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget)
142
143        if ba.app.meta.scanresults is None:
144            ba.screenmessage(
145                'Still scanning plugins; please try again.', color=(1, 0, 0)
146            )
147            ba.playsound(ba.getsound('error'))
148        pluglist = ba.app.plugins.potential_plugins
149        plugstates: dict[str, dict] = ba.app.config.setdefault('Plugins', {})
150        assert isinstance(plugstates, dict)
151
152        plug_line_height = 50
153        sub_width = self._scroll_width
154        sub_height = len(pluglist) * plug_line_height
155        self._subcontainer = ba.containerwidget(
156            parent=self._scrollwidget,
157            size=(sub_width, sub_height),
158            background=False,
159        )
160
161        for i, availplug in enumerate(pluglist):
162            plugin = ba.app.plugins.active_plugins.get(availplug.class_path)
163            active = plugin is not None
164
165            plugstate = plugstates.setdefault(availplug.class_path, {})
166            checked = plugstate.get('enabled', False)
167            assert isinstance(checked, bool)
168
169            item_y = sub_height - (i + 1) * plug_line_height
170            check = ba.checkboxwidget(
171                parent=self._subcontainer,
172                text=availplug.display_name,
173                autoselect=True,
174                value=checked,
175                maxwidth=self._scroll_width - 200,
176                position=(10, item_y),
177                size=(self._scroll_width - 40, 50),
178                on_value_change_call=ba.Call(
179                    self._check_value_changed, availplug
180                ),
181                textcolor=(
182                    (0.8, 0.3, 0.3)
183                    if not availplug.available
184                    else (0, 1, 0)
185                    if active
186                    else (0.6, 0.6, 0.6)
187                ),
188            )
189            if plugin is not None and plugin.has_settings_ui():
190                button = ba.buttonwidget(
191                    parent=self._subcontainer,
192                    label=ba.Lstr(resource='mainMenu.settingsText'),
193                    autoselect=True,
194                    size=(100, 40),
195                    position=(sub_width - 130, item_y + 6),
196                )
197                ba.buttonwidget(
198                    edit=button,
199                    on_activate_call=ba.Call(plugin.show_settings_ui, button),
200                )
201            else:
202                button = None
203
204            # Allow getting back to back button.
205            if i == 0:
206                ba.widget(
207                    edit=check,
208                    up_widget=self._back_button,
209                    left_widget=self._back_button,
210                    right_widget=self._settings_button,
211                )
212                if button is not None:
213                    ba.widget(edit=button, up_widget=self._back_button)
214
215            # Make sure we scroll all the way to the end when using
216            # keyboard/button nav.
217            ba.widget(edit=check, show_buffer_top=40, show_buffer_bottom=40)
218
219        ba.containerwidget(
220            edit=self._root_widget, selected_child=self._scrollwidget
221        )
222
223        self._restore_state()
Inherited Members
ba.ui.Window
get_root_widget