diff --git a/dzgui/controllers/emitter.py b/dzgui/controllers/emitter.py index 2be1efe..6c2481c 100644 --- a/dzgui/controllers/emitter.py +++ b/dzgui/controllers/emitter.py @@ -83,6 +83,10 @@ class Emitter(GObject.GObject): ) -> None: pass + @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(str,bool,)) + def check_toggled(self, label: str, state: bool) -> None: + pass + @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(object,)) def servers_loaded(self, tag: "ServerTab") -> None: pass diff --git a/dzgui/controllers/mc.py b/dzgui/controllers/mc.py index 510ccba..3cfc62d 100644 --- a/dzgui/controllers/mc.py +++ b/dzgui/controllers/mc.py @@ -23,7 +23,13 @@ from dzgui.api.mods import ( _hash, remove_stale_signatures, ) -from dzgui.const.enum import FilterMode, Preferences, NotebookPage, ButtonType, ContextMenu +from dzgui.const.enum import ( + FilterMode, + Preferences, + NotebookPage, + ButtonType, + ContextMenu, +) from dzgui.const.constants import ( APPID_DAYZ, @@ -56,6 +62,7 @@ from gi.repository import Gtk, Gdk, GLib, GObject # noqa E402 logger = logging.getLogger(__name__) if TYPE_CHECKING: + from dzgui.model.map_model import MapManager from dzgui.const.enum import ServerTab from dzgui.util.dist import Haversine from dzgui.views.base import Notebook, Grid, OuterWindow @@ -95,11 +102,11 @@ class Controller(GObject.GObject): self.model_man = ModelManager() self.emitter = Emitter() self.emitter.connect("map_selection_changed", self._on_map_selection_changed) + self.emitter.connect("check_toggled", self._on_check_toggled) # NOTE: suppress requests until entire UI is loaded self.loaded = False - def get_emitter(self) -> Emitter: return self.emitter @@ -112,7 +119,9 @@ class Controller(GObject.GObject): self.wait_dialog.show_all() thread = threading.Thread(target=func, args=args) thread.start() + return wrapper + return decorator def register_widget(self, attr: str, widget: Gtk.Widget) -> None: @@ -250,10 +259,10 @@ class Controller(GObject.GObject): context = self.get_active_context() page = self.mediator.notebook.get_page_by_enum() if page != NotebookPage.SERVERS: - self.emitter.emit("distcalc_ended" , None, context) + self.emitter.emit("distcalc_ended", None, context) return if enum != context: - self.emitter.emit("distcalc_ended" , None, context) + self.emitter.emit("distcalc_ended", None, context) return dist: str @@ -357,10 +366,7 @@ class Controller(GObject.GObject): params = Servers.params serv = [] with ThreadPoolExecutor() as executor: - futures = [ - executor.submit(job, key, APPID_DAYZ, param) - for param in params - ] + futures = [executor.submit(job, key, APPID_DAYZ, param) for param in params] wait(futures) for future in futures: res = future.result() @@ -368,7 +374,7 @@ class Controller(GObject.GObject): # TODO: pop warning dialog, create enum around various failure states # TODO: if first iteration, disable map combo. otherwise, do nothing self.new_maps = None - self.push_data_failure() #None, FilterMode.INITIAL, success=False) + self.push_data_failure() # None, FilterMode.INITIAL, success=False) return j = res.json serv += j["response"]["servers"] @@ -436,9 +442,9 @@ class Controller(GObject.GObject): open_workshop_page(mod, cmd) # TODO: put in model manager (dedicated manager for mod store) - #def get_mod_from_tree_path( + # def get_mod_from_tree_path( # self, tree_path: Gtk.TreePath - #) -> tuple[str, Gtk.TreeIter]: + # ) -> tuple[str, Gtk.TreeIter]: # model = self.model_man.get_mod_store() # tree_iter = model.get_iter(tree_path) # mod = model.get(tree_iter, 2)[0] @@ -544,7 +550,6 @@ class Controller(GObject.GObject): case ContextMenu.OPEN_WORKSHOP: self.open_mod_page(path) - def toggle_mod_selection(self, state: bool) -> None: sel = self.mediator.modtreeview.get_selection() if state: @@ -596,7 +601,7 @@ class Controller(GObject.GObject): it = mod.iter path = model.get_path(it) # TODO: consider storing in ListStore as int - # TODO: clone existing model and set outside of thread + # TODO: clone existing model and set outside of threai if int(mod[2]) in stale: model[path][4] = HEX_RED @@ -607,25 +612,172 @@ class Controller(GObject.GObject): def dump_test_2(self) -> None: import time + time.sleep(1) data = ( - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "172.111.51.156:2302", 1, 1, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 1, 1, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], - ["BAR", "chernarusplus", "a", "a", 1, 1, 1, "185.207.214.16:2302", 0, 0, "a", False], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 1, + 1, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "172.111.51.156:2302", + 1, + 1, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 1, + 1, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 1, + 1, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 0, + 0, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 0, + 0, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 0, + 0, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 0, + 0, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 0, + 0, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 0, + 0, + "a", + False, + ], + [ + "BAR", + "chernarusplus", + "a", + "a", + 1, + 1, + 1, + "185.207.214.16:2302", + 0, + 0, + "a", + False, + ], ) self.push_data(data, FilterMode.INITIAL, success=True) # TODO: eg dedicated cleanup on failure, cleanup on sucess # these can pop their own predefined dialogs, much simpler + def get_map_man(self) -> "MapManager": + return self.get_active_treeview().get_map_man() + def cleanup(self) -> None: treeview = self.get_active_treeview() treeview.set_loaded(True) @@ -636,7 +788,6 @@ class Controller(GObject.GObject): # model insertion after thread closes # cf. servers_loaded signal - context = self.get_active_context() self.emitter.emit("servers_loaded", context) @@ -647,10 +798,9 @@ class Controller(GObject.GObject): self.first_iteration = False self.new_maps = None - treeview.grab_focus() self.destroy_on_idle() - #if self.success is False: + # if self.success is False: # # TODO: different dialogs for server tab contexts, e.g. lan timeout # # TODO: if history/favorites is empty, don't even trigger a call to dump data # dialog = ExceptionDialog(self, "API TIMEOUT") @@ -679,7 +829,7 @@ class Controller(GObject.GObject): treeview = self.get_active_treeview() treeview.set_loaded(True) # TODO: wipe control model on failure or keep old results? - manager = treeview.get_filter_man() + # manager = treeview.get_filter_man() GLib.idle_add(self.cleanup_on_failure) def push_data(self, data: tuple, mode: Optional[FilterMode], success: bool) -> None: @@ -841,7 +991,7 @@ class Controller(GObject.GObject): return # TODO: maybe set tree to none afterwards (swap models) - #treeview.set_model(None) + # treeview.set_model(None) func = treeview.get_query_func() if func is None: self.emitter.emit("servers_loaded", treeview.get_enum()) @@ -887,23 +1037,33 @@ class Controller(GObject.GObject): return self.mediator.filters.get_keyword_filter() def get_map_store(self) -> Gtk.ListStore: - treeview = self.get_active_treeview() - map_man = treeview.get_map_man() + map_man = self.get_map_man() return map_man.get_map_store() def get_selected_map(self) -> str: - treeview = self.get_active_treeview() - map_man = treeview.get_map_man() + map_man = self.get_map_man() return map_man.get_selected_map() + def get_enabled_filters(self) -> dict: + map_man = self.get_map_man() + return map_man.get_filters() + def get_prior_map(self) -> str: - treeview = self.get_active_treeview() - map_man = treeview.get_map_man() + map_man = self.get_map_man() return map_man.get_prior_map() + def _on_check_toggled(self, emitter: Emitter, label: str, state: bool) -> None: + map_man = self.get_map_man() + map_man.set_filter(label, state) + + if state: + mode = FilterMode.TOGGLE_ON + else: + mode = FilterMode.TOGGLE_OFF + self.refilter_model(mode, label) + def _on_map_selection_changed(self, emitter: Emitter, selection: str) -> None: - treeview = self.get_active_treeview() - map_man = treeview.get_map_man() + map_man = self.get_map_man() map_man.set_selected_map(selection) self.refilter_model(FilterMode.MAP) diff --git a/dzgui/util/strings.py b/dzgui/util/strings.py index 0e43df0..0d37986 100644 --- a/dzgui/util/strings.py +++ b/dzgui/util/strings.py @@ -417,7 +417,7 @@ options = Options( DZGUI will manage mod installation and deletion for you. To prevent conflicts with Steam Workshop subscriptions and old mods from being downloaded when Steam updates, you should unsubscribe from any existing Workshop mods you manually subscribed to. -Open your Profile > Workshop Items and select 'Unsubscribe from all' +Open your Profile, then 'Workshop Items' and select 'Unsubscribe from all' on the right-hand side. """, ) diff --git a/dzgui/views/components/filter_panel.py b/dzgui/views/components/filter_panel.py index ad89a34..92eb9ab 100644 --- a/dzgui/views/components/filter_panel.py +++ b/dzgui/views/components/filter_panel.py @@ -20,83 +20,151 @@ if TYPE_CHECKING: from dzgui.const.enum import ServerTab -class FilterPanel(Gtk.Box): - def __init__(self, controller: "Controller") -> None: - super().__init__(spacing=6, vexpand=False) - - self.default_filters = { - strings.filter_1pp: True, - strings.filter_day: True, - strings.filter_empty: False, - strings.filter_3pp: True, - strings.filter_night: True, - strings.filter_full: False, - strings.filter_lowpop: True, - strings.filter_nonascii: False, - strings.filter_duplicate: False, - strings.filter_official: True, - strings.filter_unofficial: True, - strings.filter_modded: True, - } - - self.controller = controller - self.controller.register_widget("filters", self) - self.emitter = self.controller.get_emitter() - - self.map_store = self.controller.get_map_store() - - self.checks = [] - self.maps_hr = [] - - self.enabled_filters = dict(self.default_filters) - self.keyword_filter = "" - #self.selected_map: str = strings.all_maps - #self.prior_map: str = strings.all_maps - - self.button_grid = Gtk.Grid( +class ButtonGrid(Gtk.Grid): + def __init__(self, controller: "Controller", defaults: dict) -> None: + super().__init__( halign=Gtk.Align.CENTER, column_spacing=5, column_homogeneous=True ) row = 1 col = 0 + + self.controller = controller + self.emitter = controller.get_emitter() + + self.checks: list[Gtk.CheckButton] = [] + # TODO: use enumerated checks - for check in self.default_filters.keys(): + for check in defaults.keys(): checkbox = Gtk.CheckButton(label=check) label = checkbox.get_children() label[0].set_ellipsize(Pango.EllipsizeMode.END) - if self.default_filters[check]: + if defaults[check]: checkbox.set_active(True) col = col + 1 if col > 3: row += 1 col = 1 - self.button_grid.attach(checkbox, col, row, 1, 1) - + self.attach(checkbox, col, row, 1, 1) checkbox.connect("toggled", self._on_check_toggled) self.checks.append(checkbox) - self.connect("button-release-event", self._on_button_release) - self.set_orientation(Gtk.Orientation.VERTICAL) + def block_toggles(self, state: bool) -> None: + for check in self.checks: + self.controller.suppress_signal( + self, + check, + "_on_check_toggled", + state, + ) + + def reload_filters(self) -> None: + checkboxes = self.checks + self.block_toggles(True) + filters = self.controller.get_enabled_filters() + for check in checkboxes: + label = check.get_label() + state = filters[label] + check.set_active(state) + self.block_toggles(False) + + def _on_check_toggled(self, button: Gtk.CheckButton) -> None: + label = button.get_label() + state = button.get_active() + logger.info(f"User toggled button '{label}' to {state}") + self.emitter.emit("check_toggled", label, state) + + def get_checkboxes(self) -> list: + return self.checks + + +class KeywordEntry(Gtk.Entry): + def __init__(self, controller: "Controller") -> None: + # TODO :strings + super().__init__(placeholder_text="Filter by keyword") + + self.keyword_filter = "" + self.controller = controller + self.connect("activate", self._on_activated) + self.connect("key-press-event", self._on_keypress) + self.connect("icon-release", lambda *args: self.activate()) + + self.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, SEARCH_ICON) + self.set_icon_activatable(Gtk.EntryIconPosition.SECONDARY, True) + + def get_keyword(self) -> str: + return self.keyword_filter + + def _on_keypress(self, entry: Gtk.Entry, event: Gdk.EventKey) -> bool: + match event.keyval: + case Gdk.KEY_Up: + return True + case Gdk.KEY_Down: + return True + case Gdk.KEY_Escape: + GLib.idle_add(self.restore_focus_to_treeview) + return True + return False + + def _on_activated(self, entry: Gtk.Entry) -> None: + # TODO: investigate this method + self.controller.mediator.window.set_keep_below(False) + keyword = entry.get_text().lower() + if keyword == self.keyword_filter: + return + if keyword.isspace(): + return + logger.info(f"User filtered by keyword '{keyword}'") + self.keyword_filter = keyword + self.controller.refilter_model(FilterMode.KEYWORD, keyword) + + +class FilterPanel(Gtk.Box): + def __init__(self, controller: "Controller") -> None: + super().__init__(spacing=6, vexpand=False, orientation=Gtk.Orientation.VERTICAL) + + # TODO: get these from metamanager + # self.default_filters = { + # strings.filter_1pp: True, + # strings.filter_day: True, + # strings.filter_empty: False, + # strings.filter_3pp: True, + # strings.filter_night: True, + # strings.filter_full: False, + # strings.filter_lowpop: True, + # strings.filter_nonascii: False, + # strings.filter_duplicate: False, + # strings.filter_official: True, + # strings.filter_unofficial: True, + # strings.filter_modded: True, + # } + + self.controller = controller + self.controller.register_widget("filters", self) + self.emitter = self.controller.get_emitter() + + # self.selected_map: str = strings.all_maps + # self.prior_map: str = strings.all_maps + # self.set_orientation(Gtk.Orientation.VERTICAL) + + # TODO: initialize to empty + map_man = self.controller.get_map_man() + defaults = map_man.get_default_filters() + self.map_store = map_man.get_map_store() + self.enabled_filters = defaults + + self.keyword_entry = KeywordEntry(self.controller) + self.button_grid = ButtonGrid(self.controller, defaults) + + # TODO: unintended legacy behavior? + self.connect("button-release-event", lambda *args: True) set_surrounding_margins(self, 10) self.set_margin_top(1) # TODO: strings self.filters_label = BoldLabel("Filters") - self.keyword_entry = Gtk.Entry() - # TODO :strings - self.keyword_entry.set_placeholder_text("Filter by keyword") - self.keyword_entry.connect("activate", self._on_keyword_activated) - self.keyword_entry.connect("key-press-event", self._on_keyword_keypress) - self.keyword_entry.set_icon_from_icon_name( - Gtk.EntryIconPosition.SECONDARY, SEARCH_ICON - ) - self.keyword_entry.set_icon_activatable(Gtk.EntryIconPosition.SECONDARY, True) - self.keyword_entry.connect( - "icon-release", lambda *args: self.keyword_entry.activate() - ) - self.emitter.connect( "request_keyword_focus", lambda _: self.keyword_entry.grab_focus() ) @@ -107,6 +175,7 @@ class FilterPanel(Gtk.Box): self.emitter.connect("servers_loaded", self._on_servers_loaded) self.emitter.connect("load_maps", self._on_maps_loaded) + # TODO: break into MapsCombo class completion = Gtk.EntryCompletion(inline_completion=True) completion.set_text_column(0) completion.set_minimum_key_length(1) @@ -121,14 +190,30 @@ class FilterPanel(Gtk.Box): self.maps_entry.set_placeholder_text("Filter by map") self.maps_entry.connect("changed", self._on_map_completion, True) self.maps_entry.connect("key-press-event", self._on_map_entry_keypress) + self.maps_entry.connect("activate", self._on_maps_activated) self.maps_combo.pack_start(renderer_text, EXPAND) self.maps_combo.connect("changed", self._on_map_changed) self.maps_combo.connect("key-press-event", self._on_combo_keypress) - for el in self.filters_label, self.keyword_entry, self.maps_combo, self.button_grid: + for el in ( + self.filters_label, + self.keyword_entry, + self.maps_combo, + self.button_grid, + ): self.pack_start(el, NO_EXPAND, NO_FILL, NO_PADDING) + def _on_maps_activated(self, entry: Gtk.Entry) -> None: + text = entry.get_text() + model = self.maps_combo.get_model() + if text is None: + return + for i, row in enumerate(model): + if text == row[0]: + self.maps_combo.set_active(i) + self._on_map_changed(self.maps_combo) + def _on_servers_loaded(self, emitter: "Emitter", tab: "ServerTab") -> None: state = self.controller.has_server_model() for widget in (self.keyword_entry, self.maps_combo, self.button_grid): @@ -137,17 +222,23 @@ class FilterPanel(Gtk.Box): def _on_maps_loaded(self, emitter: "Emitter", store: Gtk.ListStore) -> None: self.maps_combo.set_model(store) self.maps_combo.set_active(0) + self.button_grid.reload_filters() + # TODO: move into metamanager def get_filters(self) -> tuple: selected = self.controller.get_selected_map() + enabled = self.controller.get_enabled_filters() filters = [] filters.append(selected) - filters.append(self.keyword_filter) - for k in self.enabled_filters: - if not self.enabled_filters[k]: - filters.append(k) + filters.append(self.get_keyword_filter()) + for filt in enabled: + if enabled[filt] is False: + filters.append(filt) return tuple(filters) + def get_keyword_filter(self) -> str: + return self.keyword_entry.get_keyword() + # TODO: should be used when switching ServerTab contexts # use signals here # def reinit_panel(self) -> None: @@ -159,29 +250,17 @@ class FilterPanel(Gtk.Box): # if sel_panel.is_visible(): # sel_panel.set_visible(False) - # TODO: change filters on a per-tab basis - def reinit_filters(self) -> None: - self.enabled_filters = dict(self.default_filters) - for check in self.checks: - label = check.get_label() - state = self.default_filters[label] - check.set_active(state) + # TODO: this chiefly applies when clicking refresh button, etc. + # and setting filters to default state + # def reinit_filters(self) -> None: + # self.enabled_filters = dict(self.default_filters) + # for check in self.checks: + # label = check.get_label() + # state = self.default_filters[label] + # check.set_active(state) def _on_map_entry_keypress(self, entry: Gtk.Entry, event: Gdk.EventKey) -> None: - # TODO: use activated() signal match event.keyval: - case Gdk.KEY_Return: - text = entry.get_text() - if text is None: - return - """ - If entry is exact match for value in liststore, - trigger map change function - """ - for i in enumerate(self.map_store): # type: ignore - if text == i[1][0]: - self.maps_combo.set_active(i[0]) - self._on_map_changed(self.maps_combo) case Gdk.KEY_Escape: GLib.idle_add(self.restore_focus_to_treeview) """ @@ -191,7 +270,7 @@ class FilterPanel(Gtk.Box): text = self.maps_entry.get_text() self.maps_entry.set_position(len(text)) case _: - return + return False def _on_completer_match( self, @@ -213,17 +292,6 @@ class FilterPanel(Gtk.Box): view.grab_focus() return False - def _on_keyword_keypress(self, entry: Gtk.Entry, event: Gdk.EventKey) -> bool: - match event.keyval: - case Gdk.KEY_Up: - return True - case Gdk.KEY_Down: - return True - case Gdk.KEY_Escape: - GLib.idle_add(self.restore_focus_to_treeview) - return True - return False - def _on_combo_keypress(self, combo: Gtk.ComboBox, event: Gdk.EventKey) -> bool: match event.keyval: case Gdk.KEY_Down: @@ -232,33 +300,13 @@ class FilterPanel(Gtk.Box): case _: return False - def get_keyword_filter(self) -> str: - return self.keyword_filter - - def _on_keyword_activated(self, entry: Gtk.Entry) -> None: - # TODO: - self.controller.mediator.window.set_keep_below(False) - keyword = entry.get_text().lower() - if keyword == self.keyword_filter: - return - if keyword.isspace(): - return - logger.info(f"User filtered by keyword '{keyword}'") - self.keyword_filter = keyword - self.controller.refilter_model(FilterMode.KEYWORD, keyword) - - def _on_button_release(self, window, button) -> Literal[True]: - return True - def get_active_combo(self) -> int: return self.maps_combo.get_active() def set_active_combo(self, row: int) -> None: self.maps_combo.set_active(row) - def toggle_check_by_key( - self, emitter: "Emitter", keyval: int - ) -> None | Literal[False]: + def toggle_check_by_key(self, emitter: "Emitter", keyval: int) -> bool: mappings = { Gdk.KEY_1: 0, Gdk.KEY_2: 1, @@ -277,24 +325,14 @@ class FilterPanel(Gtk.Box): return False index = mappings[keyval] self.toggle_check(index) + return True def toggle_check(self, digit: int) -> None: - check = self.checks[digit] + checks = self.button_grid.get_checkboxes() + check = checks[digit] state = check.get_active() check.set_active(not state) - def _on_check_toggled(self, button: Gtk.CheckButton) -> None: - label = button.get_label() - state = button.get_active() - logger.info(f"User toggled button '{label}' to {state}") - if state: - mode = FilterMode.TOGGLE_ON - else: - mode = FilterMode.TOGGLE_OFF - - self.enabled_filters[label] = state - self.controller.refilter_model(mode, label) - def _on_map_changed(self, combo: Gtk.ComboBox) -> None: old_sel = self.controller.get_selected_map() model = combo.get_model() @@ -306,6 +344,6 @@ class FilterPanel(Gtk.Box): return if not selection: return - logger.info(f"User selected map '{selection}'") self.maps_entry.set_text(selection) + logger.info(f"User selected map '{selection}'") self.emitter.emit("map_selection_changed", selection) diff --git a/dzgui/views/dialogs/link_dialog.py b/dzgui/views/dialogs/link_dialog.py index ba7cded..57e6c09 100644 --- a/dzgui/views/dialogs/link_dialog.py +++ b/dzgui/views/dialogs/link_dialog.py @@ -4,6 +4,7 @@ from typing import Self, TYPE_CHECKING from dzgui.const.enum import Popup, Preferences from dzgui.const.constants import NO_EXPAND, NO_FILL from dzgui.util.open_links import open_user_workshop +from dzgui.util.strings import notice from dzgui.views.dialogs.generic import GenericDialog from dzgui.views.components.buttons import SteamTextButton, WebButton @@ -18,9 +19,9 @@ if TYPE_CHECKING: class WorkshopLinkDialog(GenericDialog): def __init__(self, controller: "Controller", text: str, button_label: str, uid: str): - super().__init__(controller, text, Popup.NOTIFY) - - text = textwrap.dedent(text) + text = textwrap.dedent(text).replace("\n", " ") + super().__init__(controller, text=notice, mtype=Gtk.MessageType.INFO, buttons=Gtk.ButtonsType.OK, secondary=text) + self.controller = controller self.dialogBox = self.get_content_area() self.set_default_response(Gtk.ResponseType.OK) self.set_size_request(500, 0) diff --git a/dzgui/views/trees/tree_servers.py b/dzgui/views/trees/tree_servers.py index 460d104..f84ebf6 100644 --- a/dzgui/views/trees/tree_servers.py +++ b/dzgui/views/trees/tree_servers.py @@ -116,6 +116,7 @@ class ServerTreeView(ContextMixin, TreeView): self.emitter.connect("servers_loaded", self._on_servers_loaded) def _on_servers_loaded(self, emitter: "Emitter", tab: "ServerTab") -> None: + # FIXME: gets called on every tab, should be localized only to that context state = self.controller.has_server_model() self.set_headers_clickable(state)