[MouseFox logo]
The MouseFox Project
Join The Community Discord Server
[Discord logo]
Edit on GitHub

mousefox.app.connectpanel

Home of ConnectPanel.

  1"""Home of `ConnectPanel`."""
  2
  3from typing import Callable
  4from dataclasses import dataclass
  5from loguru import logger
  6import json
  7import kvex as kx
  8import pgnet
  9from .. import util
 10
 11
 12LINE_HEIGHT = 40
 13CONFIG_FILE = util.get_appdata_dir() / "connection_config.json"
 14
 15
 16@dataclass
 17class _ConnectionConfig:
 18    online: bool = False
 19    username: str = pgnet.util.ADMIN_USERNAME
 20    address: str = "localhost"
 21    port: int = pgnet.util.DEFAULT_PORT
 22    pubkey: str = ""
 23
 24    @classmethod
 25    def load_from_disk(cls) -> "_ConnectionConfig":
 26        if not CONFIG_FILE.is_file():
 27            return cls()
 28        with open(CONFIG_FILE) as f:
 29            try:
 30                config = json.load(f)
 31            except json.decoder.JSONDecodeError as e:
 32                logger.warning(f"Failed to load connection config: {e}")
 33                return cls()
 34        return cls(**config)
 35
 36    def save_to_disk(self):
 37        data = {k: getattr(self, k) for k in self.__dataclass_fields__.keys()}
 38        with open(CONFIG_FILE, "w") as f:
 39            json.dump(data, f, indent=4)
 40
 41
 42class ConnectPanel(kx.XAnchor):
 43    """Widget enabling creation of clients."""
 44
 45    _conpath = "client.connect"
 46
 47    def __init__(
 48        self,
 49        app_config: "mousefox.AppConfig",  # noqa: F821
 50        on_client: Callable,
 51    ):
 52        """Initialize the class."""
 53        super().__init__()
 54        if app_config.disable_local and app_config.disable_remote:
 55            raise ValueError("Cannot disable both local and remote clients.")
 56        self._client_class = app_config.client_class
 57        self._game_class = app_config.game_class
 58        self._server_factory = app_config.server_factory
 59        self._enable_local = not app_config.disable_local
 60        self._enable_remote = not app_config.disable_remote
 61        self._on_client = on_client
 62        self._make_widgets(app_config.info_text, app_config.online_info_text)
 63        self.app.controller.set_active_callback(self._conpath, self.set_focus)
 64        self.app.controller.bind(f"{self._conpath}.focus", self.set_focus)
 65
 66    def _make_widgets(self, info_text, online_info_text):
 67        self.clear_widgets()
 68        config = _ConnectionConfig.load_from_disk()
 69        if not self._enable_remote and config.online:
 70            config.online = False
 71        elif not self._enable_local and not config.online:
 72            config.online = True
 73        # Side panel
 74        info_label = kx.XLabel(
 75            text=info_text,
 76            valign="top",
 77            halign="left",
 78            padding=(10, 10),
 79            fixed_width=True,
 80        )
 81        online_info_label = kx.XLabel(
 82            text=online_info_text,
 83            valign="top",
 84            halign="left",
 85            padding=(10, 10),
 86            fixed_width=True,
 87        )
 88        self._online_info_label = kx.XCurtain(
 89            content=online_info_label,
 90            showing=config.online,
 91        )
 92        left_labels = kx.XDBox()
 93        left_labels.add_widgets(info_label, self._online_info_label)
 94        left_frame = kx.XBox(orientation="vertical")
 95        left_frame.add_widgets(left_labels, kx.XAnchor())
 96        # Connection details
 97        pwidgets = dict(
 98            online=kx.XInputPanelWidget(
 99                "Online",
100                "bool",
101                default=config.online,
102                bold=True,
103                italic=False,
104                showing=self._enable_local and self._enable_remote,
105            ),
106            username=kx.XInputPanelWidget("Username", default=config.username),
107            password=kx.XInputPanelWidget(
108                "Password",
109                "password",
110                showing=config.online,
111            ),
112            address=kx.XInputPanelWidget(
113                "IP Address",
114                default=config.address,
115                showing=config.online,
116            ),
117            invite_code=kx.XInputPanelWidget(
118                "Invite code",
119                showing=config.online,
120            ),
121            advanced=kx.XInputPanelWidget(
122                "Advanced",
123                "bool",
124                default=False,
125                bold=True,
126                italic=False,
127                showing=config.online,
128            ),
129            port=kx.XInputPanelWidget(
130                "Port number",
131                "int",
132                default=config.port,
133                showing=False,
134            ),
135            pubkey=kx.XInputPanelWidget(
136                "Server verification",
137                default=config.pubkey,
138                showing=False,
139            ),
140        )
141        with self.app.subtheme_context("secondary"):
142            self.connection_panel = kx.XInputPanel(pwidgets, invoke_text="Connect")
143            connection_panel = kx.fwrap(self.connection_panel)
144        self.connection_panel.bind(
145            on_invoke=self._connect,
146            on_values=self._on_connection_values,
147        )
148        # Assemble
149        main_frame = kx.XBox()
150        main_frame.add_widgets(kx.pwrap(left_frame), kx.pwrap(connection_panel))
151        self.add_widget(kx.pwrap(kx.fwrap(main_frame)))
152
153    def _connect(self, *args):
154        self.connection_panel.set_focus("username")
155        get_value = self.connection_panel.get_value
156        online = get_value("online")
157        advanced = online and get_value("advanced")
158        online = get_value("online")
159        username = get_value("username")
160        password = get_value("password")
161        invite_code = get_value("invite_code")
162        address = get_value("address") if online else _ConnectionConfig.address
163        port = get_value("port") if advanced else _ConnectionConfig.port
164        pubkey = get_value("pubkey") if advanced else _ConnectionConfig.pubkey
165        if online:
166            client = self._client_class.remote(
167                address=address,
168                port=port,
169                username=username,
170                password=password,
171                invite_code=invite_code,
172                verify_server_pubkey=pubkey or None,
173            )
174        else:
175            client = self._client_class.local(
176                username=username,
177                password=pgnet.util.DEFAULT_ADMIN_PASSWORD,
178                game=self._game_class,
179                server_factory=self._server_factory,
180            )
181        config = _ConnectionConfig(online, username, address, port, pubkey)
182        config.save_to_disk()
183        self._on_client(client)
184
185    def _on_connection_values(self, w, values: dict):
186        online = values["online"]
187        advanced = online and values["advanced"]
188        self._online_info_label.showing = online
189        for iname in ("password", "address", "invite_code", "advanced"):
190            self.connection_panel.set_showing(iname, online)
191        for iname in ("port", "pubkey"):
192            self.connection_panel.set_showing(iname, advanced)
193
194    def set_focus(self, *args):
195        """Focus the input widgets."""
196        self.connection_panel.set_focus("username")
class ConnectPanel(kvex.widgets.layouts.XAnchor):
 43class ConnectPanel(kx.XAnchor):
 44    """Widget enabling creation of clients."""
 45
 46    _conpath = "client.connect"
 47
 48    def __init__(
 49        self,
 50        app_config: "mousefox.AppConfig",  # noqa: F821
 51        on_client: Callable,
 52    ):
 53        """Initialize the class."""
 54        super().__init__()
 55        if app_config.disable_local and app_config.disable_remote:
 56            raise ValueError("Cannot disable both local and remote clients.")
 57        self._client_class = app_config.client_class
 58        self._game_class = app_config.game_class
 59        self._server_factory = app_config.server_factory
 60        self._enable_local = not app_config.disable_local
 61        self._enable_remote = not app_config.disable_remote
 62        self._on_client = on_client
 63        self._make_widgets(app_config.info_text, app_config.online_info_text)
 64        self.app.controller.set_active_callback(self._conpath, self.set_focus)
 65        self.app.controller.bind(f"{self._conpath}.focus", self.set_focus)
 66
 67    def _make_widgets(self, info_text, online_info_text):
 68        self.clear_widgets()
 69        config = _ConnectionConfig.load_from_disk()
 70        if not self._enable_remote and config.online:
 71            config.online = False
 72        elif not self._enable_local and not config.online:
 73            config.online = True
 74        # Side panel
 75        info_label = kx.XLabel(
 76            text=info_text,
 77            valign="top",
 78            halign="left",
 79            padding=(10, 10),
 80            fixed_width=True,
 81        )
 82        online_info_label = kx.XLabel(
 83            text=online_info_text,
 84            valign="top",
 85            halign="left",
 86            padding=(10, 10),
 87            fixed_width=True,
 88        )
 89        self._online_info_label = kx.XCurtain(
 90            content=online_info_label,
 91            showing=config.online,
 92        )
 93        left_labels = kx.XDBox()
 94        left_labels.add_widgets(info_label, self._online_info_label)
 95        left_frame = kx.XBox(orientation="vertical")
 96        left_frame.add_widgets(left_labels, kx.XAnchor())
 97        # Connection details
 98        pwidgets = dict(
 99            online=kx.XInputPanelWidget(
100                "Online",
101                "bool",
102                default=config.online,
103                bold=True,
104                italic=False,
105                showing=self._enable_local and self._enable_remote,
106            ),
107            username=kx.XInputPanelWidget("Username", default=config.username),
108            password=kx.XInputPanelWidget(
109                "Password",
110                "password",
111                showing=config.online,
112            ),
113            address=kx.XInputPanelWidget(
114                "IP Address",
115                default=config.address,
116                showing=config.online,
117            ),
118            invite_code=kx.XInputPanelWidget(
119                "Invite code",
120                showing=config.online,
121            ),
122            advanced=kx.XInputPanelWidget(
123                "Advanced",
124                "bool",
125                default=False,
126                bold=True,
127                italic=False,
128                showing=config.online,
129            ),
130            port=kx.XInputPanelWidget(
131                "Port number",
132                "int",
133                default=config.port,
134                showing=False,
135            ),
136            pubkey=kx.XInputPanelWidget(
137                "Server verification",
138                default=config.pubkey,
139                showing=False,
140            ),
141        )
142        with self.app.subtheme_context("secondary"):
143            self.connection_panel = kx.XInputPanel(pwidgets, invoke_text="Connect")
144            connection_panel = kx.fwrap(self.connection_panel)
145        self.connection_panel.bind(
146            on_invoke=self._connect,
147            on_values=self._on_connection_values,
148        )
149        # Assemble
150        main_frame = kx.XBox()
151        main_frame.add_widgets(kx.pwrap(left_frame), kx.pwrap(connection_panel))
152        self.add_widget(kx.pwrap(kx.fwrap(main_frame)))
153
154    def _connect(self, *args):
155        self.connection_panel.set_focus("username")
156        get_value = self.connection_panel.get_value
157        online = get_value("online")
158        advanced = online and get_value("advanced")
159        online = get_value("online")
160        username = get_value("username")
161        password = get_value("password")
162        invite_code = get_value("invite_code")
163        address = get_value("address") if online else _ConnectionConfig.address
164        port = get_value("port") if advanced else _ConnectionConfig.port
165        pubkey = get_value("pubkey") if advanced else _ConnectionConfig.pubkey
166        if online:
167            client = self._client_class.remote(
168                address=address,
169                port=port,
170                username=username,
171                password=password,
172                invite_code=invite_code,
173                verify_server_pubkey=pubkey or None,
174            )
175        else:
176            client = self._client_class.local(
177                username=username,
178                password=pgnet.util.DEFAULT_ADMIN_PASSWORD,
179                game=self._game_class,
180                server_factory=self._server_factory,
181            )
182        config = _ConnectionConfig(online, username, address, port, pubkey)
183        config.save_to_disk()
184        self._on_client(client)
185
186    def _on_connection_values(self, w, values: dict):
187        online = values["online"]
188        advanced = online and values["advanced"]
189        self._online_info_label.showing = online
190        for iname in ("password", "address", "invite_code", "advanced"):
191            self.connection_panel.set_showing(iname, online)
192        for iname in ("port", "pubkey"):
193            self.connection_panel.set_showing(iname, advanced)
194
195    def set_focus(self, *args):
196        """Focus the input widgets."""
197        self.connection_panel.set_focus("username")

Widget enabling creation of clients.

ConnectPanel(app_config: mousefox.app.app.AppConfig, on_client: Callable)
48    def __init__(
49        self,
50        app_config: "mousefox.AppConfig",  # noqa: F821
51        on_client: Callable,
52    ):
53        """Initialize the class."""
54        super().__init__()
55        if app_config.disable_local and app_config.disable_remote:
56            raise ValueError("Cannot disable both local and remote clients.")
57        self._client_class = app_config.client_class
58        self._game_class = app_config.game_class
59        self._server_factory = app_config.server_factory
60        self._enable_local = not app_config.disable_local
61        self._enable_remote = not app_config.disable_remote
62        self._on_client = on_client
63        self._make_widgets(app_config.info_text, app_config.online_info_text)
64        self.app.controller.set_active_callback(self._conpath, self.set_focus)
65        self.app.controller.bind(f"{self._conpath}.focus", self.set_focus)

Initialize the class.

def set_focus(self, *args):
195    def set_focus(self, *args):
196        """Focus the input widgets."""
197        self.connection_panel.set_focus("username")

Focus the input widgets.

Inherited Members
kivy.uix.anchorlayout.AnchorLayout
padding
anchor_x
anchor_y
do_layout
kivy.uix.layout.Layout
add_widget
remove_widget
layout_hint_with_bounds
kivy.uix.widget.Widget
proxy_ref
apply_class_lang_rules
collide_point
collide_widget
on_motion
on_touch_down
on_touch_move
on_touch_up
on_kv_post
clear_widgets
register_for_motion_event
unregister_for_motion_event
export_to_png
export_as_image
get_root_window
get_parent_window
walk
walk_reverse
to_widget
to_window
to_parent
to_local
get_window_matrix
x
y
width
height
pos
size
get_right
set_right
right
get_top
set_top
top
get_center_x
set_center_x
center_x
get_center_y
set_center_y
center_y
center
cls
children
parent
size_hint_x
size_hint_y
size_hint
pos_hint
size_hint_min_x
size_hint_min_y
size_hint_min
size_hint_max_x
size_hint_max_y
size_hint_max
ids
opacity
on_opacity
canvas
get_disabled
set_disabled
inc_disabled
dec_disabled
disabled
motion_filter
kivy._event.EventDispatcher
register_event_type
unregister_event_types
unregister_event_type
is_event_type
bind
unbind
fbind
funbind
unbind_uid
get_property_observers
events
dispatch
dispatch_generic
dispatch_children
setter
getter
property
properties
create_property
apply_property