bastd.ui.gather.nearbytab

Defines the nearby tab in the gather UI.

  1# Released under the MIT License. See LICENSE for details.
  2#
  3"""Defines the nearby tab in the gather UI."""
  4
  5from __future__ import annotations
  6
  7import weakref
  8from typing import TYPE_CHECKING
  9
 10import ba
 11import ba.internal
 12from bastd.ui.gather import GatherTab
 13
 14if TYPE_CHECKING:
 15    from typing import Any
 16    from bastd.ui.gather import GatherWindow
 17
 18
 19class NetScanner:
 20    """Class for scanning for games on the lan."""
 21
 22    def __init__(
 23        self,
 24        tab: GatherTab,
 25        scrollwidget: ba.Widget,
 26        tab_button: ba.Widget,
 27        width: float,
 28    ):
 29        self._tab = weakref.ref(tab)
 30        self._scrollwidget = scrollwidget
 31        self._tab_button = tab_button
 32        self._columnwidget = ba.columnwidget(
 33            parent=self._scrollwidget, border=2, margin=0, left_border=10
 34        )
 35        ba.widget(edit=self._columnwidget, up_widget=tab_button)
 36        self._width = width
 37        self._last_selected_host: dict[str, Any] | None = None
 38
 39        self._update_timer = ba.Timer(
 40            1.0,
 41            ba.WeakCall(self.update),
 42            timetype=ba.TimeType.REAL,
 43            repeat=True,
 44        )
 45        # Go ahead and run a few *almost* immediately so we don't
 46        # have to wait a second.
 47        self.update()
 48        ba.timer(0.25, ba.WeakCall(self.update), timetype=ba.TimeType.REAL)
 49
 50    def __del__(self) -> None:
 51        ba.internal.end_host_scanning()
 52
 53    def _on_select(self, host: dict[str, Any]) -> None:
 54        self._last_selected_host = host
 55
 56    def _on_activate(self, host: dict[str, Any]) -> None:
 57        ba.internal.connect_to_party(host['address'])
 58
 59    def update(self) -> None:
 60        """(internal)"""
 61
 62        # In case our UI was killed from under us.
 63        if not self._columnwidget:
 64            print(
 65                f'ERROR: NetScanner running without UI at time'
 66                f' {ba.time(timetype=ba.TimeType.REAL)}.'
 67            )
 68            return
 69
 70        t_scale = 1.6
 71        for child in self._columnwidget.get_children():
 72            child.delete()
 73
 74        # Grab this now this since adding widgets will change it.
 75        last_selected_host = self._last_selected_host
 76        hosts = ba.internal.host_scan_cycle()
 77        for i, host in enumerate(hosts):
 78            txt3 = ba.textwidget(
 79                parent=self._columnwidget,
 80                size=(self._width / t_scale, 30),
 81                selectable=True,
 82                color=(1, 1, 1),
 83                on_select_call=ba.Call(self._on_select, host),
 84                on_activate_call=ba.Call(self._on_activate, host),
 85                click_activate=True,
 86                text=host['display_string'],
 87                h_align='left',
 88                v_align='center',
 89                corner_scale=t_scale,
 90                maxwidth=(self._width / t_scale) * 0.93,
 91            )
 92            if host == last_selected_host:
 93                ba.containerwidget(
 94                    edit=self._columnwidget,
 95                    selected_child=txt3,
 96                    visible_child=txt3,
 97                )
 98            if i == 0:
 99                ba.widget(edit=txt3, up_widget=self._tab_button)
100
101
102class NearbyGatherTab(GatherTab):
103    """The nearby tab in the gather UI"""
104
105    def __init__(self, window: GatherWindow) -> None:
106        super().__init__(window)
107        self._net_scanner: NetScanner | None = None
108        self._container: ba.Widget | None = None
109
110    def on_activate(
111        self,
112        parent_widget: ba.Widget,
113        tab_button: ba.Widget,
114        region_width: float,
115        region_height: float,
116        region_left: float,
117        region_bottom: float,
118    ) -> ba.Widget:
119        c_width = region_width
120        c_height = region_height - 20
121        sub_scroll_height = c_height - 85
122        sub_scroll_width = 650
123        self._container = ba.containerwidget(
124            parent=parent_widget,
125            position=(
126                region_left,
127                region_bottom + (region_height - c_height) * 0.5,
128            ),
129            size=(c_width, c_height),
130            background=False,
131            selection_loops_to_parent=True,
132        )
133        v = c_height - 30
134        ba.textwidget(
135            parent=self._container,
136            position=(c_width * 0.5, v - 3),
137            color=(0.6, 1.0, 0.6),
138            scale=1.3,
139            size=(0, 0),
140            maxwidth=c_width * 0.9,
141            h_align='center',
142            v_align='center',
143            text=ba.Lstr(
144                resource='gatherWindow.' 'localNetworkDescriptionText'
145            ),
146        )
147        v -= 15
148        v -= sub_scroll_height + 23
149        scrollw = ba.scrollwidget(
150            parent=self._container,
151            position=((region_width - sub_scroll_width) * 0.5, v),
152            size=(sub_scroll_width, sub_scroll_height),
153        )
154
155        self._net_scanner = NetScanner(
156            self, scrollw, tab_button, width=sub_scroll_width
157        )
158
159        ba.widget(edit=scrollw, autoselect=True, up_widget=tab_button)
160        return self._container
161
162    def on_deactivate(self) -> None:
163        self._net_scanner = None
class NetScanner:
 20class NetScanner:
 21    """Class for scanning for games on the lan."""
 22
 23    def __init__(
 24        self,
 25        tab: GatherTab,
 26        scrollwidget: ba.Widget,
 27        tab_button: ba.Widget,
 28        width: float,
 29    ):
 30        self._tab = weakref.ref(tab)
 31        self._scrollwidget = scrollwidget
 32        self._tab_button = tab_button
 33        self._columnwidget = ba.columnwidget(
 34            parent=self._scrollwidget, border=2, margin=0, left_border=10
 35        )
 36        ba.widget(edit=self._columnwidget, up_widget=tab_button)
 37        self._width = width
 38        self._last_selected_host: dict[str, Any] | None = None
 39
 40        self._update_timer = ba.Timer(
 41            1.0,
 42            ba.WeakCall(self.update),
 43            timetype=ba.TimeType.REAL,
 44            repeat=True,
 45        )
 46        # Go ahead and run a few *almost* immediately so we don't
 47        # have to wait a second.
 48        self.update()
 49        ba.timer(0.25, ba.WeakCall(self.update), timetype=ba.TimeType.REAL)
 50
 51    def __del__(self) -> None:
 52        ba.internal.end_host_scanning()
 53
 54    def _on_select(self, host: dict[str, Any]) -> None:
 55        self._last_selected_host = host
 56
 57    def _on_activate(self, host: dict[str, Any]) -> None:
 58        ba.internal.connect_to_party(host['address'])
 59
 60    def update(self) -> None:
 61        """(internal)"""
 62
 63        # In case our UI was killed from under us.
 64        if not self._columnwidget:
 65            print(
 66                f'ERROR: NetScanner running without UI at time'
 67                f' {ba.time(timetype=ba.TimeType.REAL)}.'
 68            )
 69            return
 70
 71        t_scale = 1.6
 72        for child in self._columnwidget.get_children():
 73            child.delete()
 74
 75        # Grab this now this since adding widgets will change it.
 76        last_selected_host = self._last_selected_host
 77        hosts = ba.internal.host_scan_cycle()
 78        for i, host in enumerate(hosts):
 79            txt3 = ba.textwidget(
 80                parent=self._columnwidget,
 81                size=(self._width / t_scale, 30),
 82                selectable=True,
 83                color=(1, 1, 1),
 84                on_select_call=ba.Call(self._on_select, host),
 85                on_activate_call=ba.Call(self._on_activate, host),
 86                click_activate=True,
 87                text=host['display_string'],
 88                h_align='left',
 89                v_align='center',
 90                corner_scale=t_scale,
 91                maxwidth=(self._width / t_scale) * 0.93,
 92            )
 93            if host == last_selected_host:
 94                ba.containerwidget(
 95                    edit=self._columnwidget,
 96                    selected_child=txt3,
 97                    visible_child=txt3,
 98                )
 99            if i == 0:
100                ba.widget(edit=txt3, up_widget=self._tab_button)

Class for scanning for games on the lan.

NetScanner( tab: bastd.ui.gather.GatherTab, scrollwidget: _ba.Widget, tab_button: _ba.Widget, width: float)
23    def __init__(
24        self,
25        tab: GatherTab,
26        scrollwidget: ba.Widget,
27        tab_button: ba.Widget,
28        width: float,
29    ):
30        self._tab = weakref.ref(tab)
31        self._scrollwidget = scrollwidget
32        self._tab_button = tab_button
33        self._columnwidget = ba.columnwidget(
34            parent=self._scrollwidget, border=2, margin=0, left_border=10
35        )
36        ba.widget(edit=self._columnwidget, up_widget=tab_button)
37        self._width = width
38        self._last_selected_host: dict[str, Any] | None = None
39
40        self._update_timer = ba.Timer(
41            1.0,
42            ba.WeakCall(self.update),
43            timetype=ba.TimeType.REAL,
44            repeat=True,
45        )
46        # Go ahead and run a few *almost* immediately so we don't
47        # have to wait a second.
48        self.update()
49        ba.timer(0.25, ba.WeakCall(self.update), timetype=ba.TimeType.REAL)
class NearbyGatherTab(bastd.ui.gather.GatherTab):
103class NearbyGatherTab(GatherTab):
104    """The nearby tab in the gather UI"""
105
106    def __init__(self, window: GatherWindow) -> None:
107        super().__init__(window)
108        self._net_scanner: NetScanner | None = None
109        self._container: ba.Widget | None = None
110
111    def on_activate(
112        self,
113        parent_widget: ba.Widget,
114        tab_button: ba.Widget,
115        region_width: float,
116        region_height: float,
117        region_left: float,
118        region_bottom: float,
119    ) -> ba.Widget:
120        c_width = region_width
121        c_height = region_height - 20
122        sub_scroll_height = c_height - 85
123        sub_scroll_width = 650
124        self._container = ba.containerwidget(
125            parent=parent_widget,
126            position=(
127                region_left,
128                region_bottom + (region_height - c_height) * 0.5,
129            ),
130            size=(c_width, c_height),
131            background=False,
132            selection_loops_to_parent=True,
133        )
134        v = c_height - 30
135        ba.textwidget(
136            parent=self._container,
137            position=(c_width * 0.5, v - 3),
138            color=(0.6, 1.0, 0.6),
139            scale=1.3,
140            size=(0, 0),
141            maxwidth=c_width * 0.9,
142            h_align='center',
143            v_align='center',
144            text=ba.Lstr(
145                resource='gatherWindow.' 'localNetworkDescriptionText'
146            ),
147        )
148        v -= 15
149        v -= sub_scroll_height + 23
150        scrollw = ba.scrollwidget(
151            parent=self._container,
152            position=((region_width - sub_scroll_width) * 0.5, v),
153            size=(sub_scroll_width, sub_scroll_height),
154        )
155
156        self._net_scanner = NetScanner(
157            self, scrollw, tab_button, width=sub_scroll_width
158        )
159
160        ba.widget(edit=scrollw, autoselect=True, up_widget=tab_button)
161        return self._container
162
163    def on_deactivate(self) -> None:
164        self._net_scanner = None

The nearby tab in the gather UI

NearbyGatherTab(window: bastd.ui.gather.GatherWindow)
106    def __init__(self, window: GatherWindow) -> None:
107        super().__init__(window)
108        self._net_scanner: NetScanner | None = None
109        self._container: ba.Widget | None = None
def on_activate( self, parent_widget: _ba.Widget, tab_button: _ba.Widget, region_width: float, region_height: float, region_left: float, region_bottom: float) -> _ba.Widget:
111    def on_activate(
112        self,
113        parent_widget: ba.Widget,
114        tab_button: ba.Widget,
115        region_width: float,
116        region_height: float,
117        region_left: float,
118        region_bottom: float,
119    ) -> ba.Widget:
120        c_width = region_width
121        c_height = region_height - 20
122        sub_scroll_height = c_height - 85
123        sub_scroll_width = 650
124        self._container = ba.containerwidget(
125            parent=parent_widget,
126            position=(
127                region_left,
128                region_bottom + (region_height - c_height) * 0.5,
129            ),
130            size=(c_width, c_height),
131            background=False,
132            selection_loops_to_parent=True,
133        )
134        v = c_height - 30
135        ba.textwidget(
136            parent=self._container,
137            position=(c_width * 0.5, v - 3),
138            color=(0.6, 1.0, 0.6),
139            scale=1.3,
140            size=(0, 0),
141            maxwidth=c_width * 0.9,
142            h_align='center',
143            v_align='center',
144            text=ba.Lstr(
145                resource='gatherWindow.' 'localNetworkDescriptionText'
146            ),
147        )
148        v -= 15
149        v -= sub_scroll_height + 23
150        scrollw = ba.scrollwidget(
151            parent=self._container,
152            position=((region_width - sub_scroll_width) * 0.5, v),
153            size=(sub_scroll_width, sub_scroll_height),
154        )
155
156        self._net_scanner = NetScanner(
157            self, scrollw, tab_button, width=sub_scroll_width
158        )
159
160        ba.widget(edit=scrollw, autoselect=True, up_widget=tab_button)
161        return self._container

Called when the tab becomes the active one.

The tab should create and return a container widget covering the specified region.

def on_deactivate(self) -> None:
163    def on_deactivate(self) -> None:
164        self._net_scanner = None

Called when the tab will no longer be the active one.