diff options
Diffstat (limited to 'src/yuzu')
-rw-r--r-- | src/yuzu/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/yuzu/debugger/registers.cpp | 190 | ||||
-rw-r--r-- | src/yuzu/debugger/registers.h | 42 | ||||
-rw-r--r-- | src/yuzu/debugger/registers.ui | 40 | ||||
-rw-r--r-- | src/yuzu/debugger/wait_tree.cpp | 4 | ||||
-rw-r--r-- | src/yuzu/game_list.cpp | 32 | ||||
-rw-r--r-- | src/yuzu/main.cpp | 31 | ||||
-rw-r--r-- | src/yuzu/main.h | 3 | ||||
-rw-r--r-- | src/yuzu/main.ui | 6 |
9 files changed, 55 insertions, 296 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 5af3154d7..c662570d2 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -32,8 +32,6 @@ add_executable(yuzu debugger/graphics/graphics_surface.h debugger/profiler.cpp debugger/profiler.h - debugger/registers.cpp - debugger/registers.h debugger/wait_tree.cpp debugger/wait_tree.h game_list.cpp @@ -60,7 +58,6 @@ set(UIS configuration/configure_graphics.ui configuration/configure_input.ui configuration/configure_system.ui - debugger/registers.ui hotkeys.ui main.ui ) diff --git a/src/yuzu/debugger/registers.cpp b/src/yuzu/debugger/registers.cpp deleted file mode 100644 index 178cc65a7..000000000 --- a/src/yuzu/debugger/registers.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <QTreeWidgetItem> -#include "core/arm/arm_interface.h" -#include "core/core.h" -#include "yuzu/debugger/registers.h" -#include "yuzu/util/util.h" - -RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { - cpu_regs_ui.setupUi(this); - - tree = cpu_regs_ui.treeWidget; - tree->addTopLevelItem(core_registers = new QTreeWidgetItem(QStringList(tr("Registers")))); - tree->addTopLevelItem(vfp_registers = new QTreeWidgetItem(QStringList(tr("VFP Registers")))); - tree->addTopLevelItem(vfp_system_registers = - new QTreeWidgetItem(QStringList(tr("VFP System Registers")))); - tree->addTopLevelItem(cpsr = new QTreeWidgetItem(QStringList("CPSR"))); - - for (int i = 0; i < 16; ++i) { - QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("R[%1]").arg(i))); - core_registers->addChild(child); - } - - for (int i = 0; i < 32; ++i) { - QTreeWidgetItem* child = new QTreeWidgetItem(QStringList(QString("S[%1]").arg(i))); - vfp_registers->addChild(child); - } - - QFont font = GetMonospaceFont(); - - CreateCPSRChildren(); - CreateVFPSystemRegisterChildren(); - - // Set Registers to display in monospace font - for (int i = 0; i < core_registers->childCount(); ++i) - core_registers->child(i)->setFont(1, font); - - for (int i = 0; i < vfp_registers->childCount(); ++i) - vfp_registers->child(i)->setFont(1, font); - - for (int i = 0; i < vfp_system_registers->childCount(); ++i) { - vfp_system_registers->child(i)->setFont(1, font); - for (int x = 0; x < vfp_system_registers->child(i)->childCount(); ++x) { - vfp_system_registers->child(i)->child(x)->setFont(1, font); - } - } - // Set CSPR to display in monospace font - cpsr->setFont(1, font); - for (int i = 0; i < cpsr->childCount(); ++i) { - cpsr->child(i)->setFont(1, font); - for (int x = 0; x < cpsr->child(i)->childCount(); ++x) { - cpsr->child(i)->child(x)->setFont(1, font); - } - } - setEnabled(false); -} - -void RegistersWidget::OnDebugModeEntered() { - if (!Core::System::GetInstance().IsPoweredOn()) - return; - - for (int i = 0; i < core_registers->childCount(); ++i) - core_registers->child(i)->setText( - 1, QString("0x%1").arg(Core::CurrentArmInterface().GetReg(i), 8, 16, QLatin1Char('0'))); - - UpdateCPSRValues(); -} - -void RegistersWidget::OnDebugModeLeft() {} - -void RegistersWidget::OnEmulationStarting(EmuThread* emu_thread) { - setEnabled(true); -} - -void RegistersWidget::OnEmulationStopping() { - // Reset widget text - for (int i = 0; i < core_registers->childCount(); ++i) - core_registers->child(i)->setText(1, QString("")); - - for (int i = 0; i < vfp_registers->childCount(); ++i) - vfp_registers->child(i)->setText(1, QString("")); - - for (int i = 0; i < cpsr->childCount(); ++i) - cpsr->child(i)->setText(1, QString("")); - - cpsr->setText(1, QString("")); - - // FPSCR - for (int i = 0; i < vfp_system_registers->child(0)->childCount(); ++i) - vfp_system_registers->child(0)->child(i)->setText(1, QString("")); - - // FPEXC - for (int i = 0; i < vfp_system_registers->child(1)->childCount(); ++i) - vfp_system_registers->child(1)->child(i)->setText(1, QString("")); - - vfp_system_registers->child(0)->setText(1, QString("")); - vfp_system_registers->child(1)->setText(1, QString("")); - vfp_system_registers->child(2)->setText(1, QString("")); - vfp_system_registers->child(3)->setText(1, QString("")); - - setEnabled(false); -} - -void RegistersWidget::CreateCPSRChildren() { - cpsr->addChild(new QTreeWidgetItem(QStringList("M"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("T"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("F"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("I"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("A"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("E"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("IT"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("GE"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("DNM"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("J"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("Q"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("V"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("C"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("Z"))); - cpsr->addChild(new QTreeWidgetItem(QStringList("N"))); -} - -void RegistersWidget::UpdateCPSRValues() { - const u32 cpsr_val = Core::CurrentArmInterface().GetCPSR(); - - cpsr->setText(1, QString("0x%1").arg(cpsr_val, 8, 16, QLatin1Char('0'))); - cpsr->child(0)->setText( - 1, QString("b%1").arg(cpsr_val & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode - cpsr->child(1)->setText(1, QString::number((cpsr_val >> 5) & 1)); // T - State - cpsr->child(2)->setText(1, QString::number((cpsr_val >> 6) & 1)); // F - FIQ disable - cpsr->child(3)->setText(1, QString::number((cpsr_val >> 7) & 1)); // I - IRQ disable - cpsr->child(4)->setText(1, QString::number((cpsr_val >> 8) & 1)); // A - Imprecise abort - cpsr->child(5)->setText(1, QString::number((cpsr_val >> 9) & 1)); // E - Data endianness - cpsr->child(6)->setText(1, - QString::number((cpsr_val >> 10) & 0x3F)); // IT - If-Then state (DNM) - cpsr->child(7)->setText(1, - QString::number((cpsr_val >> 16) & 0xF)); // GE - Greater-than-or-Equal - cpsr->child(8)->setText(1, QString::number((cpsr_val >> 20) & 0xF)); // DNM - Do not modify - cpsr->child(9)->setText(1, QString::number((cpsr_val >> 24) & 1)); // J - Jazelle - cpsr->child(10)->setText(1, QString::number((cpsr_val >> 27) & 1)); // Q - Saturation - cpsr->child(11)->setText(1, QString::number((cpsr_val >> 28) & 1)); // V - Overflow - cpsr->child(12)->setText(1, QString::number((cpsr_val >> 29) & 1)); // C - Carry/Borrow/Extend - cpsr->child(13)->setText(1, QString::number((cpsr_val >> 30) & 1)); // Z - Zero - cpsr->child(14)->setText(1, QString::number((cpsr_val >> 31) & 1)); // N - Negative/Less than -} - -void RegistersWidget::CreateVFPSystemRegisterChildren() { - QTreeWidgetItem* const fpscr = new QTreeWidgetItem(QStringList("FPSCR")); - fpscr->addChild(new QTreeWidgetItem(QStringList("IOC"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("DZC"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("OFC"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("UFC"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("IXC"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("IDC"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("IOE"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("DZE"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("OFE"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("UFE"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("IXE"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("IDE"))); - fpscr->addChild(new QTreeWidgetItem(QStringList(tr("Vector Length")))); - fpscr->addChild(new QTreeWidgetItem(QStringList(tr("Vector Stride")))); - fpscr->addChild(new QTreeWidgetItem(QStringList(tr("Rounding Mode")))); - fpscr->addChild(new QTreeWidgetItem(QStringList("FZ"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("DN"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("V"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("C"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("Z"))); - fpscr->addChild(new QTreeWidgetItem(QStringList("N"))); - - QTreeWidgetItem* const fpexc = new QTreeWidgetItem(QStringList("FPEXC")); - fpexc->addChild(new QTreeWidgetItem(QStringList("IOC"))); - fpexc->addChild(new QTreeWidgetItem(QStringList("OFC"))); - fpexc->addChild(new QTreeWidgetItem(QStringList("UFC"))); - fpexc->addChild(new QTreeWidgetItem(QStringList("INV"))); - fpexc->addChild(new QTreeWidgetItem(QStringList(tr("Vector Iteration Count")))); - fpexc->addChild(new QTreeWidgetItem(QStringList("FP2V"))); - fpexc->addChild(new QTreeWidgetItem(QStringList("EN"))); - fpexc->addChild(new QTreeWidgetItem(QStringList("EX"))); - - vfp_system_registers->addChild(fpscr); - vfp_system_registers->addChild(fpexc); - vfp_system_registers->addChild(new QTreeWidgetItem(QStringList("FPINST"))); - vfp_system_registers->addChild(new QTreeWidgetItem(QStringList("FPINST2"))); -} - -void RegistersWidget::UpdateVFPSystemRegisterValues() { - UNIMPLEMENTED(); -} diff --git a/src/yuzu/debugger/registers.h b/src/yuzu/debugger/registers.h deleted file mode 100644 index 55bda5b59..000000000 --- a/src/yuzu/debugger/registers.h +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <QDockWidget> -#include "ui_registers.h" - -class QTreeWidget; -class QTreeWidgetItem; -class EmuThread; - -class RegistersWidget : public QDockWidget { - Q_OBJECT - -public: - explicit RegistersWidget(QWidget* parent = nullptr); - -public slots: - void OnDebugModeEntered(); - void OnDebugModeLeft(); - - void OnEmulationStarting(EmuThread* emu_thread); - void OnEmulationStopping(); - -private: - void CreateCPSRChildren(); - void UpdateCPSRValues(); - - void CreateVFPSystemRegisterChildren(); - void UpdateVFPSystemRegisterValues(); - - Ui::ARMRegisters cpu_regs_ui; - - QTreeWidget* tree; - - QTreeWidgetItem* core_registers; - QTreeWidgetItem* vfp_registers; - QTreeWidgetItem* vfp_system_registers; - QTreeWidgetItem* cpsr; -}; diff --git a/src/yuzu/debugger/registers.ui b/src/yuzu/debugger/registers.ui deleted file mode 100644 index c81ae03f9..000000000 --- a/src/yuzu/debugger/registers.ui +++ /dev/null @@ -1,40 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ARMRegisters</class> - <widget class="QDockWidget" name="ARMRegisters"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>300</height> - </rect> - </property> - <property name="windowTitle"> - <string>ARM Registers</string> - </property> - <widget class="QWidget" name="dockWidgetContents"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QTreeWidget" name="treeWidget"> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <column> - <property name="text"> - <string>Register</string> - </property> - </column> - <column> - <property name="text"> - <string>Value</string> - </property> - </column> - </widget> - </item> - </layout> - </widget> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index 017bef13c..7101b381e 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -213,6 +213,9 @@ QString WaitTreeThread::GetText() const { case THREADSTATUS_WAIT_MUTEX: status = tr("waiting for mutex"); break; + case THREADSTATUS_WAIT_ARB: + status = tr("waiting for address arbiter"); + break; case THREADSTATUS_DORMANT: status = tr("dormant"); break; @@ -240,6 +243,7 @@ QColor WaitTreeThread::GetColor() const { case THREADSTATUS_WAIT_SYNCH_ALL: case THREADSTATUS_WAIT_SYNCH_ANY: case THREADSTATUS_WAIT_MUTEX: + case THREADSTATUS_WAIT_ARB: return QColor(Qt::GlobalColor::red); case THREADSTATUS_DORMANT: return QColor(Qt::GlobalColor::darkCyan); diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index bbd681eae..55dce6d47 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include <QApplication> +#include <QDir> #include <QFileInfo> #include <QHeaderView> #include <QKeyEvent> @@ -264,8 +265,17 @@ void GameList::ValidateEntry(const QModelIndex& item) { if (file_path.isEmpty()) return; std::string std_file_path(file_path.toStdString()); - if (!FileUtil::Exists(std_file_path) || FileUtil::IsDirectory(std_file_path)) + if (!FileUtil::Exists(std_file_path)) return; + if (FileUtil::IsDirectory(std_file_path)) { + QDir dir(std_file_path.c_str()); + QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files); + if (matching_main.size() == 1) { + emit GameChosen(dir.path() + DIR_SEP + matching_main[0]); + } + return; + } + // Users usually want to run a diffrent game after closing one search_field->clear(); emit GameChosen(file_path); @@ -356,13 +366,26 @@ void GameList::LoadInterfaceLayout() { item_model->sort(header->sortIndicatorSection(), header->sortIndicatorOrder()); } -const QStringList GameList::supported_file_extensions = {"nso", "nro"}; +const QStringList GameList::supported_file_extensions = {"nso", "nro", "nca"}; static bool HasSupportedFileExtension(const std::string& file_name) { QFileInfo file = QFileInfo(file_name.c_str()); return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive); } +static bool IsExtractedNCAMain(const std::string& file_name) { + return QFileInfo(file_name.c_str()).fileName() == "main"; +} + +static QString FormatGameName(const std::string& physical_name) { + QFileInfo file_info(physical_name.c_str()); + if (IsExtractedNCAMain(physical_name)) { + return file_info.dir().path(); + } else { + return QString::fromStdString(physical_name); + } +} + void GameList::RefreshGameDirectory() { if (!UISettings::values.gamedir.isEmpty() && current_worker != nullptr) { NGLOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); @@ -380,7 +403,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign return false; // Breaks the callback loop. bool is_dir = FileUtil::IsDirectory(physical_name); - if (!is_dir && HasSupportedFileExtension(physical_name)) { + if (!is_dir && + (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name); if (!loader) return true; @@ -392,7 +416,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign loader->ReadProgramId(program_id); emit EntryReady({ - new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id), + new GameListItemPath(FormatGameName(physical_name), smdh, program_id), new GameListItem( QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), new GameListItemSize(FileUtil::GetSize(physical_name)), diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 3038bd6da..97be548d7 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -13,6 +13,7 @@ #include <QMessageBox> #include <QtGui> #include <QtWidgets> +#include "common/common_paths.h" #include "common/logging/backend.h" #include "common/logging/filter.h" #include "common/logging/log.h" @@ -33,7 +34,6 @@ #include "yuzu/debugger/graphics/graphics_breakpoints.h" #include "yuzu/debugger/graphics/graphics_surface.h" #include "yuzu/debugger/profiler.h" -#include "yuzu/debugger/registers.h" #include "yuzu/debugger/wait_tree.h" #include "yuzu/game_list.h" #include "yuzu/hotkeys.h" @@ -169,15 +169,6 @@ void GMainWindow::InitializeDebugWidgets() { debug_menu->addAction(microProfileDialog->toggleViewAction()); #endif - registersWidget = new RegistersWidget(this); - addDockWidget(Qt::RightDockWidgetArea, registersWidget); - registersWidget->hide(); - debug_menu->addAction(registersWidget->toggleViewAction()); - connect(this, &GMainWindow::EmulationStarting, registersWidget, - &RegistersWidget::OnEmulationStarting); - connect(this, &GMainWindow::EmulationStopping, registersWidget, - &RegistersWidget::OnEmulationStopping); - graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(debug_context, this); addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget); graphicsBreakpointsWidget->hide(); @@ -288,6 +279,7 @@ void GMainWindow::ConnectWidgetEvents() { void GMainWindow::ConnectMenuEvents() { // File connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); + connect(ui.action_Load_Folder, &QAction::triggered, this, &GMainWindow::OnMenuLoadFolder); connect(ui.action_Select_Game_List_Root, &QAction::triggered, this, &GMainWindow::OnMenuSelectGameListRoot); connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); @@ -460,17 +452,12 @@ void GMainWindow::BootGame(const QString& filename) { connect(render_window, &GRenderWindow::Closed, this, &GMainWindow::OnStopGame); // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views // before the CPU continues - connect(emu_thread.get(), &EmuThread::DebugModeEntered, registersWidget, - &RegistersWidget::OnDebugModeEntered, Qt::BlockingQueuedConnection); connect(emu_thread.get(), &EmuThread::DebugModeEntered, waitTreeWidget, &WaitTreeWidget::OnDebugModeEntered, Qt::BlockingQueuedConnection); - connect(emu_thread.get(), &EmuThread::DebugModeLeft, registersWidget, - &RegistersWidget::OnDebugModeLeft, Qt::BlockingQueuedConnection); connect(emu_thread.get(), &EmuThread::DebugModeLeft, waitTreeWidget, &WaitTreeWidget::OnDebugModeLeft, Qt::BlockingQueuedConnection); // Update the GUI - registersWidget->OnDebugModeEntered(); if (ui.action_Single_Window_Mode->isChecked()) { game_list->hide(); } @@ -565,6 +552,8 @@ void GMainWindow::OnMenuLoadFile() { for (const auto& piece : game_list->supported_file_extensions) extensions += "*." + piece + " "; + extensions += "main "; + QString file_filter = tr("Switch Executable") + " (" + extensions + ")"; file_filter += ";;" + tr("All Files (*.*)"); @@ -577,6 +566,18 @@ void GMainWindow::OnMenuLoadFile() { } } +void GMainWindow::OnMenuLoadFolder() { + QDir dir = QFileDialog::getExistingDirectory(this, tr("Open Extracted ROM Directory")); + + QStringList matching_main = dir.entryList(QStringList("main"), QDir::Files); + if (matching_main.size() == 1) { + BootGame(dir.path() + DIR_SEP + matching_main[0]); + } else { + QMessageBox::warning(this, tr("Invalid Directory Selected"), + tr("The directory you have selected does not contain a 'main' file.")); + } +} + void GMainWindow::OnMenuSelectGameListRoot() { QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory")); if (!dir_path.isEmpty()) { diff --git a/src/yuzu/main.h b/src/yuzu/main.h index ac3024d8a..074bba3f9 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -19,7 +19,6 @@ class GraphicsSurfaceWidget; class GRenderWindow; class MicroProfileDialog; class ProfilerWidget; -class RegistersWidget; class WaitTreeWidget; namespace Tegra { @@ -124,6 +123,7 @@ private slots: void OnGameListLoadFile(QString game_path); void OnGameListOpenSaveFolder(u64 program_id); void OnMenuLoadFile(); + void OnMenuLoadFolder(); /// Called whenever a user selects the "File->Select Game List Root" menu item void OnMenuSelectGameListRoot(); void OnMenuRecentFile(); @@ -163,7 +163,6 @@ private: // Debugger panes ProfilerWidget* profilerWidget; MicroProfileDialog* microProfileDialog; - RegistersWidget* registersWidget; GraphicsBreakPointsWidget* graphicsBreakpointsWidget; GraphicsSurfaceWidget* graphicsSurfaceWidget; WaitTreeWidget* waitTreeWidget; diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui index 0fcd93cc2..22c4cad08 100644 --- a/src/yuzu/main.ui +++ b/src/yuzu/main.ui @@ -58,6 +58,7 @@ </property> </widget> <addaction name="action_Load_File"/> + <addaction name="action_Load_Folder"/> <addaction name="separator"/> <addaction name="action_Select_Game_List_Root"/> <addaction name="menu_recent_files"/> @@ -106,6 +107,11 @@ <string>Load File...</string> </property> </action> + <action name="action_Load_Folder"> + <property name="text"> + <string>Load Folder...</string> + </property> + </action> <action name="action_Load_Symbol_Map"> <property name="text"> <string>Load Symbol Map...</string> |