mirror of
https://github.com/aclist/dztui.git
synced 2026-08-30 03:37:00 +02:00
Compare commits
No commits in common. "ab439144ea0aea2c37ffdf3e34c245ae30a4906a" and "24668870148df81e95a0a073a59382cc7ea8a2c1" have entirely different histories.
ab439144ea
...
2466887014
@ -1,13 +1,13 @@
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
from gi.repository.Gtk import ListStore # noqa E402
|
from gi.repository.Gtk import ListStore # noqa E402
|
||||||
from gi.repository import Gdk, GObject # noqa E402
|
from gi.repository import Gdk, GObject # noqa E402
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from dzgui.const.enum import NotebookPage, ServerTab
|
from dzgui.const.enum import NotebookPage, ServerTab
|
||||||
from dzgui.model.model_factory import FastInsertListStore
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: if servers fail to load, may leave dangling widgets waiting for a signal
|
# TODO: if servers fail to load, may leave dangling widgets waiting for a signal
|
||||||
@ -154,7 +154,3 @@ class Emitter(GObject.GObject):
|
|||||||
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
|
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=())
|
||||||
def lan_page_initialized(self) -> None:
|
def lan_page_initialized(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(object, str))
|
|
||||||
def custom_mods_loaded(self, store: "FastInsertListStore", folder: str) -> None:
|
|
||||||
pass
|
|
||||||
|
|||||||
@ -6,7 +6,6 @@ from pathlib import Path
|
|||||||
from dzgui.config.query import lookup
|
from dzgui.config.query import lookup
|
||||||
from dzgui.const.constants import APPID_DAYZ, APP_NAME, LIBRARYFOLDERS_PATH
|
from dzgui.const.constants import APPID_DAYZ, APP_NAME, LIBRARYFOLDERS_PATH
|
||||||
from dzgui.const.enum import Preferences
|
from dzgui.const.enum import Preferences
|
||||||
from dzgui.strings.errors import dayz_not_found
|
|
||||||
from dzgui.views.dialogs.early_alert import EarlyAlertDialog
|
from dzgui.views.dialogs.early_alert import EarlyAlertDialog
|
||||||
|
|
||||||
import dzgui.api.pefile as PeFile
|
import dzgui.api.pefile as PeFile
|
||||||
@ -20,5 +19,5 @@ def is_dayz_installed(config: Path) -> None:
|
|||||||
PeFile.get_app_path(Path(path) / LIBRARYFOLDERS_PATH, APPID_DAYZ)
|
PeFile.get_app_path(Path(path) / LIBRARYFOLDERS_PATH, APPID_DAYZ)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.critical(e)
|
logger.critical(e)
|
||||||
EarlyAlertDialog(dayz_not_found)
|
EarlyAlertDialog(str(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|||||||
@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
|
|||||||
from dzgui.api.mods import get_custom_mods
|
from dzgui.api.mods import get_custom_mods
|
||||||
from dzgui.api.steam import launch_offline
|
from dzgui.api.steam import launch_offline
|
||||||
from dzgui.const.enum import Preferences
|
from dzgui.const.enum import Preferences
|
||||||
from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager
|
from dzgui.managers.threading import call_on_thread, ThreadingManager
|
||||||
from dzgui.model.model_factory import FastInsertListStore, ModelFactory
|
from dzgui.model.model_factory import FastInsertListStore, ModelFactory
|
||||||
from dzgui.strings import dialogs
|
from dzgui.strings import dialogs
|
||||||
from dzgui.util.symlink import clone_symlinks
|
from dzgui.util.symlink import clone_symlinks
|
||||||
@ -21,7 +21,6 @@ class OfflineManager:
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.emitter = controller.get_emitter()
|
|
||||||
self.thread_man = ThreadingManager(controller)
|
self.thread_man = ThreadingManager(controller)
|
||||||
|
|
||||||
self.appid: int
|
self.appid: int
|
||||||
@ -31,20 +30,12 @@ class OfflineManager:
|
|||||||
|
|
||||||
# TODO: strings
|
# TODO: strings
|
||||||
@call_on_thread("parsing")
|
@call_on_thread("parsing")
|
||||||
def parse_custom_mods(self, local_mods: list[str], folder: str) -> "FastInsertListStore":
|
def parse_custom_mods(self, folder: str) -> "FastInsertListStore":
|
||||||
mods = get_custom_mods(Path(folder))
|
mods = get_custom_mods(Path(folder))
|
||||||
store = ModelFactory().make_mod_store()
|
store = ModelFactory().make_mod_store()
|
||||||
store.extend(mods)
|
store.extend(mods)
|
||||||
|
# TODO: manipulate tree columns to only show name and size
|
||||||
has_duplicates = False
|
return store
|
||||||
for row in store:
|
|
||||||
if row[1] in local_mods:
|
|
||||||
row[-1]=True
|
|
||||||
has_duplicates = True
|
|
||||||
|
|
||||||
func = StoredFunc(self.emitter.emit, "custom_mods_loaded", store, folder, has_duplicates)
|
|
||||||
self.thread_man.set_cleanup_func(func)
|
|
||||||
# TODO: return store from cleanup function
|
|
||||||
|
|
||||||
def setup(
|
def setup(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@ -3,4 +3,3 @@ api_validation_error = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
api_popover = "API key validation failed."
|
api_popover = "API key validation failed."
|
||||||
dayz_not_found = "Could not find DayZ and/or Steam: are they installed?"
|
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
selectable_tree = "Ctrl-click to select multiple; Shift-click to select a range."
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
|
|
||||||
from dzgui.util.localize import number
|
from dzgui.util.localize import number
|
||||||
from dzgui.strings.generic import selectable_tree
|
|
||||||
from dzgui.util.strings import no_mods, no_servers, workshop
|
from dzgui.util.strings import no_mods, no_servers, workshop
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
@ -47,7 +46,8 @@ def format_mods(size: int, mods: int) -> str:
|
|||||||
return no_mods
|
return no_mods
|
||||||
l_size = number(size)
|
l_size = number(size)
|
||||||
plural = pluralize("mods", mods)
|
plural = pluralize("mods", mods)
|
||||||
suffix = selectable_tree
|
# TODO: strings
|
||||||
|
suffix = "Ctrl-click to select multiple; Shift-click to select a range."
|
||||||
return f"Found {mods:n} {plural} taking up {l_size} MiB. {suffix}"
|
return f"Found {mods:n} {plural} taking up {l_size} MiB. {suffix}"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -48,8 +48,10 @@ class LargeIcon(Gtk.Image):
|
|||||||
|
|
||||||
|
|
||||||
class IconButton(Gtk.Button):
|
class IconButton(Gtk.Button):
|
||||||
def __init__(self, icon: str, margin: int = 0) -> None:
|
def __init__(
|
||||||
super().__init__()
|
self, icon: str, margin: int = 0, halign: Gtk.Align = Gtk.Align.START
|
||||||
|
) -> None:
|
||||||
|
super().__init__(halign=halign)
|
||||||
self.icon = Icon(icon, l_margin=margin)
|
self.icon = Icon(icon, l_margin=margin)
|
||||||
self.set_image(self.icon)
|
self.set_image(self.icon)
|
||||||
self.set_image_position(Gtk.PositionType.RIGHT)
|
self.set_image_position(Gtk.PositionType.RIGHT)
|
||||||
@ -57,8 +59,10 @@ class IconButton(Gtk.Button):
|
|||||||
|
|
||||||
|
|
||||||
class IconTextButton(IconButton):
|
class IconTextButton(IconButton):
|
||||||
def __init__(self, icon: str, label: str) -> None:
|
def __init__(
|
||||||
super().__init__(icon, margin=5)
|
self, icon: str, label: str, halign: Gtk.Align = Gtk.Align.START
|
||||||
|
) -> None:
|
||||||
|
super().__init__(icon, margin=5, halign=halign)
|
||||||
self.set_label(label)
|
self.set_label(label)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -12,14 +12,13 @@ from dzgui.const.constants import (
|
|||||||
)
|
)
|
||||||
from dzgui.const.enum import NotebookPage, Preferences
|
from dzgui.const.enum import NotebookPage, Preferences
|
||||||
from dzgui.managers.offline import OfflineManager
|
from dzgui.managers.offline import OfflineManager
|
||||||
from dzgui.strings import generic, offline
|
from dzgui.strings import offline
|
||||||
from dzgui.views.components.buttons import IconTextButton
|
from dzgui.views.components.buttons import IconTextButton
|
||||||
from dzgui.views.components.frame import HeadingFrame
|
from dzgui.views.components.frame import HeadingFrame
|
||||||
from dzgui.views.components.scrollable import NoOverlayScrolledWindow
|
from dzgui.views.components.scrollable import NoOverlayScrolledWindow
|
||||||
from dzgui.views.trees.tree_mods import OfflineModTreeView
|
from dzgui.views.trees.tree_mods import OfflineModTreeView
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
|
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
@ -65,9 +64,7 @@ class FolderHBox(HBox):
|
|||||||
|
|
||||||
# TODO: alternate class for left-aligned icons
|
# TODO: alternate class for left-aligned icons
|
||||||
self.button = IconTextButton(FOLDER, btn_label)
|
self.button = IconTextButton(FOLDER, btn_label)
|
||||||
self.button.set_halign(Gtk.Align.START)
|
|
||||||
self.button.set_image_position(Gtk.PositionType.LEFT)
|
self.button.set_image_position(Gtk.PositionType.LEFT)
|
||||||
|
|
||||||
self.label = Gtk.Label()
|
self.label = Gtk.Label()
|
||||||
self.extend([self.button, self.label])
|
self.extend([self.button, self.label])
|
||||||
|
|
||||||
@ -122,7 +119,8 @@ class ModFrame(HeadingFrame):
|
|||||||
def _on_selection_changed(self, sel: Gtk.TreeSelection) -> None:
|
def _on_selection_changed(self, sel: Gtk.TreeSelection) -> None:
|
||||||
model, rows = sel.get_selected_rows()
|
model, rows = sel.get_selected_rows()
|
||||||
if len(rows) == 0:
|
if len(rows) == 0:
|
||||||
status = generic.selectable_tree
|
# TODO recycle (util.format)
|
||||||
|
status = "Ctrl-click to select multiple; Shift-click to select a range."
|
||||||
else:
|
else:
|
||||||
status = f"Mods selected: {len(rows)}"
|
status = f"Mods selected: {len(rows)}"
|
||||||
self.status.set_label(status)
|
self.status.set_label(status)
|
||||||
@ -134,45 +132,26 @@ class ModFrame(HeadingFrame):
|
|||||||
|
|
||||||
|
|
||||||
class CustomModFrame(ModFrame):
|
class CustomModFrame(ModFrame):
|
||||||
def __init__(self, parent: Gtk.Widget, controller: "Controller", heading: str) -> None:
|
def __init__(self, controller: "Controller", heading: str) -> None:
|
||||||
super().__init__(controller, heading)
|
super().__init__(controller, heading)
|
||||||
|
|
||||||
self.parent = parent
|
|
||||||
|
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.emitter = controller.get_emitter()
|
|
||||||
|
|
||||||
# TODO: descriptive text here explaining how this area works
|
# TODO: descriptive text here explaining how this area works
|
||||||
self.custom_hbox = FolderHBox(offline.custom_button)
|
self.custom_hbox = FolderHBox(offline.custom_button)
|
||||||
self.custom_hbox.get_button().connect("clicked", self._on_custom_button_clicked)
|
self.custom_hbox.get_button().connect("clicked", self._on_custom_button_clicked)
|
||||||
|
|
||||||
self.pack(self.custom_hbox)
|
self.pack(self.custom_hbox)
|
||||||
|
|
||||||
self.emitter.connect("custom_mods_loaded", self._on_custom_mods_loaded)
|
|
||||||
|
|
||||||
|
|
||||||
def _on_custom_mods_loaded(self, store: "FastInsertListStore", folder: str, has_duplicates: bool) -> None:
|
|
||||||
if len(store) == 0:
|
|
||||||
# TODO: pop error dialog area
|
|
||||||
# block button access
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
self.custom_hbox.set_label(folder)
|
|
||||||
self.tree.set_model(store)
|
|
||||||
self.tree_vbox.show()
|
|
||||||
|
|
||||||
if has_duplicates:
|
|
||||||
# TODO: pop relevant error
|
|
||||||
# duplicates should block button access
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def _on_custom_button_clicked(self, button: Gtk.Button) -> None:
|
def _on_custom_button_clicked(self, button: Gtk.Button) -> None:
|
||||||
self.parent.parse_mods()
|
# TODO: recycle for mission folder
|
||||||
|
# TODO: propagate results back to parent
|
||||||
|
folder = self.controller.set_custom_folder()
|
||||||
|
if folder is not None:
|
||||||
|
self.custom_hbox.set_label(str(folder))
|
||||||
|
|
||||||
def get_mods(self) -> list[str]:
|
def get_mods(self) -> list[str]:
|
||||||
rows = self.tree.get_selection().get_selected_rows()
|
rows = self.tree.get_selection().get_selected_rows()
|
||||||
dirs = [str(col[1]) for col in rows]
|
dirs = [str(col[0]) for col in rows]
|
||||||
return dirs
|
return dirs
|
||||||
|
|
||||||
|
|
||||||
@ -273,14 +252,6 @@ class OfflineLoader(Gtk.Box):
|
|||||||
self.add(self.scrollable)
|
self.add(self.scrollable)
|
||||||
self.add(self.button_box)
|
self.add(self.button_box)
|
||||||
|
|
||||||
def parse_mods(self) -> None:
|
|
||||||
# TODO:
|
|
||||||
local_mods = self.local_frame.get_mods()
|
|
||||||
folder = self.controller.set_custom_folder()
|
|
||||||
if folder is not None:
|
|
||||||
# TODO:
|
|
||||||
self.offline_man.parse_custom_mods(local_mods, folder)
|
|
||||||
|
|
||||||
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None:
|
def _on_keypress(self, widget: Self, event: Gdk.EventKey) -> None:
|
||||||
if event.keyval == Gdk.KEY_Escape:
|
if event.keyval == Gdk.KEY_Escape:
|
||||||
self.back.emit("clicked")
|
self.back.emit("clicked")
|
||||||
@ -288,7 +259,6 @@ class OfflineLoader(Gtk.Box):
|
|||||||
def populate(self, store: "FastInsertListStore") -> None:
|
def populate(self, store: "FastInsertListStore") -> None:
|
||||||
self.local_frame.set_model(store)
|
self.local_frame.set_model(store)
|
||||||
# TODO: toggle if empty model, show warning label
|
# TODO: toggle if empty model, show warning label
|
||||||
# NOTE: there may be no local mods
|
|
||||||
# TODO: suppress trees if there are no mods
|
# TODO: suppress trees if there are no mods
|
||||||
self.custom_frame.collapse_tree()
|
self.custom_frame.collapse_tree()
|
||||||
|
|
||||||
@ -296,9 +266,6 @@ class OfflineLoader(Gtk.Box):
|
|||||||
self.controller.open_page(NotebookPage.MODS)
|
self.controller.open_page(NotebookPage.MODS)
|
||||||
|
|
||||||
def _on_ok_clicked(self, button: Gtk.Button) -> None:
|
def _on_ok_clicked(self, button: Gtk.Button) -> None:
|
||||||
# TODO; block button access if no mods are selected
|
|
||||||
# TODO: consider hooking up to emitter and changing button state whenever mods are selected
|
|
||||||
|
|
||||||
# appid = self.radio_frame.get_appid()
|
# appid = self.radio_frame.get_appid()
|
||||||
# mission = self.mission_frame.get_mission()
|
# mission = self.mission_frame.get_mission()
|
||||||
# local_mods = self.local_frame.get_mods()
|
# local_mods = self.local_frame.get_mods()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user