From ad6bdb2e3c46a1675376bfd477d1080b1a13d91e Mon Sep 17 00:00:00 2001
From: aclist <92275929+aclist@users.noreply.github.com>
Date: Sun, 28 Dec 2025 07:14:35 +0900
Subject: [PATCH] feat: server connection panel WIP
---
dzgui/const/enum.py | 5 ++++
dzgui/controllers/mc.py | 22 ++++++++++----
dzgui/util/strings.py | 3 +-
dzgui/views/base.py | 12 ++++----
dzgui/views/components/connect_panel.py | 39 ++++++++++++++++---------
dzgui/views/trees/tree_servers.py | 37 ++++++++++++++++++++++-
6 files changed, 91 insertions(+), 27 deletions(-)
diff --git a/dzgui/const/enum.py b/dzgui/const/enum.py
index 111a5fc..224a5b9 100644
--- a/dzgui/const/enum.py
+++ b/dzgui/const/enum.py
@@ -297,6 +297,7 @@ class RowType(EnumWithAttrs):
# TODO: rename to ContextItem
class ContextMenu(EnumWithAttrs):
ADD_SERVER = {"label": strings.add}
+ ADD_FAV = {"label": strings.add_fav}
REMOVE_SERVER = {"label": strings.remove}
COPY_NAME = {"label": strings.copy_name}
COPY_CLIPBOARD = {"label": strings.copy_ip}
@@ -324,6 +325,7 @@ class ContextMenuGroup(Enum):
SERVER_BROWSER = (
ContextMenu.CONNECT,
ContextMenu.ADD_SERVER,
+ ContextMenu.ADD_FAV,
ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD,
ContextMenu.ADD_NOTE,
@@ -333,6 +335,7 @@ class ContextMenuGroup(Enum):
)
SCAN_LAN = (
ContextMenu.CONNECT,
+ ContextMenu.ADD_FAV,
ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD,
ContextMenu.ADD_NOTE,
@@ -342,6 +345,7 @@ class ContextMenuGroup(Enum):
)
SAVED = (
ContextMenu.CONNECT,
+ ContextMenu.ADD_FAV,
ContextMenu.REMOVE_SERVER,
ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD,
@@ -353,6 +357,7 @@ class ContextMenuGroup(Enum):
RECENT = (
ContextMenu.CONNECT,
ContextMenu.ADD_SERVER,
+ ContextMenu.ADD_FAV,
ContextMenu.REMOVE_HISTORY,
ContextMenu.COPY_NAME,
ContextMenu.COPY_CLIPBOARD,
diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py
index 61e071a..8fe3989 100644
--- a/dzgui/controllers/mc.py
+++ b/dzgui/controllers/mc.py
@@ -39,7 +39,7 @@ from dzgui.util.diag import write_diagnostic
from dzgui.util import cooldown, strings
from dzgui.util._json import read_json, write_json
from dzgui.util.open_links import open_workshop_page
-from dzgui.util.format import format_mods
+from dzgui.util.format import format_mods, pluralize
from dzgui.util.redact import redact_log
from dzgui.views.dialogs.filepicker import FilePicker
@@ -56,7 +56,6 @@ if TYPE_CHECKING:
from dzgui.views.base import AppNavigation
from dzgui.const.enum import ContextMenu, RowType
from dzgui.views.base import OuterWindow
- from dzgui.views.trees.tree_servers import ServerTreeView
class Controller:
def __init__(self) -> None:
@@ -558,7 +557,6 @@ class Controller:
return self.is_developer
def update_server_status(self) -> None:
- from dzgui.util.format import pluralize
treeview = self.mediator.notebook.servers.get_active_treeview()
model = treeview.get_model()
if model is None:
@@ -575,12 +573,24 @@ class Controller:
formatted = (
f"Found {hits:n} {hits_pretty} with {players:n} {players_pretty}"
)
- suffix = "| Distance: calculating..."
+ suffix = " | Distance: calculating..."
if players == 0:
suffix = ""
self.mediator.statusbar.set_text(formatted + suffix)
#self.players = formatted
- def update_column_width(self, title: str, width: int) -> None:
- self.mediator.servers.update_tab_widths(title, width)
+ def propagate_column_width(self, col: Gtk.TreeViewColumn) -> None:
+ GLib.idle_add(self.mediator.servers.update_tab_widths, col)
+# tabs = self.mediator.servers.get_tabs()
+# tree = self.mediator.servers.get_active_treeview()
+# width = col.get_width()
+# title = col.get_title()
+# for tab in tabs:
+# if tab == tree:
+# continue
+# for col in tab.get_columns():
+# if col.get_title() == title:
+# self.suppress_signal(tab, col, "_on_col_width_changed", True)
+# col.set_fixed_width(width)
+# self.suppress_signal(tab, col, "_on_col_width_changed", False)
diff --git a/dzgui/util/strings.py b/dzgui/util/strings.py
index 88975cb..07690b4 100644
--- a/dzgui/util/strings.py
+++ b/dzgui/util/strings.py
@@ -53,7 +53,8 @@ copy_name = "Copy name to clipboard"
copy_ip = "Copy IP to clipboard"
copy_log = "Copy record(s) to clipboard"
add = "Add to my servers"
-remove = "Remove from Saved Servers"
+add_fav = "Set as favorite"
+remove = "Remove from my servers"
remove_history = "Remove from history"
connect = "Connect"
diff --git a/dzgui/views/base.py b/dzgui/views/base.py
index 0276a03..f5834cb 100644
--- a/dzgui/views/base.py
+++ b/dzgui/views/base.py
@@ -505,15 +505,15 @@ class Grid(Gtk.Grid):
self.breadcrumbs, self.notebook, Gtk.PositionType.TOP, 3, 1
)
- #from dzgui.views.components.connect_panel import ConnectPanel
- #self.conpan = ConnectPanel()
- #self.attach_next_to(
- # self.conpan, self.notebook, Gtk.PositionType.BOTTOM, 3, 1
- #)
+ from dzgui.views.components.connect_panel import ConnectPanel
+ self.conpan = ConnectPanel()
+ self.attach_next_to(
+ self.conpan, self.notebook, Gtk.PositionType.BOTTOM, 3, 1
+ )
self.attach_next_to(
- self.statusbar, self.notebook, Gtk.PositionType.BOTTOM, 3, 1
+ self.statusbar, self.conpan, Gtk.PositionType.BOTTOM, 3, 1
)
self.attach_next_to(
self.right_panel, self.notebook, Gtk.PositionType.RIGHT, 1, 1
diff --git a/dzgui/views/components/connect_panel.py b/dzgui/views/components/connect_panel.py
index 90bdd69..5cdc55c 100644
--- a/dzgui/views/components/connect_panel.py
+++ b/dzgui/views/components/connect_panel.py
@@ -4,29 +4,42 @@ from gi.repository import Gtk # noqa E402
from dzgui.views.components.web_button import WebButton
-class ConnectPanel(Gtk.Grid):
+class ConnectPanel(Gtk.Frame):
def __init__(self) -> None:
- super().__init__(vexpand=False, margin=20)
+ super().__init__(margin_top=10, margin_bottom=5)
- self.label = Gtk.Label(label="Connect by IP/ID")
+ self.label = Gtk.Label(label="Add/connect")
self.label2 = Gtk.Label(label="Favorite server")
# TODO: embold function
+ #self.label2.set_markup("Favorite server")
self.label2.set_markup("Favorite server")
sep = Gtk.Separator()
self.entry1 = Gtk.Entry(placeholder_text="Enter IP or Battlemetrics ID", hexpand=False)
self.entry2 = Gtk.Entry()
- self.fav = Gtk.Label("MY favorite server")
+ self.fav = Gtk.Label(label="MY favorite server very long title")
self.favedit = Gtk.Button("Edit")
self.edit = WebButton(label="EDIT")
self.favbutton = Gtk.Button(label="Connect")
- self.attach(self.label, 0, 0, 3, 1)
- button = Gtk.Button(label="Connect")
- self.attach_next_to(self.entry1, self.label, Gtk.PositionType.BOTTOM, 3, 1)
- self.attach_next_to(button, self.entry1, Gtk.PositionType.RIGHT, 3, 1)
+ # TODO: dedent
+ long = """IP: Format as IP:Query port, e.g.\n192.168.1.1:27016\n
+ Battlemetrics: numeric server ID
+ """
- self.attach_next_to(sep, self.entry1, Gtk.PositionType.BOTTOM, 3, 1)
- self.attach_next_to(self.label2, sep, Gtk.PositionType.BOTTOM, 3, 1)
- self.attach_next_to(self.fav, self.label2, Gtk.PositionType.BOTTOM, 3, 1)
- self.attach_next_to(self.edit, self.fav, Gtk.PositionType.RIGHT, 3, 1)
- self.attach_next_to(self.favbutton, self.edit, Gtk.PositionType.RIGHT, 3, 1)
+ # TODO: add tooltips to all buttons
+ self.entry1.set_tooltip_text(long)
+
+ self.con = Gtk.Button(label="Connect")
+ self.addb = Gtk.Button(label="Add")
+
+ self.grid = Gtk.Grid(margin=10, vexpand=False, column_spacing=15, row_spacing=5)
+ self.grid.attach(self.label2, 0, 0, 3, 1)
+ button = Gtk.Button(label="Connect")
+ self.grid.attach_next_to(self.fav, self.label2, Gtk.PositionType.RIGHT, 3, 1)
+ self.grid.attach_next_to(self.favbutton, self.fav, Gtk.PositionType.RIGHT, 3, 1)
+ self.grid.attach_next_to(self.label, self.label2, Gtk.PositionType.BOTTOM, 3, 1)
+ self.grid.attach_next_to(self.entry1, self.label, Gtk.PositionType.RIGHT, 3, 1)
+ self.grid.attach_next_to(self.addb, self.entry1, Gtk.PositionType.RIGHT, 3, 1)
+ self.grid.attach_next_to(self.con, self.addb, Gtk.PositionType.RIGHT, 3, 1)
+
+ self.add(self.grid)
diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py
index 857ce1c..e428b0d 100644
--- a/dzgui/views/trees/tree_servers.py
+++ b/dzgui/views/trees/tree_servers.py
@@ -44,6 +44,7 @@ class ServerTreeView(TreeView):
super().__init__(controller)
self.menu = Gtk.Menu()
+ self.menu.connect("key-press-event", self._on_key)
self.controller = controller
self.resizable_cols: list[Gtk.TreeViewColumn] = []
@@ -85,6 +86,7 @@ class ServerTreeView(TreeView):
if column_title == "Map":
column.set_fixed_width(300)
+
self.resizable_cols.append(column)
column.connect("notify::fixed-width", self._on_col_width_changed)
self.append_column(column)
@@ -97,9 +99,41 @@ class ServerTreeView(TreeView):
GLib.timeout_add(200, self._check_result_queue)
+ def _on_key(self, menu: Gtk.Menu, event: Gdk.EventKey) -> bool | None:
+ if not is_navkey(event.keyval):
+ return False
+ sel = menu.get_selected_item()
+ children = menu.get_children()
+ for i, child in enumerate(children):
+ if sel is child:
+ ind = i
+ break
+
+ match event.keyval:
+ case Gdk.KEY_j:
+ if ind == len(children) - 1:
+ return True
+ menu.select_item(children[ind+1])
+ case Gdk.KEY_k:
+ if ind - 1 < 0:
+ return True
+ menu.select_item(children[ind-1])
+ case Gdk.KEY_g:
+ menu.select_item(children[0])
+ case Gdk.KEY_G:
+ ind = len(children) - 1
+ menu.select_item(children[ind])
+ case _:
+ return False
+ return True
+
def _on_col_width_changed(
self, col: Gtk.TreeViewColumn, width: GObject.ParamSpecInt
) -> None:
+ """
+ Propagate width change to other tabs
+ """
+ # TODO: only update res file on quit
title = col.get_title()
size = col.get_width()
@@ -117,7 +151,8 @@ class ServerTreeView(TreeView):
except Exception as e:
logger.critical(e)
- #self.controller.update_column_width(title, size)
+ # NOTE: get final width after drag action completes
+ GLib.idle_add(self.controller.propagate_column_width, col)
def terminate_process(self) -> None:
if self.current_proc and self.current_proc.is_alive():