fix: dynamic statusbar WIP

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

No files matched your search

+30 -44
View File
@@ -2,6 +2,7 @@ import logging
import shutil import shutil
import threading import threading
import traceback import traceback
from warnings import deprecated
from pathlib import Path from pathlib import Path
from typing import Any, Callable, Literal, TYPE_CHECKING from typing import Any, Callable, Literal, TYPE_CHECKING
@@ -83,6 +84,7 @@ class AppNavigation:
class Controller: class Controller:
def __init__(self) -> None: def __init__(self) -> None:
self.dist_cache: dict[str, "Haversine", "ServerTab"] = {} self.dist_cache: dict[str, "Haversine", "ServerTab"] = {}
# TODO: store in crumbs class
self.crumbs_cache = "" self.crumbs_cache = ""
self.mediator = AppNavigation() self.mediator = AppNavigation()
self.prefs: UserPrefs self.prefs: UserPrefs
@@ -98,6 +100,7 @@ class Controller:
except AttributeError: except AttributeError:
logger.critical(f"{attr} is not a valid AppNavigation attribute.") logger.critical(f"{attr} is not a valid AppNavigation attribute.")
# TODO: relegate to crumbs class
def set_crumbs(self, text: str) -> None: def set_crumbs(self, text: str) -> None:
self.mediator.grid.set_breadcrumbs(text) self.mediator.grid.set_breadcrumbs(text)
@@ -231,29 +234,29 @@ class Controller:
def get_statusbar(self) -> str: def get_statusbar(self) -> str:
return self.mediator.statusbar.get_text() return self.mediator.statusbar.get_text()
@deprecated("use statusbar internal contexts")
def remove_statusbar(self, context: str) -> None: def remove_statusbar(self, context: str) -> None:
c = self.mediator.statusbar.statusbar.get_context_id(context) c = self.mediator.statusbar.statusbar.get_context_id(context)
self.mediator.statusbar.statusbar.pop(c) self.mediator.statusbar.statusbar.pop(c)
# TODO: use set_by_context()
def set_statusbar(self, text: str, context: str) -> int: def set_statusbar(self, text: str, context: str) -> int:
msg_id = self.mediator.statusbar.set_text(text, context) msg_id = self.mediator.statusbar.set_text(text, context)
return msg_id 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: def set_statusbar_dist(self, haversine: "Haversine", enum: "ServerTab") -> None:
# NOTE: prevent race condition where page was changed before distance was written tv = self.get_active_treeview()
if self.mediator.notebook.get_page_by_enum() is not NotebookPage.SERVERS: context = tv.get_enum()
cid = self.mediator.statusbar.statusbar.get_context_id(str(enum)) page = self.mediator.notebook.get_page_by_enum()
self.mediator.statusbar.statusbar.pop(cid) """
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() self.mediator.statusbar.spinner.stop()
return return
if enum != context:
tv = self.get_active_treeview() self.mediator.statusbar.emit("distcalc_ended", None, context)
if tv.get_enum() != enum:
self.mediator.statusbar.spinner.stop()
return return
# NOTE: user may have changed km/mi toggle, so recalculate # NOTE: user may have changed km/mi toggle, so recalculate
@@ -269,10 +272,8 @@ class Controller:
raw = round(haversine.as_kilometers()) raw = round(haversine.as_kilometers())
separated = number(raw) separated = number(raw)
dist = str(separated) + " km" dist = str(separated) + " km"
text = self.statusbar_placeholder
# TODO: abstract self.mediator.statusbar.emit("distcalc_ended", dist, context)
self.set_statusbar(f"{text} | Distance: {dist}", "Servers")
self.mediator.statusbar.spinner.stop()
def delete_multiple_mods(self) -> None: def delete_multiple_mods(self) -> None:
sel = self.mediator.modtreeview.get_selection() sel = self.mediator.modtreeview.get_selection()
@@ -334,6 +335,8 @@ class Controller:
def toggle_server_panels(self, state: bool) -> None: def toggle_server_panels(self, state: bool) -> None:
# TODO: this is going to be signal dependent now # 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_filter_panel(state)
self.mediator.grid.toggle_connect_panel(state) self.mediator.grid.toggle_connect_panel(state)
self.mediator.grid.toggle_refresh_button(state) self.mediator.grid.toggle_refresh_button(state)
@@ -343,8 +346,6 @@ class Controller:
def show_developers_page(self) -> None: def show_developers_page(self) -> None:
self.open_page(NotebookPage.DEVELOPERS) self.open_page(NotebookPage.DEVELOPERS)
# TODO: put cursor on first row
# self.mediator.developers.focus_first_row()
def open_page(self, page: NotebookPage) -> None: def open_page(self, page: NotebookPage) -> None:
self.mediator.grid.notebook.set_page_by_enum(page) self.mediator.grid.notebook.set_page_by_enum(page)
@@ -599,10 +600,11 @@ class Controller:
for row in data: for row in data:
manager.append_row(row) manager.append_row(row)
treeview.set_loaded(True) treeview.set_loaded(True)
self.update_server_status() self.mediator.statusbar.emit("server_page_changed", context)
treeview.grab_focus() treeview.grab_focus()
treeview = self.get_active_treeview() treeview = self.get_active_treeview()
context = treeview.get_enum()
manager = treeview.get_filter_man() manager = treeview.get_filter_man()
data = self.data data = self.data
@@ -707,30 +709,15 @@ class Controller:
treeview.set_loaded(False) treeview.set_loaded(False)
self.populate_model() self.populate_model()
def update_server_status(self) -> None: def get_player_count(self) -> str:
# TODO: emit signal on statusbar only if page changed
treeview = self.get_active_treeview() treeview = self.get_active_treeview()
context = str(treeview.enum) context = treeview.get_enum()
model = treeview.get_model() model = treeview.get_model()
status = format_player_count(model) status = format_player_count(model)
return status
self.set_statusbar_placeholder(status) def get_statusbar(self) -> None:
self.set_statusbar(status, context) return self.mediator.statusbar
#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 populate_model(self) -> None: def populate_model(self) -> None:
treeview = self.get_active_treeview() treeview = self.get_active_treeview()
@@ -748,15 +735,14 @@ class Controller:
self.mediator.right_panel.focus_button_box() self.mediator.right_panel.focus_button_box()
def present_servers(self) -> None: def present_servers(self) -> None:
# TODO: abstract treeview = self.get_active_treeview()
self.update_server_status() context = treeview.get_enum()
self.mediator.statusbar.emit("server_page_changed", context)
# TODO: signal for crumbs # TODO: signal for crumbs
crumbs = self.mediator.servers.get_cached_label() crumbs = self.mediator.servers.get_cached_label()
self.set_crumbs(crumbs) self.set_crumbs(crumbs)
tree = self.get_active_treeview()
tree.emit("on_distcalc_started")
def toggle_check(self, event: Gdk.EventKey) -> None | Literal[False]: def toggle_check(self, event: Gdk.EventKey) -> None | Literal[False]:
mappings = { mappings = {
Gdk.KEY_1: 0, Gdk.KEY_1: 0,
+1
View File
@@ -1,5 +1,6 @@
import logging import logging
import multiprocessing import multiprocessing
from math import radians, cos, sin, asin, sqrt from math import radians, cos, sin, asin, sqrt
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
+29 -7
View File
@@ -19,6 +19,8 @@ class Statusbar(Gtk.Grid):
"server_page_changed": (GObject.SignalFlags.RUN_FIRST, None, (object,)), "server_page_changed": (GObject.SignalFlags.RUN_FIRST, None, (object,)),
"notebook_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,)), "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: def __init__(self, controller: "Controller") -> None:
@@ -29,7 +31,7 @@ class Statusbar(Gtk.Grid):
help_text = strings.statusbar_helptext help_text = strings.statusbar_helptext
self.context: int self.playercount = ""
self.statusbar = Gtk.Statusbar() self.statusbar = Gtk.Statusbar()
self.spinner = Gtk.Spinner() self.spinner = Gtk.Spinner()
@@ -49,9 +51,11 @@ class Statusbar(Gtk.Grid):
self.set_text(help_text, "Help") self.set_text(help_text, "Help")
self.players = "" self.players = ""
self.connect("server_row_changed", self._on_server_row_changed)
self.connect("server_page_changed", self._on_server_page_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_changed", self._on_notebook_page_changed)
self.connect("notebook_page_returned", self._on_notebook_page_returned) self.connect("notebook_page_returned", self._on_notebook_page_returned)
self.connect("distcalc_ended", self._on_distcalc_ended)
def _on_notebook_page_changed( def _on_notebook_page_changed(
self, statusbar: Self, context: "NotebookPage" self, statusbar: Self, context: "NotebookPage"
@@ -67,21 +71,39 @@ class Statusbar(Gtk.Grid):
bar = self.controller.format_mod_statusbar() bar = self.controller.format_mod_statusbar()
case NotebookPage.HELP: case NotebookPage.HELP:
bar = self.controller.get_help_text() bar = self.controller.get_help_text()
case NotebookPage.SERVERS:
pass
self.set_by_context(context, bar) self.set_by_context(context, bar)
def _on_notebook_page_returned( def _on_notebook_page_returned(
self, statusbar: Self, prior_context: "NotebookPage" self, statusbar: Self, prior_context: NotebookPage
) -> None: ) -> None:
self.pop(prior_context) self.pop(prior_context)
def _on_server_page_changed(self, statusbar: Self, context: "ServerTab") -> None: def _on_server_row_changed(self, statusbar: Self) -> None:
self.pop(context)
def start_spinner(self) -> None:
self.spinner.start() 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() 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: def pop(self, context: Union["ServerTab", "NotebookPage"]) -> None:
cid = self.statusbar.get_context_id(str(context)) cid = self.statusbar.get_context_id(str(context))
+4 -5
View File
@@ -213,27 +213,26 @@ class ServerTreeView(TreeView):
self.current_proc.terminate() self.current_proc.terminate()
def _on_distcalc_started(self, treeview: Self): def _on_distcalc_started(self, treeview: Self):
bar = self.controller.get_statusbar()
record = self.get_record() record = self.get_record()
if record is None: if record is None:
return return
bar.emit("server_row_changed")
cache = self.controller.get_dist_cache() cache = self.controller.get_dist_cache()
if record.ip in cache: if record.ip in cache:
haversine = cache[record.ip] haversine = cache[record.ip]
self.controller.set_statusbar_dist(haversine, None) self.controller.set_statusbar_dist(haversine, self.get_enum())
return return
if len(self.get_model()) > 1:
self.controller.start_spinner()
self.current_proc = CalcDist( self.current_proc = CalcDist(
record.ip, self.get_enum(), self.queue, self.controller record.ip, self.get_enum(), self.queue, self.controller
) )
self.current_proc.start() self.current_proc.start()
def _check_result_queue(self) -> Literal[True]: def _check_result_queue(self) -> Literal[True]:
# TODO: trigger signal when changing page contexts
# TODO: delegate to controller # TODO: delegate to controller
latest_result = None latest_result = None
while not self.queue.empty(): while not self.queue.empty():