Add Footer, Remove Mods, and Add Main Mod
All checks were successful
Build and Upload Release (Windows EXE) / Build Windows EXE (release) Successful in 3m30s
All checks were successful
Build and Upload Release (Windows EXE) / Build Windows EXE (release) Successful in 3m30s
This commit is contained in:
@@ -3,6 +3,7 @@ import os
|
||||
import shutil
|
||||
import sys
|
||||
import threading
|
||||
import webbrowser
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Tuple
|
||||
@@ -209,9 +210,23 @@ class SeaLoaderApp(tk.Tk):
|
||||
bottom.pack(fill=tk.X, padx=12, pady=(0, 12))
|
||||
self.enable_btn = ttk.Button(bottom, text="Enable Matching Mods", command=self._on_enable)
|
||||
self.enable_btn.pack(side=tk.LEFT)
|
||||
self.disable_all_btn = ttk.Button(bottom, text="Disable All Mods", command=self._on_disable_all)
|
||||
self.disable_all_btn.pack(side=tk.LEFT, padx=(8, 0))
|
||||
self.help_btn = ttk.Button(bottom, text="Help", command=self._on_help)
|
||||
self.help_btn.pack(side=tk.RIGHT)
|
||||
|
||||
# Footer attribution
|
||||
footer = ttk.Frame(self, style="TFrame")
|
||||
footer.pack(fill=tk.X, padx=12, pady=(0, 10))
|
||||
self._footer_icon = self._load_png_icon("hrsys.png", max_px=18)
|
||||
if self._footer_icon is not None:
|
||||
icon_lbl = ttk.Label(footer, image=self._footer_icon, style="TLabel")
|
||||
icon_lbl.pack(side=tk.LEFT)
|
||||
icon_lbl.bind("<Button-1>", lambda e: self._open_link("https://hudsonriggs.systems"))
|
||||
link_lbl = ttk.Label(footer, text="Created by HudsonRiggs.Systems", style="TLabel", foreground=MUTED)
|
||||
link_lbl.pack(side=tk.LEFT, padx=(6, 0))
|
||||
link_lbl.bind("<Button-1>", lambda e: self._open_link("https://hudsonriggs.systems"))
|
||||
|
||||
def _create_tree(self, parent, columns: List[str], ratios: List[float]):
|
||||
tree = ttk.Treeview(parent, columns=columns, show="headings", height=12)
|
||||
for col in columns:
|
||||
@@ -219,12 +234,10 @@ class SeaLoaderApp(tk.Tk):
|
||||
tree.column(col, width=50, anchor=tk.W, stretch=True)
|
||||
|
||||
vsb = ttk.Scrollbar(parent, orient="vertical", command=tree.yview)
|
||||
hsb = ttk.Scrollbar(parent, orient="horizontal", command=tree.xview)
|
||||
tree.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
|
||||
tree.configure(yscrollcommand=vsb.set)
|
||||
|
||||
tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
|
||||
vsb.pack(side=tk.LEFT, fill=tk.Y)
|
||||
hsb.pack(side=tk.BOTTOM, fill=tk.X)
|
||||
|
||||
self._bind_auto_columns(parent, tree, ratios)
|
||||
return tree
|
||||
@@ -372,6 +385,59 @@ class SeaLoaderApp(tk.Tk):
|
||||
pass
|
||||
return Path(__file__).resolve().parent / name
|
||||
|
||||
def _open_link(self, url: str) -> None:
|
||||
try:
|
||||
webbrowser.open(url)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _load_png_icon(self, filename: str, max_px: int = 18):
|
||||
try:
|
||||
png_path = self._resource_path(filename)
|
||||
if not png_path.exists():
|
||||
return None
|
||||
img = tk.PhotoImage(file=str(png_path))
|
||||
# Downscale if needed using integer subsample
|
||||
sx = max(img.width() // max_px, 1)
|
||||
sy = max(img.height() // max_px, 1)
|
||||
scale = max(sx, sy)
|
||||
if scale > 1:
|
||||
img = img.subsample(scale, scale)
|
||||
return img
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _on_disable_all(self) -> None:
|
||||
confirm = messagebox.askyesno("SeaLoader", "Disable all mods in usersettings.ini?")
|
||||
if not confirm:
|
||||
return
|
||||
try:
|
||||
self._disable_all_mods()
|
||||
except Exception as exc:
|
||||
messagebox.showerror("SeaLoader", f"Failed to disable all mods: {exc}")
|
||||
return
|
||||
self._load_installed_mods()
|
||||
messagebox.showinfo("SeaLoader", "All mods disabled.")
|
||||
|
||||
def _disable_all_mods(self) -> None:
|
||||
parser = configparser.ConfigParser()
|
||||
parser.optionxform = str
|
||||
parser.read(self.ini_path, encoding="utf-8")
|
||||
section = "LoadOrder"
|
||||
if section not in parser:
|
||||
raise ValueError("[LoadOrder] section not found in usersettings.ini")
|
||||
shutil.copyfile(self.ini_path, self.ini_path + ".bak")
|
||||
for key, value in list(parser[section].items()):
|
||||
if not key.lower().startswith("mod"):
|
||||
continue
|
||||
parts = value.split(",")
|
||||
if not parts:
|
||||
continue
|
||||
left_token = parts[0].strip()
|
||||
parser[section][key] = f"{left_token},False"
|
||||
with open(self.ini_path, "w", encoding="utf-8") as f:
|
||||
parser.write(f)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ini_path = DEFAULT_INI_PATH
|
||||
|
||||
Reference in New Issue
Block a user