diff --git a/dzgui/const/enum.py b/dzgui/const/enum.py index 4cc0ea1..b9e032f 100644 --- a/dzgui/const/enum.py +++ b/dzgui/const/enum.py @@ -361,20 +361,6 @@ class ContextMenuGroup(Enum): ) -MAIN_MENU_ROWS = ( - RowType.SERVER_BROWSER, - RowType.SAVED_SERVERS, - RowType.RECENT_SERVERS, - RowType.SCAN_LAN, - RowType.SEPARATOR, - RowType.QUICK_CONNECT, - RowType.CONN_BY_IP, - RowType.CONN_BY_ID, - RowType.SEPARATOR, - RowType.ADD_BY_IP, - RowType.ADD_BY_ID, - RowType.CHNG_FAV, -) HELP_MENU_ROWS = ( RowType.CHANGELOG, RowType.SHOW_LOG, @@ -389,87 +375,6 @@ HELP_MENU_ROWS = ( RowType.THANKS, ) -#class WindowContext(EnumWithAttrs): -# # TODO: deprecated -# @classmethod -# def row2con(cls, row: RowType) -> "WindowContext": -# m = WindowContext.MAIN_MENU -# for member in cls: -# if row in member.dict["rows"]: -# m = member -# elif row in member.dict["called_by"]: -# m = member -# else: -# continue -# return m -# -# # outer menu pages -# # TODO: some deprecated keys in here -# #MAIN_MENU = { -# # RowType.SERVER_BROWSER, -# # RowType.SAVED_SERVERS, -# # RowType.RECENT_SERVERS, -# # RowType.SCAN_LAN, -# # RowType.SEPARATOR, -# # RowType.QUICK_CONNECT, -# # RowType.CONN_BY_IP, -# # RowType.CONN_BY_ID, -# # RowType.SEPARATOR, -# # RowType.ADD_BY_IP, -# # RowType.ADD_BY_ID, -# # RowType.CHNG_FAV, -# # } -# #MODS = { -# # "label": "Mods", -# # "rows": [], -# # "called_by": [], -# #} -# HELP = { -# "label": "Help", -# "rows": [ -# RowType.CHANGELOG, -# RowType.SHOW_LOG, -# RowType.DUMP_LOG, -# RowType.SEPARATOR, -# RowType.DOCS, -# RowType.DOCS_FALLBACK, -# RowType.BUGS, -# RowType.FORUM, -# RowType.SPONSOR, -# RowType.SEPARATOR, -# RowType.THANKS, -# ], -# "called_by": [], -# } -# -# ## inner server contexts -# #TABLE_API = { -# # "label": "", -# # "rows": [], -# # "called_by": [RowType.SERVER_BROWSER], -# #} -# #TABLE_SERVER = { -# # "label": "", -# # "rows": [], -# # "called_by": [ -# # RowType.SAVED_SERVERS, -# # RowType.RECENT_SERVERS, -# # RowType.SCAN_LAN, -# # ], -# #} -# #TABLE_MODS = { -# # "label": "", -# # "rows": [], -# # "called_by": [ -# # RowType.LIST_MODS, -# # ], -# #} -# #TABLE_LOG = { -# # "label": "", -# # "rows": [], -# # "called_by": [RowType.SHOW_LOG], -# #} - class ModButton(EnumWithAttrs): SELECT_ALL = { @@ -499,10 +404,10 @@ class ModButton(EnumWithAttrs): class ButtonType(EnumWithAttrs): - MAIN_MENU = { - "label": strings.buttons.main_label, - "tooltip": strings.buttons.main_tooltip, - "opens": NotebookPage.MAIN, + SERVERS = { + "label": strings.buttons.servers_label, + "tooltip": strings.buttons.servers_tooltip, + "opens": NotebookPage.SERVERS, } MODS = { "label": strings.buttons.mods_label, @@ -517,7 +422,7 @@ class ButtonType(EnumWithAttrs): HELP = { "label": strings.buttons.help_label, "tooltip": strings.buttons.help_tooltip, - "opens": NotebookPage.MAIN, + "opens": NotebookPage.HELP, } EXIT = { "label": strings.buttons.exit_label, diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index b4f158b..f71cc55 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -79,8 +79,8 @@ class Controller: def get_crumbs(self) -> str: return self.mediator.grid.get_breadcrumbs() - def get_row_store(self) -> Gtk.ListStore: - return self.model_manager.get_row_store() + #def get_row_store(self) -> Gtk.ListStore: + # return self.model_manager.get_row_store() def get_help_store(self) -> Gtk.ListStore: return self.model_manager.get_help_store() @@ -160,7 +160,8 @@ class Controller: widget.handler_block_by_func(func) else: widget.handler_unblock_by_func(func) - self.mediator.treeview.sel_blocked = state + # TODO + #self.mediator.treeview.sel_blocked = state def toggle_debug_mode(self) -> None: self.toggle_config(Preferences.DEBUG) @@ -277,6 +278,7 @@ class Controller: self.mediator.grid.notebook.set_page_by_enum(page) def open_page_by_button(self, button: "ContextualButton") -> None: + print(button.context) match button.context: case ButtonType.EXIT: logger.info("Normal user exit") @@ -288,13 +290,16 @@ class Controller: self.load_mods() case ButtonType.HELP: help_store = self.model_manager.get_help_store() + # TODO: simply set this model once and open the page self.mediator.treeview.set_model(help_store) - case ButtonType.MAIN_MENU: - # TODO: going to be deprecated after server notebook is added - row_store = self.model_manager.get_row_store() - self.mediator.treeview.set_model(row_store) + case ButtonType.SERVERS: + self.mediator.notebook.set_page_by_enum(button.opens) + # TODO: shorten this + treeview = self.mediator.notebook.servers.get_active_treeview() + treeview.grab_focus() + return - self.mediator.grid.notebook.set_page_by_enum(button.opens) + self.mediator.notebook.set_page_by_enum(button.opens) self.set_crumbs(button.get_label()) # TODO: deprecated? @@ -544,3 +549,29 @@ class Controller: def get_developer_mode(self) -> bool: return self.is_developer + + def set_server_statusbar(self) -> None: + # TODO: different models + model = self.model_manager.get_server_store() + model = AppNav.treeview.get_model() + if model is None: + players = 0 + hits = 0 + else: + hits = len(model) + players = 0 + for row in model: + players += row[4] + + # TODO: move to util.format + players_pretty = pluralize("players", players) + hits_pretty = pluralize("matches", hits) + formatted = ( + f"Found {hits:n} {hits_pretty} with {players:n} {players_pretty}" + ) + suffix = "| Distance: calculating..." + + if players == 0: + suffix = "" + self.set_text(formatted + suffix) + self.players = formatted diff --git a/dzgui/controllers/model.py b/dzgui/controllers/model.py index d8ebc7a..f401c67 100644 --- a/dzgui/controllers/model.py +++ b/dzgui/controllers/model.py @@ -2,7 +2,7 @@ import re from dataclasses import dataclass from typing import Self -from dzgui.const.enum import FilterMode, MAIN_MENU_ROWS, HELP_MENU_ROWS +from dzgui.const.enum import FilterMode, HELP_MENU_ROWS from dzgui.util import strings import gi @@ -69,16 +69,16 @@ class ModelManager: self.ping_cache: dict[str, int] = {} self.map_store = ListStore(str) - self.row_store = self.new_model_from_class(MenuCols) + #self.row_store = self.new_model_from_class(MenuCols) self.help_store = self.new_model_from_class(MenuCols) self.mod_store = self.new_model_from_class(ModCols) self.log_store = self.new_model_from_class(LogCols) self.modlist_store = self.new_model_from_class(ServerModCols) - for row in MAIN_MENU_ROWS: - label = row.dict["label"] - self.row_store.append([label, row]) + #for row in MAIN_MENU_ROWS: + # label = row.dict["label"] + # self.row_store.append([label, row]) for row in HELP_MENU_ROWS: label = row.dict["label"] @@ -100,8 +100,8 @@ class ModelManager: def get_map_store(self) -> ListStore: return self.map_store - def get_row_store(self) -> ListStore: - return self.row_store + #def get_row_store(self) -> ListStore: + # return self.row_store def get_help_store(self) -> ListStore: return self.help_store diff --git a/dzgui/util/strings.py b/dzgui/util/strings.py index 3bab098..8a92998 100644 --- a/dzgui/util/strings.py +++ b/dzgui/util/strings.py @@ -240,8 +240,8 @@ class Init: @dataclass(slots=True, frozen=True) class Button: - main_label: str - main_tooltip: str + servers_label: str + servers_tooltip: str mods_label: str mods_tooltip: str options_label: str @@ -426,8 +426,8 @@ dialog = Dialog( ) buttons = Button( - main_label="Main menu", - main_tooltip="Search for and connect to servers", + servers_label="Servers", + servers_tooltip="Search for and connect to servers", mods_label="Mods", mods_tooltip="Manage local mods", options_label="Options", @@ -448,7 +448,7 @@ crumbs = Crumbs( mods="Mods", my_servers="Main menu > Saved servers", options="Options", - servers="Main menu > Server browser", + servers="Servers", thanks="Help > Special thanks", developers="Options > Developers", ) diff --git a/dzgui/views/base.py b/dzgui/views/base.py index 2847449..c4418c6 100644 --- a/dzgui/views/base.py +++ b/dzgui/views/base.py @@ -11,13 +11,12 @@ import threading import typing # noqa import warnings -from collections.abc import Callable -from concurrent.futures import wait -from concurrent.futures import ThreadPoolExecutor +#from concurrent.futures import wait +#from concurrent.futures import ThreadPoolExecutor + from dataclasses import dataclass from enum import Enum from pathlib import Path -from typing import Literal, Any # TODO: most likely very little of this will be retained from dzgui.const.enum import ( @@ -26,7 +25,6 @@ from dzgui.const.enum import ( RowType, NotebookPage, VAdjustment, - MAIN_MENU_ROWS, ) from dzgui.const.constants import NO_EXPAND, NO_FILL, EXPAND, FILL from dzgui.const.constants import APP_NAME, APP_NAME_LOWER, WINDOW_DEFAULT_X, WINDOW_DEFAULT_Y @@ -34,26 +32,25 @@ from dzgui.controllers.mc import Controller from dzgui.util import css, dist, localize, strings, ip, deck, open_links from dzgui.util.format import pluralize -# GRID ITEMS +# NOTEBOOK ITEMS # TODO: import notebook only and add components there? from dzgui.views.pages.changelog import Changelog from dzgui.views.pages.keys import Keybindings -from dzgui.views.pages.thanks import Thanks from dzgui.views.pages.options import Options +from dzgui.views.pages.servers import ServerNotebook +from dzgui.views.pages.thanks import Thanks from dzgui.views.components.mod_panel import ModSelectionPanel from dzgui.views.components.right_panel import RightPanel from dzgui.views.components.toast import Toast +from dzgui.views.dialogs.generic import GenericDialog from dzgui.views.mixins.scrollable_mixin import ScrollableMixin # TREES from dzgui.views.trees.tree_log import LogTreeView -from dzgui.views.trees.tree_menu import MenuTreeView from dzgui.views.trees.tree_mods import ModTreeView from dzgui.views.trees.tree_servers import ServerTreeView -from dzgui.views.dialogs.generic import GenericDialog - # TODO: not going to be in base anymore import dzgui.util._json as JSON # noqa @@ -233,6 +230,7 @@ class OuterWindow(Gtk.Window): self.toast = Toast() self.overlay = Gtk.Overlay() self.overlay.add_overlay(self.grid) + # TODO: toast is deprecated self.overlay.add_overlay(self.toast) self.add(self.overlay) @@ -244,7 +242,7 @@ class OuterWindow(Gtk.Window): self.grid.sel_panel.set_visible(False) # TODO: register from treeview or notebook - AppNav.treeview = self.grid.notebook.scrollable_treelist.treeview + #AppNav.treeview = self.grid.notebook.scrollable_treelist.treeview css.load_css() AppNav.grid.notebook.set_page_by_enum(NotebookPage.SERVERS) @@ -268,27 +266,15 @@ class OuterWindow(Gtk.Window): MainController.save_res_and_quit() -# TODO: consolidate -# wrap base tree class in this -class ScrollableTree(Gtk.ScrolledWindow): - def __init__(self): - super().__init__() - - self.treeview = MenuTreeView(MainController) - self.add(self.treeview) - - def _set_adjustment(self, adjustment: VAdjustment) -> None: - pass - - class AppHeaderBar(Gtk.HeaderBar): - def __init__(self): + def __init__(self) -> None: super().__init__() self.props.title = APP_NAME self.set_decoration_layout(":minimize,maximize,close") self.set_show_close_button(True) +# TODO: deprecated class ScrollableNote(ScrollableMixin, Gtk.Box): def __init__(self, content_box: Gtk.Box, back_button=False): super().__init__(orientation=Gtk.Orientation.VERTICAL) @@ -322,11 +308,11 @@ class Notebook(ScrollableMixin, Gtk.Notebook): AppNav.notebook = self self.prior_page: int - # TODO: set internally - self.scrollable_treelist = ScrollableTree() - self.scrollable_treelist.set_hexpand(False) - self.scrollable_treelist.set_vexpand(True) - self.scrollable_treelist.type = None + # TODO: set static help page + #self.scrollable_treelist = ScrollableTree() + #self.scrollable_treelist.set_hexpand(False) + #self.scrollable_treelist.set_vexpand(True) + #self.scrollable_treelist.type = None self.change = Changelog(MainController) self.clog = ScrollableNote(self.change, back_button=False) @@ -344,11 +330,8 @@ class Notebook(ScrollableMixin, Gtk.Notebook): # add all treeviews as page and register them to AppNav and self.indexes # when switching to a treeview, update relevant view and just pop that page # instead of loading/unloading the model each time - from dzgui.views.pages.servers import ServerNotebook self.servers = ServerNotebook(MainController) - #self.ssu = Gtk.ScrolledWindow() - #self.servers = ServerTreeView(MainController) - #self.ssu.add(self.servers) + AppNav.servers = self.servers self.quad = Gtk.ScrolledWindow() @@ -369,9 +352,9 @@ class Notebook(ScrollableMixin, Gtk.Notebook): from dzgui.views.pages.devs import Developers developers = Developers(MainController) self.developers = ScrollableNote(developers) - + self.pages = { - self.scrollable_treelist: NotebookPage.MAIN, + #self.scrollable_treelist: NotebookPage.MAIN, self.clog: NotebookPage.CHANGELOG, self.keys: NotebookPage.KEYS, self.settings: NotebookPage.OPTIONS, @@ -491,6 +474,7 @@ class Notebook(ScrollableMixin, Gtk.Notebook): self.focus_current() # TODO: should be an internal property of those pages blank = [ + NotebookPage.SERVERS, NotebookPage.OPTIONS, NotebookPage.THANKS, NotebookPage.CHANGELOG, @@ -510,13 +494,11 @@ class Notebook(ScrollableMixin, Gtk.Notebook): crumbs = enum.dict["crumbs"] MainController.set_crumbs(crumbs) - # TODO: going to be deprecated after server notebook is added - if enum is not NotebookPage.MAIN: - return - - MainController.set_help_menu_crumbs() + # TODO: + # MainController.set_help_menu_crumbs() +# TODO: move to components class Statusbar(Gtk.Statusbar): def __init__(self) -> None: super().__init__() @@ -603,6 +585,14 @@ class Grid(Gtk.Grid): self.attach_next_to( 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 + #) + + self.attach_next_to( self.statusbar, self.notebook, Gtk.PositionType.BOTTOM, 3, 1 ) @@ -615,6 +605,7 @@ class Grid(Gtk.Grid): return self.breadcrumbs.get_text() def set_breadcrumbs(self, text: str) -> None: + # TODO: embolden func self.breadcrumbs.set_markup(f"{text}") @@ -658,7 +649,12 @@ class AppNavigation: window: OuterWindow notebook: Notebook right_panel: RightPanel - treeview: MenuTreeView + #treeview: MenuTreeView + servers: Gtk.ScrolledWindow + browser: ServerTreeView + saved: ServerTreeView + recent: ServerTreeView + lan: ServerTreeView modtreeview: ModTreeView logtreeview: LogTreeView # TODO: add tree_log and tree_server views here diff --git a/dzgui/views/components/buttonbox.py b/dzgui/views/components/buttonbox.py index 6cf6976..fefce37 100644 --- a/dzgui/views/components/buttonbox.py +++ b/dzgui/views/components/buttonbox.py @@ -29,7 +29,6 @@ class ButtonBox(Gtk.Box): orientation=Gtk.Orientation.VERTICAL, ) - self.prior_button = ButtonType.MAIN_MENU self.controller = controller self.buttons = list() self.connect("key-press-event", self._on_keypress) @@ -56,6 +55,10 @@ class ButtonBox(Gtk.Box): def _on_selection_button_clicked(self, button: Gtk.Button) -> None: self.controller.open_page_by_button(button) + button.set_sensitive(False) + for b in self.buttons: + if b != button: + b.set_sensitive(True) def _walk_buttons(self, increment: int) -> None: for i, button in enumerate(self.buttons): diff --git a/dzgui/views/components/connect_panel.py b/dzgui/views/components/connect_panel.py index f600828..90bdd69 100644 --- a/dzgui/views/components/connect_panel.py +++ b/dzgui/views/components/connect_panel.py @@ -2,16 +2,31 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # noqa E402 +from dzgui.views.components.web_button import WebButton + class ConnectPanel(Gtk.Grid): def __init__(self) -> None: - super().__init__() + super().__init__(vexpand=False, margin=20) self.label = Gtk.Label(label="Connect by IP/ID") - self.label2 = Gtk.Label(label="Save server by IP/ID") - self.entry1 = Gtk.Entry() + self.label2 = Gtk.Label(label="Favorite server") + # TODO: embold function + 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.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(self.label2, self.entry1, Gtk.PositionType.BOTTOM, 3, 1) - self.attach_next_to(self.entry2, self.label2, Gtk.PositionType.BOTTOM, 3, 1) + self.attach_next_to(button, self.entry1, Gtk.PositionType.RIGHT, 3, 1) + + 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) diff --git a/dzgui/views/components/web_button.py b/dzgui/views/components/web_button.py index 4d8f0ef..d0a301e 100644 --- a/dzgui/views/components/web_button.py +++ b/dzgui/views/components/web_button.py @@ -5,7 +5,7 @@ import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # noqa E402 - +# TODO: abstract to support other icons class WebButton(Gtk.Button): def __init__(self, label: str): super().__init__(label=label) diff --git a/dzgui/views/trees/tree_base.py b/dzgui/views/trees/tree_base.py index 7e4ce7c..1b50607 100644 --- a/dzgui/views/trees/tree_base.py +++ b/dzgui/views/trees/tree_base.py @@ -84,10 +84,15 @@ class TreeView(CursorMixin, Gtk.TreeView): if is_navkey(event.keyval): # TODO: investigate this + # TODO: get active tree if server view is open + servers = self.controller.mediator.notebook.servers + tv = servers.get_active_treeview() if self.sel_blocked is False: self.controller.suppress_signal( - self.controller.mediator.treeview, - self.controller.mediator.treeview.selected_row, + tv, + tv.selected_row, + #self.controller.mediator.treeview, + #self.controller.mediator.treeview.selected_row, "_on_tree_selection_changed", True, ) diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py index 53f643c..672c053 100644 --- a/dzgui/views/trees/tree_servers.py +++ b/dzgui/views/trees/tree_servers.py @@ -80,14 +80,6 @@ class ServerTreeView(TreeView): self.append_column(column) - # TODO: do not load model on initial init - # TODO: test values: see below - #r = Gtk.ListStore( - # str, str, str, str, int, int, int, str, int, int, str, bool - #) - #r.append(["TEST", "a", "a", "a", 0, 0, 0, "a", 0, 0, "a", False]) - #self.set_model(r) - self.connect("on_distcalc_started", self._on_calclat_started) @@ -117,7 +109,7 @@ class ServerTreeView(TreeView): addr = latest_result[0] km = latest_result[1] cache[addr] = km - # TODO: fixme + # FIXME self.statusbar.append_distance(km) return True @@ -137,9 +129,6 @@ class ServerTreeView(TreeView): return True AppNav.right_panel.filters_vbox.keyword_entry.grab_focus() case Gdk.KEY_m: - # FIXME: should no longer be relevant - if AppNav.treeview.view == WindowContext.TABLE_MODS: - return True AppNav.right_panel.filters_vbox.maps_entry.grab_focus() else: keyname = Gdk.keyval_name(event.keyval) @@ -164,6 +153,7 @@ class ServerTreeView(TreeView): def _on_server_button_release( self, widget: Gtk.Widget, event: Gdk.EventButton ) -> None: + # TODO: use ContextMixin if event.type is Gdk.EventType.BUTTON_RELEASE and event.button != 3: return @@ -181,6 +171,7 @@ class ServerTreeView(TreeView): self.menu = Gtk.Menu() mod_context_items = [ContextMenu.OPEN_WORKSHOP, ContextMenu.DELETE_MOD] # TODO: reimplement server context enums + # TODO: inherit from tree_servers.py server_context_items = { RowType.SERVER_BROWSER: [ ContextMenu.ADD_SERVER, @@ -221,12 +212,7 @@ class ServerTreeView(TreeView): } # TODO: how to get current server context - if self.view == WindowContext.TABLE_MODS: - items = mod_context_items - elif self.subpage in server_context_items: - items = server_context_items[self.subpage] - else: - return + items = server_context_items[self.subpage] for row in items: if row == ContextMenu.ADD_SERVER: @@ -265,22 +251,21 @@ class ServerTreeView(TreeView): print(self.get_value_at_index(0)) def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection): - print(self.get_value_at_index(0)) self.terminate_process() record = self.get_record() - print(record) - # TODO: ? - if not record: - grid.statusbar.update_server_meta() + if record is None: + # TODO: move to controller + #grid.statusbar.update_server_meta() return ip = record.ip - self.emit("on_distcalc_started") - self.current_proc = CalcDist(self, record.ip, self.queue, cache) - self.current_proc.start() + # TODO + #self.emit("on_distcalc_started") + #self.current_proc = CalcDist(self, record.ip, self.queue, cache) + #self.current_proc.start() def get_record_string(self) -> str: addr = self.get_value_at_index(7)