fix: dynamic statusbar WIP

This commit is contained in:
aclist 2026-01-22 14:20:45 +09:00
parent 934ff91f05
commit 61f2d35f16
4 changed files with 64 additions and 56 deletions

View File

@ -2,6 +2,7 @@ import logging
import shutil
import threading
import traceback
from warnings import deprecated
from pathlib import Path
from typing import Any, Callable, Literal, TYPE_CHECKING
@ -83,6 +84,7 @@ class AppNavigation:
class Controller:
def __init__(self) -> None:
self.dist_cache: dict[str, "Haversine", "ServerTab"] = {}
# TODO: store in crumbs class
self.crumbs_cache = ""
self.mediator = AppNavigation()
self.prefs: UserPrefs
@ -98,6 +100,7 @@ class Controller:
except AttributeError:
logger.critical(f"{attr} is not a valid AppNavigation attribute.")
# TODO: relegate to crumbs class
def set_crumbs(self, text: str) -> None:
self.mediator.grid.set_breadcrumbs(text)
@ -231,29 +234,29 @@ class Controller:
def get_statusbar(self) -> str:
return self.mediator.statusbar.get_text()
@deprecated("use statusbar internal contexts")
def remove_statusbar(self, context: str) -> None:
c = self.mediator.statusbar.statusbar.get_context_id(context)
self.mediator.statusbar.statusbar.pop(c)
# TODO: use set_by_context()
def set_statusbar(self, text: str, context: str) -> int:
msg_id = self.mediator.statusbar.set_text(text, context)
return msg_id
def set_statusbar_placeholder(self, text: str) -> None:
# TODO: use statusbar stacks instead
self.statusbar_placeholder = text
def set_statusbar_dist(self, haversine: "Haversine", enum: "ServerTab") -> None:
# NOTE: prevent race condition where page was changed before distance was written
if self.mediator.notebook.get_page_by_enum() is not NotebookPage.SERVERS:
cid = self.mediator.statusbar.statusbar.get_context_id(str(enum))
self.mediator.statusbar.statusbar.pop(cid)
tv = self.get_active_treeview()
context = tv.get_enum()
page = self.mediator.notebook.get_page_by_enum()
"""
NOTE: prevents race condition when notebook page changed,
but allows caching the distance in the background
"""
if page != NotebookPage.SERVERS:
self.mediator.statusbar.spinner.stop()
return
tv = self.get_active_treeview()
if tv.get_enum() != enum:
self.mediator.statusbar.spinner.stop()
if enum != context:
self.mediator.statusbar.emit("distcalc_ended", None, context)
return
# NOTE: user may have changed km/mi toggle, so recalculate
@ -269,10 +272,8 @@ class Controller:
raw = round(haversine.as_kilometers())
separated = number(raw)
dist = str(separated) + " km"
text = self.statusbar_placeholder
# TODO: abstract
self.set_statusbar(f"{text} | Distance: {dist}", "Servers")
self.mediator.statusbar.spinner.stop()
self.mediator.statusbar.emit("distcalc_ended", dist, context)
def delete_multiple_mods(self) -> None:
sel = self.mediator.modtreeview.get_selection()
@ -334,6 +335,8 @@ class Controller:
def toggle_server_panels(self, state: bool) -> None:
# TODO: this is going to be signal dependent now
# cf. map/unmap
#self.mediator.grid.emit("toggle panels", state)
self.mediator.grid.toggle_filter_panel(state)
self.mediator.grid.toggle_connect_panel(state)
self.mediator.grid.toggle_refresh_button(state)
@ -343,8 +346,6 @@ class Controller:
def show_developers_page(self) -> None:
self.open_page(NotebookPage.DEVELOPERS)
# TODO: put cursor on first row
# self.mediator.developers.focus_first_row()
def open_page(self, page: NotebookPage) -> None:
self.mediator.grid.notebook.set_page_by_enum(page)
@ -599,10 +600,11 @@ class Controller:
for row in data:
manager.append_row(row)
treeview.set_loaded(True)
self.update_server_status()
self.mediator.statusbar.emit("server_page_changed", context)
treeview.grab_focus()
treeview = self.get_active_treeview()
context = treeview.get_enum()
manager = treeview.get_filter_man()
data = self.data
@ -707,30 +709,15 @@ class Controller:
treeview.set_loaded(False)
self.populate_model()
def update_server_status(self) -> None:
# TODO: emit signal on statusbar only if page changed
def get_player_count(self) -> str:
treeview = self.get_active_treeview()
context = str(treeview.enum)
context = treeview.get_enum()
model = treeview.get_model()
status = format_player_count(model)
return status
self.set_statusbar_placeholder(status)
self.set_statusbar(status, context)
#if len(model) >= 1:
# self.mediator.statusbar.spinner.start()
def start_spinner(self) -> None:
# TODO: use signal instead
self.mediator.statusbar.start_spinner()
def notify_statusbar_of_notebook_change(self) -> None:
enum = self.mediator.notebook.get_page_by_enum()
self.mediator.statusbar.emit("notebook_page_changed", enum)
def notify_statusbar(self) -> None:
tv = self.get_active_treeview()
enum = tv.get_enum()
self.mediator.statusbar.emit("server_page_changed", enum)
def get_statusbar(self) -> None:
return self.mediator.statusbar
def populate_model(self) -> None:
treeview = self.get_active_treeview()
@ -748,15 +735,14 @@ class Controller:
self.mediator.right_panel.focus_button_box()
def present_servers(self) -> None:
# TODO: abstract
self.update_server_status()
treeview = self.get_active_treeview()
context = treeview.get_enum()
self.mediator.statusbar.emit("server_page_changed", context)
# TODO: signal for crumbs
crumbs = self.mediator.servers.get_cached_label()
self.set_crumbs(crumbs)
tree = self.get_active_treeview()
tree.emit("on_distcalc_started")
def toggle_check(self, event: Gdk.EventKey) -> None | Literal[False]:
mappings = {
Gdk.KEY_1: 0,

View File

@ -1,5 +1,6 @@
import logging
import multiprocessing
from math import radians, cos, sin, asin, sqrt
from typing import TYPE_CHECKING

View File

@ -19,6 +19,8 @@ class Statusbar(Gtk.Grid):
"server_page_changed": (GObject.SignalFlags.RUN_FIRST, None, (object,)),
"notebook_page_changed": (GObject.SignalFlags.RUN_FIRST, None, (object,)),
"notebook_page_returned": (GObject.SignalFlags.RUN_FIRST, None, (object,)),
"distcalc_ended": (GObject.SignalFlags.RUN_FIRST, None, (object, str)),
"server_row_changed": (GObject.SignalFlags.RUN_FIRST, None, ()),
}
def __init__(self, controller: "Controller") -> None:
@ -29,7 +31,7 @@ class Statusbar(Gtk.Grid):
help_text = strings.statusbar_helptext
self.context: int
self.playercount = ""
self.statusbar = Gtk.Statusbar()
self.spinner = Gtk.Spinner()
@ -49,9 +51,11 @@ class Statusbar(Gtk.Grid):
self.set_text(help_text, "Help")
self.players = ""
self.connect("server_row_changed", self._on_server_row_changed)
self.connect("server_page_changed", self._on_server_page_changed)
self.connect("notebook_page_changed", self._on_notebook_page_changed)
self.connect("notebook_page_returned", self._on_notebook_page_returned)
self.connect("distcalc_ended", self._on_distcalc_ended)
def _on_notebook_page_changed(
self, statusbar: Self, context: "NotebookPage"
@ -67,21 +71,39 @@ class Statusbar(Gtk.Grid):
bar = self.controller.format_mod_statusbar()
case NotebookPage.HELP:
bar = self.controller.get_help_text()
case NotebookPage.SERVERS:
pass
self.set_by_context(context, bar)
def _on_notebook_page_returned(
self, statusbar: Self, prior_context: "NotebookPage"
self, statusbar: Self, prior_context: NotebookPage
) -> None:
self.pop(prior_context)
def _on_server_page_changed(self, statusbar: Self, context: "ServerTab") -> None:
self.pop(context)
def start_spinner(self) -> None:
def _on_server_row_changed(self, statusbar: Self) -> None:
self.spinner.start()
def stop_spinner(self) -> None:
def _on_distcalc_ended(
self,
statusbar: Self,
dist: Union[str, None],
context: Union["ServerTab", NotebookPage],
) -> None:
self.spinner.stop()
if dist is None:
self.set_by_context(context, self.playercount)
else:
pretty = f"{self.playercount} | Distance: {dist}"
self.set_by_context(context, pretty)
def _on_server_page_changed(self, statusbar: Self, context: "ServerTab") -> None:
c = self.controller.get_player_count()
self.playercount = c
self.set_by_context(context, c)
tree = self.controller.get_active_treeview()
tree.emit("on_distcalc_started")
def pop(self, context: Union["ServerTab", "NotebookPage"]) -> None:
cid = self.statusbar.get_context_id(str(context))

View File

@ -213,27 +213,26 @@ class ServerTreeView(TreeView):
self.current_proc.terminate()
def _on_distcalc_started(self, treeview: Self):
bar = self.controller.get_statusbar()
record = self.get_record()
if record is None:
return
bar.emit("server_row_changed")
cache = self.controller.get_dist_cache()
if record.ip in cache:
haversine = cache[record.ip]
self.controller.set_statusbar_dist(haversine, None)
self.controller.set_statusbar_dist(haversine, self.get_enum())
return
if len(self.get_model()) > 1:
self.controller.start_spinner()
self.current_proc = CalcDist(
record.ip, self.get_enum(), self.queue, self.controller
)
self.current_proc.start()
def _check_result_queue(self) -> Literal[True]:
# TODO: trigger signal when changing page contexts
# TODO: delegate to controller
latest_result = None
while not self.queue.empty():