forked from mirror/openmw-tes3mp
Merged pull request #1623
This commit is contained in:
commit
efb4abbb7f
11 changed files with 338 additions and 16 deletions
|
@ -8,6 +8,7 @@ set(LAUNCHER
|
|||
settingspage.cpp
|
||||
advancedpage.cpp
|
||||
|
||||
utils/cellnameloader.cpp
|
||||
utils/profilescombobox.cpp
|
||||
utils/textinputdialog.cpp
|
||||
utils/lineedit.cpp
|
||||
|
@ -24,6 +25,7 @@ set(LAUNCHER_HEADER
|
|||
settingspage.hpp
|
||||
advancedpage.hpp
|
||||
|
||||
utils/cellnameloader.hpp
|
||||
utils/profilescombobox.hpp
|
||||
utils/textinputdialog.hpp
|
||||
utils/lineedit.hpp
|
||||
|
@ -39,6 +41,7 @@ set(LAUNCHER_HEADER_MOC
|
|||
settingspage.hpp
|
||||
advancedpage.hpp
|
||||
|
||||
utils/cellnameloader.hpp
|
||||
utils/textinputdialog.hpp
|
||||
utils/profilescombobox.hpp
|
||||
utils/lineedit.hpp
|
||||
|
|
|
@ -1,10 +1,18 @@
|
|||
#include "advancedpage.hpp"
|
||||
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
#include <components/config/gamesettings.hpp>
|
||||
#include <components/config/launchersettings.hpp>
|
||||
#include <QFileDialog>
|
||||
#include <QCompleter>
|
||||
#include <components/contentselector/view/contentselector.hpp>
|
||||
#include <components/contentselector/model/esmfile.hpp>
|
||||
|
||||
Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent)
|
||||
Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg,
|
||||
Config::GameSettings &gameSettings,
|
||||
Settings::Manager &engineSettings, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, mCfgMgr(cfg)
|
||||
, mGameSettings(gameSettings)
|
||||
, mEngineSettings(engineSettings)
|
||||
{
|
||||
setObjectName ("AdvancedPage");
|
||||
|
@ -13,8 +21,54 @@ Launcher::AdvancedPage::AdvancedPage(Files::ConfigurationManager &cfg, Settings:
|
|||
loadSettings();
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::loadCellsForAutocomplete(QStringList cellNames) {
|
||||
// Set up an auto-completer for the "Start default character at" field
|
||||
auto *completer = new QCompleter(cellNames);
|
||||
completer->setCompletionMode(QCompleter::PopupCompletion);
|
||||
completer->setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive);
|
||||
startDefaultCharacterAtField->setCompleter(completer);
|
||||
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::on_skipMenuCheckBox_stateChanged(int state) {
|
||||
startDefaultCharacterAtLabel->setEnabled(state == Qt::Checked);
|
||||
startDefaultCharacterAtField->setEnabled(state == Qt::Checked);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::on_runScriptAfterStartupBrowseButton_clicked()
|
||||
{
|
||||
QString scriptFile = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
QObject::tr("Select script file"),
|
||||
QDir::currentPath(),
|
||||
QString(tr("Text file (*.txt)")));
|
||||
|
||||
|
||||
if (scriptFile.isEmpty())
|
||||
return;
|
||||
|
||||
QFileInfo info(scriptFile);
|
||||
|
||||
if (!info.exists() || !info.isReadable())
|
||||
return;
|
||||
|
||||
const QString path(QDir::toNativeSeparators(info.absoluteFilePath()));
|
||||
|
||||
}
|
||||
|
||||
bool Launcher::AdvancedPage::loadSettings()
|
||||
{
|
||||
// Testing
|
||||
bool skipMenu = mGameSettings.value("skip-menu").toInt() == 1;
|
||||
if (skipMenu) {
|
||||
skipMenuCheckBox->setCheckState(Qt::Checked);
|
||||
}
|
||||
startDefaultCharacterAtLabel->setEnabled(skipMenu);
|
||||
startDefaultCharacterAtField->setEnabled(skipMenu);
|
||||
|
||||
startDefaultCharacterAtField->setText(mGameSettings.value("start"));
|
||||
runScriptAfterStartupField->setText(mGameSettings.value("script-run"));
|
||||
|
||||
// Game Settings
|
||||
loadSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game");
|
||||
loadSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
|
||||
|
@ -54,6 +108,19 @@ void Launcher::AdvancedPage::saveSettings()
|
|||
// Ensure we only set the new settings if they changed. This is to avoid cluttering the
|
||||
// user settings file (which by definition should only contain settings the user has touched)
|
||||
|
||||
// Testing
|
||||
int skipMenu = skipMenuCheckBox->checkState() == Qt::Checked;
|
||||
if (skipMenu != mGameSettings.value("skip-menu").toInt())
|
||||
mGameSettings.setValue("skip-menu", QString::number(skipMenu));
|
||||
|
||||
QString startCell = startDefaultCharacterAtField->text();
|
||||
if (startCell != mGameSettings.value("start")) {
|
||||
mGameSettings.setValue("start", startCell);
|
||||
}
|
||||
QString scriptRun = runScriptAfterStartupField->text();
|
||||
if (scriptRun != mGameSettings.value("script-run"))
|
||||
mGameSettings.setValue("script-run", scriptRun);
|
||||
|
||||
// Game Settings
|
||||
saveSettingBool(canLootDuringDeathAnimationCheckBox, "can loot during death animation", "Game");
|
||||
saveSettingBool(followersAttackOnSightCheckBox, "followers attack on sight", "Game");
|
||||
|
@ -95,4 +162,9 @@ void Launcher::AdvancedPage::saveSettingBool(QCheckBox *checkbox, const std::str
|
|||
bool cValue = checkbox->checkState();
|
||||
if (cValue != mEngineSettings.getBool(setting, group))
|
||||
mEngineSettings.setBool(setting, group, cValue);
|
||||
}
|
||||
|
||||
void Launcher::AdvancedPage::slotLoadedCellsChanged(QStringList cellNames)
|
||||
{
|
||||
loadCellsForAutocomplete(cellNames);
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
#include <components/settings/settings.hpp>
|
||||
|
||||
namespace Files { struct ConfigurationManager; }
|
||||
namespace Config { class GameSettings; }
|
||||
|
||||
namespace Launcher
|
||||
{
|
||||
|
@ -16,15 +17,29 @@ namespace Launcher
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AdvancedPage(Files::ConfigurationManager &cfg, Settings::Manager &engineSettings, QWidget *parent = 0);
|
||||
AdvancedPage(Files::ConfigurationManager &cfg, Config::GameSettings &gameSettings,
|
||||
Settings::Manager &engineSettings, QWidget *parent = 0);
|
||||
|
||||
bool loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
public slots:
|
||||
void slotLoadedCellsChanged(QStringList cellNames);
|
||||
|
||||
private slots:
|
||||
void on_skipMenuCheckBox_stateChanged(int state);
|
||||
void on_runScriptAfterStartupBrowseButton_clicked();
|
||||
|
||||
private:
|
||||
Files::ConfigurationManager &mCfgMgr;
|
||||
Config::GameSettings &mGameSettings;
|
||||
Settings::Manager &mEngineSettings;
|
||||
|
||||
/**
|
||||
* Load the cells associated with the given content files for use in autocomplete
|
||||
* @param filePaths the file paths of the content files to be examined
|
||||
*/
|
||||
void loadCellsForAutocomplete(QStringList filePaths);
|
||||
void loadSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
||||
void saveSettingBool(QCheckBox *checkbox, const std::string& setting, const std::string& group);
|
||||
};
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
#include <QCheckBox>
|
||||
#include <QMenu>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
|
||||
#include <apps/launcher/utils/cellnameloader.hpp>
|
||||
#include <components/files/configurationmanager.hpp>
|
||||
|
||||
#include <components/contentselector/model/esmfile.hpp>
|
||||
|
@ -16,6 +19,7 @@
|
|||
|
||||
#include <components/config/gamesettings.hpp>
|
||||
#include <components/config/launchersettings.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include "utils/textinputdialog.hpp"
|
||||
#include "utils/profilescombobox.hpp"
|
||||
|
@ -40,6 +44,13 @@ Launcher::DataFilesPage::DataFilesPage(Files::ConfigurationManager &cfg, Config:
|
|||
|
||||
buildView();
|
||||
loadSettings();
|
||||
|
||||
// Connect signal and slot after the settings have been loaded. We only care about the user changing
|
||||
// the addons and don't want to get signals of the system doing it during startup.
|
||||
connect(mSelector, SIGNAL(signalAddonDataChanged(QModelIndex,QModelIndex)),
|
||||
this, SLOT(slotAddonDataChanged()));
|
||||
// Call manually to indicate all changes to addon data during startup.
|
||||
slotAddonDataChanged();
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::buildView()
|
||||
|
@ -142,6 +153,17 @@ void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
|||
mGameSettings.setContentList(fileNames);
|
||||
}
|
||||
|
||||
QStringList Launcher::DataFilesPage::selectedFilePaths()
|
||||
{
|
||||
//retrieve the files selected for the profile
|
||||
ContentSelectorModel::ContentFileList items = mSelector->selectedFiles();
|
||||
QStringList filePaths;
|
||||
foreach(const ContentSelectorModel::EsmFile *item, items) {
|
||||
filePaths.append(item->filePath());
|
||||
}
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::removeProfile(const QString &profile)
|
||||
{
|
||||
mLauncherSettings.removeContentList(profile);
|
||||
|
@ -308,3 +330,31 @@ bool Launcher::DataFilesPage::showDeleteMessageBox (const QString &text)
|
|||
|
||||
return (msgBox.clickedButton() == deleteButton);
|
||||
}
|
||||
|
||||
void Launcher::DataFilesPage::slotAddonDataChanged()
|
||||
{
|
||||
QStringList selectedFiles = selectedFilePaths();
|
||||
if (previousSelectedFiles != selectedFiles) {
|
||||
previousSelectedFiles = selectedFiles;
|
||||
// Loading cells for core Morrowind + Expansions takes about 0.2 seconds, which is enough to cause a
|
||||
// barely perceptible UI lag. Splitting into its own thread to alleviate that.
|
||||
std::thread loadCellsThread(&DataFilesPage::reloadCells, this, selectedFiles);
|
||||
loadCellsThread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
// Mutex lock to run reloadCells synchronously.
|
||||
std::mutex _reloadCellsMutex;
|
||||
|
||||
void Launcher::DataFilesPage::reloadCells(QStringList selectedFiles)
|
||||
{
|
||||
// Use a mutex lock so that we can prevent two threads from executing the rest of this code at the same time
|
||||
// Based on https://stackoverflow.com/a/5429695/531762
|
||||
std::unique_lock<std::mutex> lock(_reloadCellsMutex);
|
||||
|
||||
// The following code will run only if there is not another thread currently running it
|
||||
CellNameLoader cellNameLoader;
|
||||
QStringList cellNamesList = QStringList::fromSet(cellNameLoader.getCellNames(selectedFiles));
|
||||
std::sort(cellNamesList.begin(), cellNamesList.end());
|
||||
emit signalLoadedCellsChanged(cellNamesList);
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QStringList>
|
||||
|
||||
class QSortFilterProxyModel;
|
||||
class QAbstractItemModel;
|
||||
|
@ -41,8 +42,15 @@ namespace Launcher
|
|||
void saveSettings(const QString &profile = "");
|
||||
bool loadSettings();
|
||||
|
||||
/**
|
||||
* Returns the file paths of all selected content files
|
||||
* @return the file paths of all selected content files
|
||||
*/
|
||||
QStringList selectedFilePaths();
|
||||
|
||||
signals:
|
||||
void signalProfileChanged (int index);
|
||||
void signalLoadedCellsChanged(QStringList selectedFiles);
|
||||
|
||||
public slots:
|
||||
void slotProfileChanged (int index);
|
||||
|
@ -52,6 +60,7 @@ namespace Launcher
|
|||
void slotProfileChangedByUser(const QString &previous, const QString ¤t);
|
||||
void slotProfileRenamed(const QString &previous, const QString ¤t);
|
||||
void slotProfileDeleted(const QString &item);
|
||||
void slotAddonDataChanged ();
|
||||
|
||||
void updateOkButton(const QString &text);
|
||||
|
||||
|
@ -72,7 +81,7 @@ namespace Launcher
|
|||
Config::LauncherSettings &mLauncherSettings;
|
||||
|
||||
QString mPreviousProfile;
|
||||
|
||||
QStringList previousSelectedFiles;
|
||||
QString mDataLocal;
|
||||
|
||||
void setPluginsCheckstates(Qt::CheckState state);
|
||||
|
@ -87,6 +96,7 @@ namespace Launcher
|
|||
void addProfile (const QString &profile, bool setAsCurrent);
|
||||
void checkForDefaultProfile();
|
||||
void populateFileViews(const QString& contentModelName);
|
||||
void reloadCells(QStringList selectedFiles);
|
||||
|
||||
class PathIterator
|
||||
{
|
||||
|
|
|
@ -119,7 +119,7 @@ void Launcher::MainDialog::createPages()
|
|||
mDataFilesPage = new DataFilesPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
|
||||
mGraphicsPage = new GraphicsPage(mCfgMgr, mEngineSettings, this);
|
||||
mSettingsPage = new SettingsPage(mCfgMgr, mGameSettings, mLauncherSettings, this);
|
||||
mAdvancedPage = new AdvancedPage(mCfgMgr, mEngineSettings, this);
|
||||
mAdvancedPage = new AdvancedPage(mCfgMgr, mGameSettings, mEngineSettings, this);
|
||||
|
||||
// Set the combobox of the play page to imitate the combobox on the datafilespage
|
||||
mPlayPage->setProfilesModel(mDataFilesPage->profilesModel());
|
||||
|
@ -139,6 +139,8 @@ void Launcher::MainDialog::createPages()
|
|||
|
||||
connect(mPlayPage, SIGNAL(signalProfileChanged(int)), mDataFilesPage, SLOT(slotProfileChanged(int)));
|
||||
connect(mDataFilesPage, SIGNAL(signalProfileChanged(int)), mPlayPage, SLOT(setProfilesIndex(int)));
|
||||
// Using Qt::QueuedConnection because signal is emitted in a subthread and slot is in the main thread
|
||||
connect(mDataFilesPage, SIGNAL(signalLoadedCellsChanged(QStringList)), mAdvancedPage, SLOT(slotLoadedCellsChanged(QStringList)), Qt::QueuedConnection);
|
||||
|
||||
}
|
||||
|
||||
|
|
48
apps/launcher/utils/cellnameloader.cpp
Normal file
48
apps/launcher/utils/cellnameloader.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include "cellnameloader.hpp"
|
||||
|
||||
#include <components/esm/loadcell.hpp>
|
||||
#include <components/contentselector/view/contentselector.hpp>
|
||||
|
||||
QSet<QString> CellNameLoader::getCellNames(QStringList &contentPaths)
|
||||
{
|
||||
QSet<QString> cellNames;
|
||||
ESM::ESMReader esmReader;
|
||||
|
||||
// Loop through all content files
|
||||
for (auto &contentPath : contentPaths) {
|
||||
esmReader.open(contentPath.toStdString());
|
||||
|
||||
// Loop through all records
|
||||
while(esmReader.hasMoreRecs())
|
||||
{
|
||||
ESM::NAME recordName = esmReader.getRecName();
|
||||
esmReader.getRecHeader();
|
||||
|
||||
if (isCellRecord(recordName)) {
|
||||
QString cellName = getCellName(esmReader);
|
||||
if (!cellName.isEmpty()) {
|
||||
cellNames.insert(cellName);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop loading content for this record and continue to the next
|
||||
esmReader.skipRecord();
|
||||
}
|
||||
}
|
||||
|
||||
return cellNames;
|
||||
}
|
||||
|
||||
bool CellNameLoader::isCellRecord(ESM::NAME &recordName)
|
||||
{
|
||||
return recordName.intval == ESM::REC_CELL;
|
||||
}
|
||||
|
||||
QString CellNameLoader::getCellName(ESM::ESMReader &esmReader)
|
||||
{
|
||||
ESM::Cell cell;
|
||||
bool isDeleted = false;
|
||||
cell.loadNameAndData(esmReader, isDeleted);
|
||||
|
||||
return QString::fromStdString(cell.mName);
|
||||
}
|
41
apps/launcher/utils/cellnameloader.hpp
Normal file
41
apps/launcher/utils/cellnameloader.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
#ifndef OPENMW_CELLNAMELOADER_H
|
||||
#define OPENMW_CELLNAMELOADER_H
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
|
||||
namespace ESM {class ESMReader; struct Cell;}
|
||||
namespace ContentSelectorView {class ContentSelector;}
|
||||
|
||||
class CellNameLoader {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns the names of all cells contained within the given content files
|
||||
* @param contentPaths the file paths of each content file to be examined
|
||||
* @return the names of all cells
|
||||
*/
|
||||
QSet<QString> getCellNames(QStringList &contentPaths);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Returns whether or not the given record is of type "Cell"
|
||||
* @param name The name associated with the record
|
||||
* @return whether or not the given record is of type "Cell"
|
||||
*/
|
||||
bool isCellRecord(ESM::NAME &name);
|
||||
|
||||
/**
|
||||
* Returns the name of the cell
|
||||
* @param esmReader the reader currently pointed to a loaded cell
|
||||
* @return the name of the cell
|
||||
*/
|
||||
QString getCellName(ESM::ESMReader &esmReader);
|
||||
};
|
||||
|
||||
|
||||
#endif //OPENMW_CELLNAMELOADER_H
|
|
@ -239,4 +239,4 @@ void ContentSelectorView::ContentSelector::slotUncheckMultiSelectedItems()
|
|||
void ContentSelectorView::ContentSelector::slotCheckMultiSelectedItems()
|
||||
{
|
||||
setCheckStateForMultiSelectedItems(true);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@ namespace ContentSelectorView
|
|||
Q_OBJECT
|
||||
|
||||
QMenu *mContextMenu;
|
||||
QStringList mFilePaths;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -61,6 +60,7 @@ namespace ContentSelectorView
|
|||
void signalCurrentGamefileIndexChanged (int);
|
||||
|
||||
void signalAddonDataChanged (const QModelIndex& topleft, const QModelIndex& bottomright);
|
||||
void signalSelectedFilesChanged(QStringList selectedFiles);
|
||||
|
||||
private slots:
|
||||
|
||||
|
|
|
@ -11,13 +11,6 @@
|
|||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="pageVerticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="pageDescriptionLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>This temporary page contains new settings that will be available in-game in a post-1.0 release of OpenMW.</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="widgetResizable">
|
||||
|
@ -27,9 +20,9 @@
|
|||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-187</y>
|
||||
<y>0</y>
|
||||
<width>630</width>
|
||||
<height>510</height>
|
||||
<height>746</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="scrollAreaVerticalLayout">
|
||||
|
@ -276,6 +269,94 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="testingGroup">
|
||||
<property name="title">
|
||||
<string>Testing</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="testingGroupVerticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="testingLabel">
|
||||
<property name="text">
|
||||
<string>These settings are intended for testing mods and will cause issues if used for normal gameplay.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="testingLine">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="skipMenuCheckBox">
|
||||
<property name="text">
|
||||
<string>Skip menu and generate default character</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="startDefaultCharacterAtHorizontalLayout">
|
||||
<item>
|
||||
<spacer name="startDefaultCharacterAtHorizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="startDefaultCharacterAtLabel">
|
||||
<property name="text">
|
||||
<string>Start default character at</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="startDefaultCharacterAtField">
|
||||
<property name="placeholderText">
|
||||
<string>default cell</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Run script after startup:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="runScriptAfterStartupHorizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="runScriptAfterStartupField"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="runScriptAfterStartupBrowseButton">
|
||||
<property name="text">
|
||||
<string>Browse…</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="otherGroup">
|
||||
<property name="title">
|
||||
|
|
Loading…
Reference in a new issue