Add open output folder button

This commit is contained in:
Campbell 2026-01-05 15:16:03 -05:00
parent 5faab5bade
commit ed90dd529b
Signed by: NinjaCheetah
GPG Key ID: B547958AF96ED344
5 changed files with 153 additions and 6 deletions

View File

@ -39,7 +39,7 @@ from modules.download_batch import run_nus_download_batch
from modules.download_wii import run_nus_download_wii
from modules.download_dsi import run_nus_download_dsi
nusget_version = "1.4.3"
nusget_version = "1.5.0"
regions = {"World": ["41"], "USA/NTSC": ["45"], "Europe/PAL": ["50"], "Japan": ["4A"], "Korea": ["4B"], "China": ["43"],
"Australia/NZ": ["55"]}
@ -82,6 +82,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.ui.setupUi(self)
self.threadpool = QThreadPool()
self.ui.download_btn.clicked.connect(self.download_btn_pressed)
self.ui.open_output_btn.clicked.connect(self.open_output_dir)
self.ui.script_btn.clicked.connect(self.script_btn_pressed)
self.ui.custom_out_dir_btn.clicked.connect(self.choose_output_dir)
self.ui.pack_archive_checkbox.toggled.connect(
@ -191,6 +192,16 @@ class MainWindow(QMainWindow, Ui_MainWindow):
dsi_model = NUSGetTreeModel(dsi_database, root_name="DSi Titles")
self.tree_models = [wii_model, vwii_model, dsi_model]
self.trees = [self.ui.wii_title_tree, self.ui.vwii_title_tree, self.ui.dsi_title_tree]
# ---------
# UI Tweaks
# ---------
# Any misc UI tweaks that need to be done when the UI loads.
# Set the appropriate folder icon for the open output folder button depending on the theme.
if is_dark_theme(config_data):
icon = QIcon(os.path.join(os.path.dirname(__file__), "resources", "folder_white.svg"))
else:
icon = QIcon(os.path.join(os.path.dirname(__file__), "resources", "folder_black.svg"))
self.ui.open_output_btn.setIcon(icon)
# Build proxy models required for searching
self.proxy_models = [TIDFilterProxyModel(self.ui.wii_title_tree), TIDFilterProxyModel(self.ui.vwii_title_tree),
TIDFilterProxyModel(self.ui.dsi_title_tree)]
@ -613,6 +624,16 @@ class MainWindow(QMainWindow, Ui_MainWindow):
worker.signals.progress.connect(self.download_progress_update)
self.threadpool.start(worker)
def open_output_dir(self):
# Like all good things in life, this is a platform-dependent procedure. Did I say good? I meant annoying.
system = platform.system()
if system == "Windows":
subprocess.run(["explorer.exe", out_folder])
elif system == "Darwin":
subprocess.run(["open", out_folder])
else:
subprocess.run(["xdg-open", out_folder])
def choose_output_dir(self):
# Use this handy convenience method to prompt the user to select a directory. Then we just need to validate
# that the directory does indeed exist and is a directory, and we can save it as the output directory.

View File

@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'MainMenu.ui'
##
## Created by: Qt User Interface Compiler version 6.9.0
## Created by: Qt User Interface Compiler version 6.10.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@ -210,6 +210,13 @@ class Ui_MainWindow(object):
self.horizontalLayout.addWidget(self.download_btn)
self.open_output_btn = QPushButton(self.centralwidget)
self.open_output_btn.setObjectName(u"open_output_btn")
icon1 = QIcon(QIcon.fromTheme(QIcon.ThemeIcon.FolderOpen))
self.open_output_btn.setIcon(icon1)
self.horizontalLayout.addWidget(self.open_output_btn)
self.script_btn = QPushButton(self.centralwidget)
self.script_btn.setObjectName(u"script_btn")
sizePolicy.setHeightForWidth(self.script_btn.sizePolicy().hasHeightForWidth())
@ -371,7 +378,7 @@ class Ui_MainWindow(object):
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QMenuBar(MainWindow)
self.menubar.setObjectName(u"menubar")
self.menubar.setGeometry(QRect(0, 0, 1010, 21))
self.menubar.setGeometry(QRect(0, 0, 1010, 30))
self.menu_help = QMenu(self.menubar)
self.menu_help.setObjectName(u"menu_help")
self.menu_options = QMenu(self.menubar)
@ -431,6 +438,7 @@ class Ui_MainWindow(object):
self.label_5.setText(QCoreApplication.translate("MainWindow", u"Console:", None))
self.console_select_dropdown.setCurrentText("")
self.download_btn.setText(QCoreApplication.translate("MainWindow", u"Start Download", None))
self.open_output_btn.setText("")
self.script_btn.setText(QCoreApplication.translate("MainWindow", u"Run Script", None))
self.label_3.setText(QCoreApplication.translate("MainWindow", u"General Settings", None))
self.archive_file_entry.setPlaceholderText(QCoreApplication.translate("MainWindow", u"File Name", None))
@ -445,7 +453,7 @@ class Ui_MainWindow(object):
"hr { height: 1px; border-width: 0; }\n"
"li.unchecked::marker { content: \"\\2610\"; }\n"
"li.checked::marker { content: \"\\2612\"; }\n"
"</style></head><body style=\" font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;\">\n"
"</style></head><body style=\" font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;\">\n"
"<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;\"><br /></p></body></html>", None))
self.menu_help.setTitle(QCoreApplication.translate("MainWindow", u"Help", None))
self.menu_options.setTitle(QCoreApplication.translate("MainWindow", u"Options", None))

View File

@ -199,6 +199,16 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="open_output_btn">
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="QIcon::ThemeIcon::FolderOpen"/>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="script_btn">
<property name="sizePolicy">
@ -435,7 +445,7 @@ p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'.AppleSystemUIFont'; font-size:13pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:10pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
@ -469,7 +479,7 @@ li.checked::marker { content: &quot;\2612&quot;; }
<x>0</x>
<y>0</y>
<width>1010</width>
<height>21</height>
<height>30</height>
</rect>
</property>
<widget class="QMenu" name="menu_help">

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 32 32"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
sodipodi:docname="folder_black.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="25.125"
inkscape:cx="13.631841"
inkscape:cy="16.238806"
inkscape:window-width="1920"
inkscape:window-height="1012"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
id="defs1" /><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
style="fill:none"><g
id="g22"
transform="matrix(1.0676083,0,0,1.0676083,-1.0887422,-0.64491126)"><path
style="fill:none;stroke:#000000;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 2.906,9.6716418 V 18.984712"
id="path22" /><path
style="fill:none;stroke:#000000;stroke-width:2.013;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 2.9628905,7.9165624 V 9.6716418"
id="path21" /><path
style="fill:none;stroke:#000000;stroke-width:2.013;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 21.591797,7.9165624 C 21.591797,5.748664 19.845632,4.0025 17.677734,4.0025 H 6.8769531 c -2.1678983,0 -3.9140626,1.746164 -3.9140626,3.9140624"
id="path19" /><path
id="rect1-2"
style="stroke:#000000;stroke-width:1.93182;stroke-linecap:round;stroke-linejoin:round"
d="M 6.8475664,8.9410339 H 25.16587 c 2.174644,0 3.925351,1.6023621 3.925351,3.5927411 v 11.126173 c 0,1.990378 -1.750707,3.559824 -3.925351,3.559824 H 6.8475664 c -2.1746444,0 -3.9253508,-1.513144 -3.9253508,-3.503522 V 12.533775 c 0,-1.990379 1.7507064,-3.5927411 3.9253508,-3.5927411 z"
sodipodi:nodetypes="sssssssss" /></g></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="32"
height="32"
viewBox="0 0 32 32"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
sodipodi:docname="folder_white.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#999999"
borderopacity="1"
inkscape:showpageshadow="2"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="px"
inkscape:zoom="25.125"
inkscape:cx="13.631841"
inkscape:cy="16.199005"
inkscape:window-width="1920"
inkscape:window-height="1012"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
id="defs1" /><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
style="fill:none"><g
id="g22"
transform="matrix(1.0676083,0,0,1.0676083,-1.0887422,-0.64491126)"><path
style="fill:none;stroke:#ffffff;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 2.906,9.6716418 V 18.984712"
id="path22" /><path
style="fill:none;stroke:#ffffff;stroke-width:2.013;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 2.9628905,7.9165624 V 9.6716418"
id="path21" /><path
style="fill:none;stroke:#ffffff;stroke-width:2.013;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="M 21.591797,7.9165624 C 21.591797,5.748664 19.845632,4.0025 17.677734,4.0025 H 6.8769531 c -2.1678983,0 -3.9140626,1.746164 -3.9140626,3.9140624"
id="path19" /><path
id="rect1-2"
style="stroke:#ffffff;stroke-width:1.93182;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
d="M 6.8475664,8.9410339 H 25.16587 c 2.174644,0 3.925351,1.6023621 3.925351,3.5927411 v 11.126173 c 0,1.990378 -1.750707,3.559824 -3.925351,3.559824 H 6.8475664 c -2.1746444,0 -3.9253508,-1.513144 -3.9253508,-3.503522 V 12.533775 c 0,-1.990379 1.7507064,-3.5927411 3.9253508,-3.5927411 z"
sodipodi:nodetypes="sssssssss" /></g></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB