mirror of
https://github.com/aclist/dztui.git
synced 2026-10-31 23:22:44 +01:00
feat: wrap callback function
This commit is contained in:
1 parent
2c8e722d8a
commit
96244a4560
8 files changed
+150
-108
No files matched your search
@@ -83,7 +83,23 @@ class Emitter(GObject.GObject):
|
|||||||
) -> None:
|
) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(str,bool,))
|
@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=(
|
||||||
|
str,
|
||||||
|
bool,
|
||||||
|
),
|
||||||
|
)
|
||||||
def check_toggled(self, label: str, state: bool) -> None:
|
def check_toggled(self, label: str, state: bool) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -102,3 +118,15 @@ class Emitter(GObject.GObject):
|
|||||||
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(object,))
|
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(object,))
|
||||||
def load_maps(self, store: ListStore) -> None:
|
def load_maps(self, store: ListStore) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
|
||||||
|
def mod_page_loaded(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
|
||||||
|
def mods_highlighted(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
|
||||||
|
def api_change_failed(self) -> None:
|
||||||
|
pass
|
||||||
+63
-74
@@ -1,3 +1,4 @@
|
|||||||
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
import shutil
|
import shutil
|
||||||
import threading
|
import threading
|
||||||
@@ -93,11 +94,22 @@ class AppNavigation:
|
|||||||
filters: "FilterPanel"
|
filters: "FilterPanel"
|
||||||
|
|
||||||
|
|
||||||
|
class CleanupFunc:
|
||||||
|
def __init__(self, func: Callable, *args, **kwargs) -> None:
|
||||||
|
sig = inspect.signature(func)
|
||||||
|
self.func = func
|
||||||
|
self.bindings = sig.bind(*args, **kwargs)
|
||||||
|
|
||||||
|
def call(self) -> None:
|
||||||
|
self.func(*self.bindings.args, *self.bindings.kwargs)
|
||||||
|
|
||||||
|
|
||||||
class Controller(GObject.GObject):
|
class Controller(GObject.GObject):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.dist_cache: dict[str, "Haversine", "ServerTab"] = {}
|
self.dist_cache: dict[str, "Haversine", "ServerTab"] = {}
|
||||||
self.mediator = AppNavigation()
|
self.mediator = AppNavigation()
|
||||||
self.prefs: UserPrefs
|
self.prefs: UserPrefs
|
||||||
|
self.cleanup_func: CleanupFunc = None
|
||||||
|
|
||||||
self.model_man = ModelManager()
|
self.model_man = ModelManager()
|
||||||
self.emitter = Emitter()
|
self.emitter = Emitter()
|
||||||
@@ -114,10 +126,14 @@ class Controller(GObject.GObject):
|
|||||||
def decorator(func: Callable) -> Callable:
|
def decorator(func: Callable) -> Callable:
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
|
def callback() -> None:
|
||||||
|
func(*args, **kwargs)
|
||||||
|
GLib.idle_add(self._destroy_on_idle)
|
||||||
|
|
||||||
self = args[0]
|
self = args[0]
|
||||||
self.wait_dialog = WaitDialog(self, dialog_str)
|
self.wait_dialog = WaitDialog(self, dialog_str)
|
||||||
self.wait_dialog.show_all()
|
self.wait_dialog.show_all()
|
||||||
thread = threading.Thread(target=func, args=args)
|
thread = threading.Thread(target=callback)
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
@@ -156,6 +172,7 @@ class Controller(GObject.GObject):
|
|||||||
def unblock_signals(self) -> None:
|
def unblock_signals(self) -> None:
|
||||||
self.block_signals(False)
|
self.block_signals(False)
|
||||||
|
|
||||||
|
@deprecated("Currently unused")
|
||||||
def block_signals(self, state: bool = True) -> None:
|
def block_signals(self, state: bool = True) -> None:
|
||||||
self.suppress_signal(
|
self.suppress_signal(
|
||||||
self.mediator.filters,
|
self.mediator.filters,
|
||||||
@@ -280,6 +297,7 @@ class Controller(GObject.GObject):
|
|||||||
|
|
||||||
self.emitter.emit("distcalc_ended", dist, context)
|
self.emitter.emit("distcalc_ended", dist, context)
|
||||||
|
|
||||||
|
# TODO: threading
|
||||||
def delete_multiple_mods(self) -> None:
|
def delete_multiple_mods(self) -> None:
|
||||||
sel = self.mediator.modtreeview.get_selection()
|
sel = self.mediator.modtreeview.get_selection()
|
||||||
model, pathlist = sel.get_selected_rows()
|
model, pathlist = sel.get_selected_rows()
|
||||||
@@ -290,10 +308,13 @@ class Controller(GObject.GObject):
|
|||||||
total_mods, total_size = self.calc_mod_size()
|
total_mods, total_size = self.calc_mod_size()
|
||||||
self.update_mod_statusbar()
|
self.update_mod_statusbar()
|
||||||
|
|
||||||
|
def load_mods_cleanup(self, model: Gtk.ListStore) -> None:
|
||||||
|
self.mediator.modtreeview.set_model(model)
|
||||||
|
self.emitter.emit("mod_page_loaded")
|
||||||
|
|
||||||
|
@call_on_thread(strings.dialog.modlist)
|
||||||
def load_mods(self) -> None:
|
def load_mods(self) -> None:
|
||||||
# TODO: threading; could get slow with 100s of mods
|
model = self.model_man.new_mod_store()
|
||||||
model = self.model_man.get_mod_store()
|
|
||||||
model.clear()
|
|
||||||
path = self.query_config(Preferences.DEFAULT)
|
path = self.query_config(Preferences.DEFAULT)
|
||||||
mods = get_delimited_mods(Path(path))
|
mods = get_delimited_mods(Path(path))
|
||||||
|
|
||||||
@@ -302,6 +323,8 @@ class Controller(GObject.GObject):
|
|||||||
mod.append(None)
|
mod.append(None)
|
||||||
model.append(mod)
|
model.append(mod)
|
||||||
|
|
||||||
|
self.cleanup_func = CleanupFunc(self.load_mods_cleanup, model)
|
||||||
|
|
||||||
def toggle_config(self, context: Preferences) -> None:
|
def toggle_config(self, context: Preferences) -> None:
|
||||||
config = self.prefs.paths.config
|
config = self.prefs.paths.config
|
||||||
try:
|
try:
|
||||||
@@ -484,16 +507,21 @@ class Controller(GObject.GObject):
|
|||||||
except PeFile.AppNotInstalledError:
|
except PeFile.AppNotInstalledError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
model = self.model_man.get_mod_store()
|
model = self.get_mod_store()
|
||||||
model.remove(it)
|
model.remove(it)
|
||||||
|
|
||||||
|
def get_mod_store(self) -> Gtk.ListStore:
|
||||||
|
return self.mediator.modtreeview.get_model()
|
||||||
|
|
||||||
def format_mod_statusbar(self) -> None:
|
def format_mod_statusbar(self) -> None:
|
||||||
total_mods, total_size = self.calc_mod_size()
|
total_mods, total_size = self.calc_mod_size()
|
||||||
msg = format_mods(total_size, total_mods)
|
msg = format_mods(total_size, total_mods)
|
||||||
return msg
|
return msg
|
||||||
|
|
||||||
def calc_mod_size(self) -> tuple[int, int]:
|
def calc_mod_size(self) -> tuple[int, int]:
|
||||||
model = self.model_man.get_mod_store()
|
model = self.get_mod_store()
|
||||||
|
if model is None:
|
||||||
|
return 0, 0
|
||||||
total_mods = len(model)
|
total_mods = len(model)
|
||||||
total_size = 0
|
total_size = 0
|
||||||
for mod in model:
|
for mod in model:
|
||||||
@@ -590,7 +618,7 @@ class Controller(GObject.GObject):
|
|||||||
self.open_page(NotebookPage.LOG)
|
self.open_page(NotebookPage.LOG)
|
||||||
|
|
||||||
def select_colorized(self) -> None:
|
def select_colorized(self) -> None:
|
||||||
model = self.model_man.get_mod_store()
|
model = self.get_mod_store()
|
||||||
sel = self.mediator.modtreeview.get_selection()
|
sel = self.mediator.modtreeview.get_selection()
|
||||||
for mod in model:
|
for mod in model:
|
||||||
it = mod.iter
|
it = mod.iter
|
||||||
@@ -598,29 +626,14 @@ class Controller(GObject.GObject):
|
|||||||
if mod[4] == HEX_RED:
|
if mod[4] == HEX_RED:
|
||||||
sel.select_path(path)
|
sel.select_path(path)
|
||||||
|
|
||||||
|
# TODO: make as method of tree?
|
||||||
def uncolorize_mods(self) -> None:
|
def uncolorize_mods(self) -> None:
|
||||||
model = self.model_man.get_mod_store()
|
model = self.get_mod_store()
|
||||||
for mod in model:
|
for mod in model:
|
||||||
it = mod.iter
|
it = mod.iter
|
||||||
path = model.get_path(it)
|
path = model.get_path(it)
|
||||||
model[path][4] = None
|
model[path][4] = None
|
||||||
|
|
||||||
def colorize_mods(self) -> None:
|
|
||||||
model = self.model_man.get_mod_store()
|
|
||||||
stale = find_stale_mods(self.prefs.paths.config)
|
|
||||||
for mod in model:
|
|
||||||
it = mod.iter
|
|
||||||
path = model.get_path(it)
|
|
||||||
# TODO: consider storing in ListStore as int
|
|
||||||
# TODO: clone existing model and set outside of threai
|
|
||||||
if int(mod[2]) in stale:
|
|
||||||
model[path][4] = HEX_RED
|
|
||||||
|
|
||||||
self.destroy_on_idle()
|
|
||||||
|
|
||||||
def unselect_all_mods(self) -> None:
|
|
||||||
self.mediator.modtreeview.get_selection().unselect_all()
|
|
||||||
|
|
||||||
def dump_test_2(self) -> None:
|
def dump_test_2(self) -> None:
|
||||||
import time
|
import time
|
||||||
|
|
||||||
@@ -810,7 +823,6 @@ class Controller(GObject.GObject):
|
|||||||
self.new_maps = None
|
self.new_maps = None
|
||||||
|
|
||||||
treeview.grab_focus()
|
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: 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
|
# # TODO: if history/favorites is empty, don't even trigger a call to dump data
|
||||||
@@ -818,10 +830,10 @@ class Controller(GObject.GObject):
|
|||||||
# dialog.run()
|
# dialog.run()
|
||||||
|
|
||||||
def cleanup_on_failure(self) -> None:
|
def cleanup_on_failure(self) -> None:
|
||||||
# TODO: what if refresh action occurred, and the old model is valid?
|
|
||||||
treeview = self.get_active_treeview()
|
treeview = self.get_active_treeview()
|
||||||
treeview.set_model(None)
|
treeview.set_model(None)
|
||||||
map_man = treeview.get_map_man()
|
map_man = treeview.get_map_man()
|
||||||
|
# TODO: what if refresh action occurred, and the old model is still valid?
|
||||||
# TODO: disable map, keyword, and filter widgets if model is None?
|
# TODO: disable map, keyword, and filter widgets if model is None?
|
||||||
# -> signal driven (servers_empty)
|
# -> signal driven (servers_empty)
|
||||||
# would have to make those unsensitive when changing server tabs
|
# would have to make those unsensitive when changing server tabs
|
||||||
@@ -832,7 +844,6 @@ class Controller(GObject.GObject):
|
|||||||
# TODO: distinguish signals, e.g. "servers_failed_to_load"
|
# TODO: distinguish signals, e.g. "servers_failed_to_load"
|
||||||
self.emitter.emit("servers_loaded", context)
|
self.emitter.emit("servers_loaded", context)
|
||||||
treeview.grab_focus()
|
treeview.grab_focus()
|
||||||
self.destroy_on_idle()
|
|
||||||
dialog = ExceptionDialog(self, "API TIMEOUT")
|
dialog = ExceptionDialog(self, "API TIMEOUT")
|
||||||
dialog.run()
|
dialog.run()
|
||||||
|
|
||||||
@@ -841,7 +852,7 @@ class Controller(GObject.GObject):
|
|||||||
treeview.set_loaded(True)
|
treeview.set_loaded(True)
|
||||||
# TODO: wipe control model on failure or keep old results?
|
# 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)
|
self.cleanup_func = CleanupFunc(self.cleanup_on_failure)
|
||||||
|
|
||||||
def push_data(self, data: tuple, mode: Optional[FilterMode], success: bool) -> None:
|
def push_data(self, data: tuple, mode: Optional[FilterMode], success: bool) -> None:
|
||||||
|
|
||||||
@@ -866,38 +877,31 @@ class Controller(GObject.GObject):
|
|||||||
self.new_maps = sorted(u_maps)
|
self.new_maps = sorted(u_maps)
|
||||||
|
|
||||||
treeview.set_loaded(True)
|
treeview.set_loaded(True)
|
||||||
GLib.idle_add(self.cleanup)
|
self.cleanup_func = CleanupFunc(self.cleanup)
|
||||||
|
|
||||||
@call_on_thread(strings.dialog.working)
|
@call_on_thread(strings.dialog.working)
|
||||||
def highlight_stale(self) -> None:
|
def highlight_stale(self) -> None:
|
||||||
self.colorize_mods()
|
model = self.get_mod_store()
|
||||||
|
stale = find_stale_mods(self.prefs.paths.config)
|
||||||
|
for mod in model:
|
||||||
|
it = mod.iter
|
||||||
|
path = model.get_path(it)
|
||||||
|
# TODO: consider storing in ListStore as int
|
||||||
|
# FIXME: deep copy existing model and set outside of thread
|
||||||
|
if int(mod[2]) in stale:
|
||||||
|
model[path][4] = HEX_RED
|
||||||
|
self.cleanup_func = CleanupFunc(lambda: self.emitter.emit("mods_highlighted"))
|
||||||
|
|
||||||
def get_callback(self) -> Callable | None:
|
def get_cleanup_func(self) -> CleanupFunc:
|
||||||
return self.callback["func"]
|
return self.cleanup_func
|
||||||
|
|
||||||
def get_callback_args(self) -> Any:
|
def _destroy_on_idle(self) -> None:
|
||||||
return self.callback["args"]
|
|
||||||
|
|
||||||
def set_callback(self, callback: Callable | None, *args) -> None:
|
|
||||||
"""
|
|
||||||
Lets calling widgets register a callback function
|
|
||||||
when spawning a threaded process
|
|
||||||
"""
|
|
||||||
self.callback = {"func": callback, "args": args}
|
|
||||||
|
|
||||||
def destroy_on_idle(self) -> None:
|
|
||||||
"""
|
|
||||||
TODO: chiefly responsible for removing spinner dialog
|
|
||||||
"""
|
|
||||||
self.wait_dialog.destroy()
|
self.wait_dialog.destroy()
|
||||||
func = self.get_callback()
|
func = self.get_cleanup_func()
|
||||||
self.mediator.window.set_sensitive(True)
|
|
||||||
# TODO: spawn error dialog if API crawl failed
|
|
||||||
# most likely going to drop callback method
|
|
||||||
if func is not None:
|
if func is not None:
|
||||||
args = self.get_callback_args()
|
func.call()
|
||||||
GLib.idle_add(func, *args)
|
self.cleanup_func = None
|
||||||
self.set_callback(None, None)
|
self.mediator.window.set_sensitive(True)
|
||||||
|
|
||||||
def dump_diagnostics(self) -> None:
|
def dump_diagnostics(self) -> None:
|
||||||
picker = FilePicker(self.mediator.window)
|
picker = FilePicker(self.mediator.window)
|
||||||
@@ -909,7 +913,8 @@ class Controller(GObject.GObject):
|
|||||||
dialog = ExceptionDialog(self, str(e))
|
dialog = ExceptionDialog(self, str(e))
|
||||||
dialog.run()
|
dialog.run()
|
||||||
|
|
||||||
def test_api_response(self, text: str, key: Preferences) -> None:
|
@call_on_thread(strings.dialog.working)
|
||||||
|
def update_api_key(self, text: str, key: Preferences) -> None:
|
||||||
if key is Preferences.STEAM:
|
if key is Preferences.STEAM:
|
||||||
res = test_steam_api(text)
|
res = test_steam_api(text)
|
||||||
else:
|
else:
|
||||||
@@ -917,17 +922,9 @@ class Controller(GObject.GObject):
|
|||||||
|
|
||||||
if res is True:
|
if res is True:
|
||||||
self.update_config(key, text)
|
self.update_config(key, text)
|
||||||
self.set_callback(None, None)
|
|
||||||
self.destroy_on_idle()
|
|
||||||
else:
|
else:
|
||||||
self.destroy_on_idle()
|
# FIXME: dialog spawning in thread
|
||||||
dialog = ExceptionDialog(self, strings.api_error)
|
self.cleanup_func = CleanupFunc(self.emitter.emit("api_change_failed"))
|
||||||
dialog.run()
|
|
||||||
|
|
||||||
@call_on_thread(strings.dialog.working)
|
|
||||||
# FIXME: entire process is behind thread, including destroy_on_idle()
|
|
||||||
def update_api_key(self, text: str, key: Preferences) -> None:
|
|
||||||
self.test_api_response(text, key)
|
|
||||||
|
|
||||||
def set_resolution(self, window: "OuterWindow") -> None:
|
def set_resolution(self, window: "OuterWindow") -> None:
|
||||||
if self.prefs.is_game_mode:
|
if self.prefs.is_game_mode:
|
||||||
@@ -985,14 +982,12 @@ class Controller(GObject.GObject):
|
|||||||
self.push_data("", mode, success=True)
|
self.push_data("", mode, success=True)
|
||||||
|
|
||||||
# FIXME: optional label/map/keyword parameter
|
# FIXME: optional label/map/keyword parameter
|
||||||
# FIXME: drop set_callback
|
# TODO: consolidate with method above
|
||||||
def refilter_model(self, mode: FilterMode, label: Optional[str] = None) -> None:
|
def refilter_model(self, mode: FilterMode, label: Optional[str] = None) -> None:
|
||||||
tv = self.get_active_treeview()
|
tv = self.get_active_treeview()
|
||||||
filter_man = tv.get_filter_man()
|
filter_man = tv.get_filter_man()
|
||||||
if filter_man.get_control() is None:
|
if filter_man.get_control() is None:
|
||||||
return
|
return
|
||||||
# TODO: deprecated in this context?
|
|
||||||
self.set_callback(None, None)
|
|
||||||
self.filter_threaded(mode, label)
|
self.filter_threaded(mode, label)
|
||||||
|
|
||||||
def populate_model(self) -> None:
|
def populate_model(self) -> None:
|
||||||
@@ -1001,18 +996,15 @@ class Controller(GObject.GObject):
|
|||||||
self.emitter.emit("servers_loaded", treeview.get_enum())
|
self.emitter.emit("servers_loaded", treeview.get_enum())
|
||||||
return
|
return
|
||||||
|
|
||||||
# TODO: maybe set tree to none afterwards (swap models)
|
|
||||||
# treeview.set_model(None)
|
|
||||||
func = treeview.get_query_func()
|
func = treeview.get_query_func()
|
||||||
if func is None:
|
if func is None:
|
||||||
self.emitter.emit("servers_loaded", treeview.get_enum())
|
self.emitter.emit("servers_loaded", treeview.get_enum())
|
||||||
treeview.set_model(None)
|
treeview.set_model(None)
|
||||||
return
|
return
|
||||||
# TODO:
|
# TODO: clear ephemeral model if necessary
|
||||||
# manager = treeview.get_filter_man()
|
# manager = treeview.get_filter_man()
|
||||||
# manager.clear_model()
|
# manager.clear_model()
|
||||||
self.first_iteration = True
|
self.first_iteration = True
|
||||||
self.set_callback(None, None)
|
|
||||||
self.run_query_func(func)
|
self.run_query_func(func)
|
||||||
|
|
||||||
def get_favorite(self) -> tuple[str, str] | tuple[None, None]:
|
def get_favorite(self) -> tuple[str, str] | tuple[None, None]:
|
||||||
@@ -1034,9 +1026,6 @@ class Controller(GObject.GObject):
|
|||||||
def get_modlist_store(self) -> Gtk.ListStore:
|
def get_modlist_store(self) -> Gtk.ListStore:
|
||||||
return self.model_man.get_modlist_store()
|
return self.model_man.get_modlist_store()
|
||||||
|
|
||||||
def get_mod_store(self) -> Gtk.ListStore:
|
|
||||||
return self.model_man.get_mod_store()
|
|
||||||
|
|
||||||
def get_log_store(self) -> Gtk.ListStore:
|
def get_log_store(self) -> Gtk.ListStore:
|
||||||
return self.model_man.get_log_store()
|
return self.model_man.get_log_store()
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ class ModelManager:
|
|||||||
|
|
||||||
self.map_store = ListStore(str)
|
self.map_store = ListStore(str)
|
||||||
self.help_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.log_store = self.new_model_from_class(LogCols)
|
||||||
|
# FIXME: needs to be generated on demand
|
||||||
self.modlist_store = self.new_model_from_class(ServerModCols)
|
self.modlist_store = self.new_model_from_class(ServerModCols)
|
||||||
|
|
||||||
for row in HELP_MENU_ROWS:
|
for row in HELP_MENU_ROWS:
|
||||||
@@ -65,8 +65,8 @@ class ModelManager:
|
|||||||
def get_help_store(self) -> ListStore:
|
def get_help_store(self) -> ListStore:
|
||||||
return self.help_store
|
return self.help_store
|
||||||
|
|
||||||
def get_mod_store(self) -> ListStore:
|
def new_mod_store(self) -> ListStore:
|
||||||
return self.mod_store
|
return self.new_model_from_class(ModCols)
|
||||||
|
|
||||||
def get_log_store(self) -> ListStore:
|
def get_log_store(self) -> ListStore:
|
||||||
return self.log_store
|
return self.log_store
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
|||||||
|
|
||||||
class EnumeratedModButton(Gtk.Button):
|
class EnumeratedModButton(Gtk.Button):
|
||||||
def __init__(self, enum: ModButton) -> None:
|
def __init__(self, enum: ModButton) -> None:
|
||||||
super().__init__(margin_start=10, margin_end=10)
|
super().__init__(margin_start=10, margin_end=10, focus_on_click=False)
|
||||||
|
|
||||||
self.enum = enum
|
self.enum = enum
|
||||||
self.set_label(enum.dict["label"])
|
self.set_label(enum.dict["label"])
|
||||||
@@ -30,6 +30,7 @@ class ModSelectionPanel(Gtk.Box):
|
|||||||
self.controller = controller
|
self.controller = controller
|
||||||
emitter = controller.get_emitter()
|
emitter = controller.get_emitter()
|
||||||
emitter.connect("mod_page_toggled", self._on_mod_page_toggled)
|
emitter.connect("mod_page_toggled", self._on_mod_page_toggled)
|
||||||
|
emitter.connect("mods_highlighted", self._on_mods_highlighted)
|
||||||
|
|
||||||
header = BoldLabel(mod_panel.header)
|
header = BoldLabel(mod_panel.header)
|
||||||
|
|
||||||
@@ -60,14 +61,17 @@ class ModSelectionPanel(Gtk.Box):
|
|||||||
for el in header, self.main_panel, self.stale_panel:
|
for el in header, self.main_panel, self.stale_panel:
|
||||||
self.pack_start(el, NO_EXPAND, FILL, NO_PADDING)
|
self.pack_start(el, NO_EXPAND, FILL, NO_PADDING)
|
||||||
|
|
||||||
|
def _on_mods_highlighted(self, emitter: "Emitter") -> None:
|
||||||
|
self.swap_sensitive(True)
|
||||||
|
|
||||||
def _on_mod_page_toggled(self, emitter: "Emitter", state: bool) -> None:
|
def _on_mod_page_toggled(self, emitter: "Emitter", state: bool) -> None:
|
||||||
self.set_visible(state)
|
self.set_visible(state)
|
||||||
|
|
||||||
def after_colorize(self) -> None:
|
#def after_colorize(self) -> None:
|
||||||
# TODO: split into signal that touches two widgets,
|
# # TODO: split into signal that touches two widgets,
|
||||||
# modtreeview and this widget
|
# # modtreeview and this widget
|
||||||
self.controller.unselect_all_mods()
|
# #self.controller.unselect_all_mods()
|
||||||
self.swap_sensitive(True)
|
# self.swap_sensitive(True)
|
||||||
|
|
||||||
def swap_sensitive(self, state: bool) -> None:
|
def swap_sensitive(self, state: bool) -> None:
|
||||||
for child in self.stale_panel.get_children():
|
for child in self.stale_panel.get_children():
|
||||||
@@ -79,15 +83,12 @@ class ModSelectionPanel(Gtk.Box):
|
|||||||
def _on_button_clicked(self, button: EnumeratedModButton) -> None:
|
def _on_button_clicked(self, button: EnumeratedModButton) -> None:
|
||||||
match button.enum:
|
match button.enum:
|
||||||
case ModButton.SELECT_ALL:
|
case ModButton.SELECT_ALL:
|
||||||
# TODO: signals
|
|
||||||
self.controller.toggle_mod_selection(True)
|
self.controller.toggle_mod_selection(True)
|
||||||
case ModButton.UNSELECT_ALL:
|
case ModButton.UNSELECT_ALL:
|
||||||
self.controller.toggle_mod_selection(False)
|
self.controller.toggle_mod_selection(False)
|
||||||
case ModButton.DELETE_SELECTED:
|
case ModButton.DELETE_SELECTED:
|
||||||
self.controller.delete_multiple_mods()
|
self.controller.delete_multiple_mods()
|
||||||
|
|
||||||
case ModButton.HIGHLIGHT_STALE:
|
case ModButton.HIGHLIGHT_STALE:
|
||||||
self.controller.set_callback(self.after_colorize)
|
|
||||||
self.controller.highlight_stale()
|
self.controller.highlight_stale()
|
||||||
case ModButton.UNHIGHLIGHT_STALE:
|
case ModButton.UNHIGHLIGHT_STALE:
|
||||||
self.controller.uncolorize_mods()
|
self.controller.uncolorize_mods()
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ class RightPanel(Gtk.Box):
|
|||||||
state = self.controller.has_server_model()
|
state = self.controller.has_server_model()
|
||||||
for widget in (self.refresh_button, self.filters_vbox):
|
for widget in (self.refresh_button, self.filters_vbox):
|
||||||
widget.set_sensitive(state)
|
widget.set_sensitive(state)
|
||||||
|
# FIXME: may wish to reload these in place to show new data
|
||||||
if context in (ServerTab.RECENT, ServerTab.SAVED):
|
if context in (ServerTab.RECENT, ServerTab.SAVED):
|
||||||
self.refresh_button.set_sensitive(False)
|
self.refresh_button.set_sensitive(False)
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,11 @@ class Statusbar(Gtk.Grid):
|
|||||||
self.emitter.connect("distcalc_started", self._on_distcalc_started)
|
self.emitter.connect("distcalc_started", self._on_distcalc_started)
|
||||||
self.emitter.connect("distcalc_ended", self._on_distcalc_ended)
|
self.emitter.connect("distcalc_ended", self._on_distcalc_ended)
|
||||||
self.emitter.connect("servers_loaded", self._on_servers_loaded)
|
self.emitter.connect("servers_loaded", self._on_servers_loaded)
|
||||||
|
self.emitter.connect("mod_page_loaded", self._on_mod_page_loaded)
|
||||||
|
|
||||||
|
def _on_mod_page_loaded(self, emitter: "Emitter") -> None:
|
||||||
|
msg = self.controller.format_mod_statusbar()
|
||||||
|
self.set_by_context(NotebookPage.MODS, msg)
|
||||||
|
|
||||||
def _on_notebook_page_changed(
|
def _on_notebook_page_changed(
|
||||||
self, notebook: "Notebook", child: Gtk.Widget, index: int
|
self, notebook: "Notebook", child: Gtk.Widget, index: int
|
||||||
@@ -75,12 +80,15 @@ class Statusbar(Gtk.Grid):
|
|||||||
|
|
||||||
match enum:
|
match enum:
|
||||||
case NotebookPage.MODS:
|
case NotebookPage.MODS:
|
||||||
bar = self.controller.format_mod_statusbar()
|
return
|
||||||
|
# FIXME: format on callback after mods load
|
||||||
|
#bar = self.controller.format_mod_statusbar()
|
||||||
case NotebookPage.HELP:
|
case NotebookPage.HELP:
|
||||||
bar = self.controller.get_help_row()
|
bar = self.controller.get_help_row()
|
||||||
case NotebookPage.SERVERS:
|
case NotebookPage.SERVERS:
|
||||||
context = self.controller.get_active_context()
|
context = self.controller.get_active_context()
|
||||||
self.emitter.emit("servers_loaded", context)
|
# FIXME: may be superfluous
|
||||||
|
#self.emitter.emit("servers_loaded", context)
|
||||||
return
|
return
|
||||||
case NotebookPage.KEYS:
|
case NotebookPage.KEYS:
|
||||||
bar = question_to_return
|
bar = question_to_return
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ from gi.repository import Gtk, Gdk # noqa
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
from dzgui.controllers.emitter import Emitter
|
||||||
|
|
||||||
|
|
||||||
class Options(Gtk.Box):
|
class Options(Gtk.Box):
|
||||||
@@ -48,6 +49,8 @@ class Options(Gtk.Box):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
emitter = controller.get_emitter()
|
||||||
|
emitter.connect("api_change_failed", self._on_api_change_failed)
|
||||||
|
|
||||||
self.DEFAULT_WIDTH = 1
|
self.DEFAULT_WIDTH = 1
|
||||||
self.DEFAULT_HEIGHT = 1
|
self.DEFAULT_HEIGHT = 1
|
||||||
@@ -270,6 +273,9 @@ class Options(Gtk.Box):
|
|||||||
self, button: Gtk.Button, entry: Gtk.Entry, enum: Preferences
|
self, button: Gtk.Button, entry: Gtk.Entry, enum: Preferences
|
||||||
) -> None:
|
) -> None:
|
||||||
old_text = self.controller.query_config(enum)
|
old_text = self.controller.query_config(enum)
|
||||||
|
self.old_text = old_text
|
||||||
|
self.old_entry = entry
|
||||||
|
|
||||||
button.set_sensitive(False)
|
button.set_sensitive(False)
|
||||||
match enum:
|
match enum:
|
||||||
case Preferences.NAME:
|
case Preferences.NAME:
|
||||||
@@ -277,9 +283,14 @@ class Options(Gtk.Box):
|
|||||||
self.controller.update_config(enum, value)
|
self.controller.update_config(enum, value)
|
||||||
case Preferences.BM | Preferences.STEAM:
|
case Preferences.BM | Preferences.STEAM:
|
||||||
text = "".join(entry.get_text().split())
|
text = "".join(entry.get_text().split())
|
||||||
self.controller.set_callback(self.restore_api_text, old_text, entry)
|
# self.controller.set_callback(self.restore_api_text, old_text, entry)
|
||||||
self.controller.update_api_key(text, enum)
|
self.controller.update_api_key(text, enum)
|
||||||
|
|
||||||
|
def _on_api_change_failed(self, emitter: "Emitter") -> None:
|
||||||
|
self.old_entry.set_text(self.old_text)
|
||||||
|
dialog = ExceptionDialog(self.controller, strings.api_error)
|
||||||
|
dialog.run()
|
||||||
|
|
||||||
def restore_api_text(self, text: str, entry: Gtk.Entry) -> None:
|
def restore_api_text(self, text: str, entry: Gtk.Entry) -> None:
|
||||||
entry.set_text(text)
|
entry.set_text(text)
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from gi.repository import Gtk, GLib, Gdk, GObject, Pango # noqa
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.controllers.mc import Controller
|
from dzgui.controllers.mc import Controller
|
||||||
|
from dzgui.controllers.emitter import Emitter
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -23,12 +24,14 @@ class ModTreeView(ModsMixin, ContextMixin, TreeView):
|
|||||||
def __init__(self, controller: "Controller") -> None:
|
def __init__(self, controller: "Controller") -> None:
|
||||||
super().__init__(controller, menu=ContextMenuGroup.MOD)
|
super().__init__(controller, menu=ContextMenuGroup.MOD)
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
emitter = self.controller.get_emitter()
|
||||||
|
emitter.connect("mod_page_loaded", self._on_mod_page_loaded)
|
||||||
|
emitter.connect("mods_highlighted", self._on_mods_highlighted)
|
||||||
|
|
||||||
self.set_fixed_height_mode(True)
|
self.set_fixed_height_mode(True)
|
||||||
self.set_headers_visible(True)
|
self.set_headers_visible(True)
|
||||||
|
|
||||||
mod_store = self.controller.get_mod_store()
|
self.set_model(None)
|
||||||
self.set_model(mod_store)
|
|
||||||
|
|
||||||
for i, column_title in enumerate(strings.mod_cols):
|
for i, column_title in enumerate(strings.mod_cols):
|
||||||
renderer = Gtk.CellRendererText()
|
renderer = Gtk.CellRendererText()
|
||||||
@@ -52,26 +55,27 @@ class ModTreeView(ModsMixin, ContextMixin, TreeView):
|
|||||||
self.connect("generic_treesel_changed", self._parent_selection_changed)
|
self.connect("generic_treesel_changed", self._parent_selection_changed)
|
||||||
self.connect("button-press-event", self.present_menu)
|
self.connect("button-press-event", self.present_menu)
|
||||||
self.connect("key-press-event", self.present_menu)
|
self.connect("key-press-event", self.present_menu)
|
||||||
self.connect("map", self._on_map)
|
|
||||||
|
|
||||||
def _on_map(self, tree: Self) -> None:
|
def _on_mods_highlighted(self, emitter: "Emitter") -> None:
|
||||||
# FIXME: placeholder logic
|
self.get_selection().unselect_all()
|
||||||
# identify root cause of row unfocus on init
|
|
||||||
|
# TODO: test loading with no mods
|
||||||
|
def _on_mod_page_loaded(self, emitter: "Emitter") -> None:
|
||||||
self.set_cursor(0)
|
self.set_cursor(0)
|
||||||
|
|
||||||
# def _on_mods_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None:
|
# def _on_mods_keypress(self, widget: Gtk.Widget, event: Gdk.EventKey) -> None:
|
||||||
# # TODO: multiselect
|
# # TODO: multiselect
|
||||||
# # if event.keyval is Gdk.KEY_space:
|
# # if event.keyval is Gdk.KEY_space:
|
||||||
# # it = self.get_focused_row_iter()
|
# # it = self.get_focused_row_iter()
|
||||||
# # self.get_selection().select_iter(it)
|
# # self.get_selection().select_iter(it)
|
||||||
# # path = self.get_focused_row_path()
|
# # path = self.get_focused_row_path()
|
||||||
# # self.set_cursor(path)
|
# # self.set_cursor(path)
|
||||||
# # return False
|
# # return False
|
||||||
# self.present_menu(widget, event)
|
# self.present_menu(widget, event)
|
||||||
|
|
||||||
# def _on_mods_button_press(self, widget: Gtk.Widget, event: Gdk.EventButton) -> None:
|
# def _on_mods_button_press(self, widget: Gtk.Widget, event: Gdk.EventButton) -> None:
|
||||||
# if event.button == 3:
|
# if event.button == 3:
|
||||||
# self.present_menu(widget, event)
|
# self.present_menu(widget, event)
|
||||||
|
|
||||||
def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection):
|
def _parent_selection_changed(self, base_class: TreeView, sel: Gtk.TreeSelection):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in new issue
Block a user