- Reset All Settings button in General preferences - Clears all settings and restores XPlor Dark theme - Applies theme change immediately - Confirmation dialog before reset 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
550 lines
19 KiB
C++
550 lines
19 KiB
C++
#include "preferenceeditor.h"
|
|
#include "settings.h"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QGroupBox>
|
|
#include <QDialogButtonBox>
|
|
#include <QFontDatabase>
|
|
#include <QFileDialog>
|
|
#include <QFormLayout>
|
|
#include <QFrame>
|
|
#include <QMessageBox>
|
|
|
|
PreferenceEditor::PreferenceEditor(QWidget *parent)
|
|
: QDialog(parent)
|
|
{
|
|
setupUi();
|
|
loadSettings();
|
|
applyStylesheet();
|
|
}
|
|
|
|
void PreferenceEditor::setupUi()
|
|
{
|
|
setWindowTitle("XPlor Preferences");
|
|
setMinimumSize(700, 500);
|
|
resize(800, 550);
|
|
|
|
auto *mainLayout = new QVBoxLayout(this);
|
|
mainLayout->setSpacing(10);
|
|
mainLayout->setContentsMargins(15, 15, 15, 15);
|
|
|
|
// Main content area
|
|
auto *contentLayout = new QHBoxLayout();
|
|
contentLayout->setSpacing(15);
|
|
|
|
// Category list
|
|
m_categoryList = new QListWidget(this);
|
|
m_categoryList->setFixedWidth(160);
|
|
m_categoryList->setSpacing(2);
|
|
m_categoryList->addItem("Appearance");
|
|
m_categoryList->addItem("General");
|
|
m_categoryList->addItem("Debug & Logging");
|
|
m_categoryList->addItem("Tree Browser");
|
|
m_categoryList->addItem("Previews");
|
|
m_categoryList->setCurrentRow(0);
|
|
connect(m_categoryList, &QListWidget::currentRowChanged, this, &PreferenceEditor::onCategoryChanged);
|
|
contentLayout->addWidget(m_categoryList);
|
|
|
|
// Page stack
|
|
m_pageStack = new QStackedWidget(this);
|
|
createAppearancePage();
|
|
createGeneralPage();
|
|
createDebugPage();
|
|
createTreePage();
|
|
createPreviewPage();
|
|
contentLayout->addWidget(m_pageStack, 1);
|
|
|
|
mainLayout->addLayout(contentLayout, 1);
|
|
|
|
// Separator
|
|
auto *separator = new QFrame(this);
|
|
separator->setFrameShape(QFrame::HLine);
|
|
separator->setStyleSheet("background-color: #3c3c3c;");
|
|
mainLayout->addWidget(separator);
|
|
|
|
// Button box
|
|
auto *buttonBox = new QDialogButtonBox(
|
|
QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply,
|
|
this);
|
|
connect(buttonBox, &QDialogButtonBox::accepted, this, &PreferenceEditor::onAccept);
|
|
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
|
connect(buttonBox->button(QDialogButtonBox::Apply), &QPushButton::clicked, this, &PreferenceEditor::onApply);
|
|
mainLayout->addWidget(buttonBox);
|
|
}
|
|
|
|
void PreferenceEditor::createAppearancePage()
|
|
{
|
|
auto *page = new QWidget(this);
|
|
auto *layout = new QVBoxLayout(page);
|
|
layout->setSpacing(15);
|
|
|
|
// Title
|
|
auto *titleLabel = new QLabel("Appearance", page);
|
|
titleLabel->setStyleSheet("font-size: 14px; font-weight: bold; color: #ad0c0c;");
|
|
layout->addWidget(titleLabel);
|
|
|
|
// Theme group
|
|
auto *themeGroup = new QGroupBox("Color Theme", page);
|
|
auto *themeLayout = new QVBoxLayout(themeGroup);
|
|
themeLayout->setSpacing(10);
|
|
|
|
auto *themeRow = new QHBoxLayout();
|
|
auto *themeLabel = new QLabel("Theme:", themeGroup);
|
|
themeRow->addWidget(themeLabel);
|
|
|
|
m_themeCombo = new QComboBox(themeGroup);
|
|
for (const QString &themeName : Settings::instance().availableThemes()) {
|
|
m_themeCombo->addItem(themeName);
|
|
}
|
|
connect(m_themeCombo, &QComboBox::currentTextChanged, this, &PreferenceEditor::updateThemePreview);
|
|
themeRow->addWidget(m_themeCombo, 1);
|
|
themeLayout->addLayout(themeRow);
|
|
|
|
// Theme preview
|
|
m_themePreview = new QLabel(themeGroup);
|
|
m_themePreview->setFixedHeight(80);
|
|
m_themePreview->setAlignment(Qt::AlignCenter);
|
|
themeLayout->addWidget(m_themePreview);
|
|
|
|
// Theme description
|
|
auto *themeDesc = new QLabel(
|
|
"Choose a color theme for the application. The theme affects the accent color "
|
|
"and overall appearance. Changes will take effect after restarting the application.",
|
|
themeGroup);
|
|
themeDesc->setWordWrap(true);
|
|
themeDesc->setStyleSheet("color: #888; font-size: 11px;");
|
|
themeLayout->addWidget(themeDesc);
|
|
|
|
layout->addWidget(themeGroup);
|
|
layout->addStretch();
|
|
|
|
m_pageStack->addWidget(page);
|
|
}
|
|
|
|
void PreferenceEditor::updateThemePreview()
|
|
{
|
|
Theme t = Settings::getTheme(m_themeCombo->currentText());
|
|
QString previewStyle = QString(
|
|
"background: qlineargradient(x1:0, y1:0, x2:1, y2:0, "
|
|
"stop:0 %1, stop:0.15 %1, stop:0.15 %2, stop:0.85 %2, stop:0.85 %3, stop:1 %3);"
|
|
"border: 2px solid %4; border-radius: 6px; color: %5; font-weight: bold;"
|
|
).arg(t.accentColor, t.backgroundColor, t.panelColor, t.borderColor, t.textColor);
|
|
m_themePreview->setStyleSheet(previewStyle);
|
|
m_themePreview->setText(t.name);
|
|
}
|
|
|
|
void PreferenceEditor::createGeneralPage()
|
|
{
|
|
auto *page = new QWidget(this);
|
|
auto *layout = new QVBoxLayout(page);
|
|
layout->setSpacing(15);
|
|
|
|
// Title
|
|
auto *titleLabel = new QLabel("General Settings", page);
|
|
titleLabel->setStyleSheet("font-size: 14px; font-weight: bold; color: #ad0c0c;");
|
|
layout->addWidget(titleLabel);
|
|
|
|
// Export settings group
|
|
auto *exportGroup = new QGroupBox("Export Settings", page);
|
|
auto *exportLayout = new QFormLayout(exportGroup);
|
|
exportLayout->setSpacing(10);
|
|
|
|
auto *dirLayout = new QHBoxLayout();
|
|
m_exportDirEdit = new QLineEdit(exportGroup);
|
|
m_exportDirEdit->setPlaceholderText("Export directory path...");
|
|
dirLayout->addWidget(m_exportDirEdit);
|
|
|
|
auto *browseBtn = new QPushButton("Browse...", exportGroup);
|
|
browseBtn->setFixedWidth(80);
|
|
connect(browseBtn, &QPushButton::clicked, this, &PreferenceEditor::onBrowseExportDir);
|
|
dirLayout->addWidget(browseBtn);
|
|
exportLayout->addRow("Export Directory:", dirLayout);
|
|
|
|
m_autoExportCheck = new QCheckBox("Automatically export resources when parsing", exportGroup);
|
|
exportLayout->addRow("", m_autoExportCheck);
|
|
|
|
layout->addWidget(exportGroup);
|
|
|
|
// View settings group
|
|
auto *viewGroup = new QGroupBox("View Settings", page);
|
|
auto *viewLayout = new QFormLayout(viewGroup);
|
|
viewLayout->setSpacing(10);
|
|
|
|
m_fontFamilyCombo = new QComboBox(viewGroup);
|
|
QStringList families = QFontDatabase::families();
|
|
for (const QString &family : families) {
|
|
if (QFontDatabase::isFixedPitch(family) || family.contains("Mono", Qt::CaseInsensitive) ||
|
|
family == "Segoe UI" || family == "Roboto" || family == "Arial") {
|
|
m_fontFamilyCombo->addItem(family);
|
|
}
|
|
}
|
|
viewLayout->addRow("Font Family:", m_fontFamilyCombo);
|
|
|
|
m_fontSizeSpin = new QSpinBox(viewGroup);
|
|
m_fontSizeSpin->setRange(8, 24);
|
|
m_fontSizeSpin->setSuffix(" pt");
|
|
viewLayout->addRow("Font Size:", m_fontSizeSpin);
|
|
|
|
m_zoomSpin = new QSpinBox(viewGroup);
|
|
m_zoomSpin->setRange(50, 200);
|
|
m_zoomSpin->setSuffix(" %");
|
|
m_zoomSpin->setSingleStep(10);
|
|
viewLayout->addRow("View Zoom:", m_zoomSpin);
|
|
|
|
layout->addWidget(viewGroup);
|
|
|
|
// Reset group
|
|
auto *resetGroup = new QGroupBox("Reset", page);
|
|
auto *resetLayout = new QVBoxLayout(resetGroup);
|
|
resetLayout->setSpacing(10);
|
|
|
|
auto *resetDesc = new QLabel(
|
|
"Reset all settings to their default values. This will restore the default theme (XPlor Dark) "
|
|
"and clear all customizations.",
|
|
resetGroup);
|
|
resetDesc->setWordWrap(true);
|
|
resetDesc->setStyleSheet("color: #888; font-size: 11px;");
|
|
resetLayout->addWidget(resetDesc);
|
|
|
|
auto *resetBtn = new QPushButton("Reset All Settings", resetGroup);
|
|
resetBtn->setStyleSheet("background-color: #8a0a0a;");
|
|
connect(resetBtn, &QPushButton::clicked, this, &PreferenceEditor::onResetSettings);
|
|
resetLayout->addWidget(resetBtn);
|
|
|
|
layout->addWidget(resetGroup);
|
|
layout->addStretch();
|
|
|
|
m_pageStack->addWidget(page);
|
|
}
|
|
|
|
void PreferenceEditor::createDebugPage()
|
|
{
|
|
auto *page = new QWidget(this);
|
|
auto *layout = new QVBoxLayout(page);
|
|
layout->setSpacing(15);
|
|
|
|
// Title
|
|
auto *titleLabel = new QLabel("Debug & Logging", page);
|
|
titleLabel->setStyleSheet("font-size: 14px; font-weight: bold; color: #ad0c0c;");
|
|
layout->addWidget(titleLabel);
|
|
|
|
// Logging group
|
|
auto *logGroup = new QGroupBox("Logging Options", page);
|
|
auto *logLayout = new QVBoxLayout(logGroup);
|
|
logLayout->setSpacing(10);
|
|
|
|
m_debugLoggingCheck = new QCheckBox("Enable debug logging", logGroup);
|
|
m_debugLoggingCheck->setToolTip("Log detailed parsing information to the Logs panel.\n"
|
|
"Shows parse positions, chunk processing, and tree routing.");
|
|
logLayout->addWidget(m_debugLoggingCheck);
|
|
|
|
m_verboseParsingCheck = new QCheckBox("Verbose parsing output", logGroup);
|
|
m_verboseParsingCheck->setToolTip("Show additional details during file parsing.\n"
|
|
"Includes field assignments and type information.");
|
|
logLayout->addWidget(m_verboseParsingCheck);
|
|
|
|
m_logToFileCheck = new QCheckBox("Save logs to file", logGroup);
|
|
m_logToFileCheck->setToolTip("Write all log entries to xplor.log in the application directory.");
|
|
logLayout->addWidget(m_logToFileCheck);
|
|
|
|
layout->addWidget(logGroup);
|
|
|
|
// Info label
|
|
auto *infoLabel = new QLabel(
|
|
"Debug logging provides detailed information about file parsing and "
|
|
"data processing. Enable this when troubleshooting issues with file "
|
|
"parsing or to understand how data is being processed.\n\n"
|
|
"Note: Extensive logging may affect performance with large files.",
|
|
page);
|
|
infoLabel->setWordWrap(true);
|
|
infoLabel->setStyleSheet("color: #888; padding: 10px; background-color: #252526; border-radius: 4px;");
|
|
layout->addWidget(infoLabel);
|
|
|
|
layout->addStretch();
|
|
|
|
m_pageStack->addWidget(page);
|
|
}
|
|
|
|
void PreferenceEditor::createTreePage()
|
|
{
|
|
auto *page = new QWidget(this);
|
|
auto *layout = new QVBoxLayout(page);
|
|
layout->setSpacing(15);
|
|
|
|
// Title
|
|
auto *titleLabel = new QLabel("Tree Browser", page);
|
|
titleLabel->setStyleSheet("font-size: 14px; font-weight: bold; color: #ad0c0c;");
|
|
layout->addWidget(titleLabel);
|
|
|
|
// Display group
|
|
auto *displayGroup = new QGroupBox("Display Options", page);
|
|
auto *displayLayout = new QVBoxLayout(displayGroup);
|
|
displayLayout->setSpacing(10);
|
|
|
|
m_showCountsCheck = new QCheckBox("Show item counts on categories", displayGroup);
|
|
m_showCountsCheck->setToolTip("Display the number of children next to category names.");
|
|
displayLayout->addWidget(m_showCountsCheck);
|
|
|
|
m_collapseDefaultCheck = new QCheckBox("Collapse items by default", displayGroup);
|
|
m_collapseDefaultCheck->setToolTip("New items are collapsed when added to the tree.");
|
|
displayLayout->addWidget(m_collapseDefaultCheck);
|
|
|
|
layout->addWidget(displayGroup);
|
|
|
|
// Organization group
|
|
auto *orgGroup = new QGroupBox("Organization", page);
|
|
auto *orgLayout = new QVBoxLayout(orgGroup);
|
|
orgLayout->setSpacing(10);
|
|
|
|
m_groupByExtCheck = new QCheckBox("Group resources by file extension", orgGroup);
|
|
m_groupByExtCheck->setToolTip("Organize resources into subfolders based on file extension (.wav, .tga, etc.)");
|
|
orgLayout->addWidget(m_groupByExtCheck);
|
|
|
|
m_naturalSortCheck = new QCheckBox("Natural sorting (1, 2, 10 instead of 1, 10, 2)", orgGroup);
|
|
m_naturalSortCheck->setToolTip("Sort items numerically when they contain numbers.");
|
|
orgLayout->addWidget(m_naturalSortCheck);
|
|
|
|
layout->addWidget(orgGroup);
|
|
layout->addStretch();
|
|
|
|
m_pageStack->addWidget(page);
|
|
}
|
|
|
|
void PreferenceEditor::createPreviewPage()
|
|
{
|
|
auto *page = new QWidget(this);
|
|
auto *layout = new QVBoxLayout(page);
|
|
layout->setSpacing(15);
|
|
|
|
// Title
|
|
auto *titleLabel = new QLabel("Preview Settings", page);
|
|
titleLabel->setStyleSheet("font-size: 14px; font-weight: bold; color: #ad0c0c;");
|
|
layout->addWidget(titleLabel);
|
|
|
|
// Audio group
|
|
auto *audioGroup = new QGroupBox("Audio Preview", page);
|
|
auto *audioLayout = new QVBoxLayout(audioGroup);
|
|
audioLayout->setSpacing(10);
|
|
|
|
m_audioAutoPlayCheck = new QCheckBox("Auto-play audio when selected", audioGroup);
|
|
audioLayout->addWidget(m_audioAutoPlayCheck);
|
|
|
|
layout->addWidget(audioGroup);
|
|
|
|
// Image group
|
|
auto *imageGroup = new QGroupBox("Image Preview", page);
|
|
auto *imageLayout = new QVBoxLayout(imageGroup);
|
|
imageLayout->setSpacing(10);
|
|
|
|
m_imageShowGridCheck = new QCheckBox("Show transparency grid", imageGroup);
|
|
m_imageShowGridCheck->setToolTip("Display a checkered grid behind transparent images.");
|
|
imageLayout->addWidget(m_imageShowGridCheck);
|
|
|
|
m_imageAutoZoomCheck = new QCheckBox("Auto-zoom to fit", imageGroup);
|
|
m_imageAutoZoomCheck->setToolTip("Automatically scale images to fit the preview area.");
|
|
imageLayout->addWidget(m_imageAutoZoomCheck);
|
|
|
|
layout->addWidget(imageGroup);
|
|
layout->addStretch();
|
|
|
|
m_pageStack->addWidget(page);
|
|
}
|
|
|
|
void PreferenceEditor::loadSettings()
|
|
{
|
|
Settings &s = Settings::instance();
|
|
|
|
// Appearance
|
|
int themeIdx = m_themeCombo->findText(s.currentTheme());
|
|
if (themeIdx >= 0) m_themeCombo->setCurrentIndex(themeIdx);
|
|
updateThemePreview();
|
|
|
|
// General
|
|
m_exportDirEdit->setText(s.exportDirectory());
|
|
m_autoExportCheck->setChecked(s.autoExportOnParse());
|
|
|
|
int fontIdx = m_fontFamilyCombo->findText(s.fontFamily());
|
|
if (fontIdx >= 0) m_fontFamilyCombo->setCurrentIndex(fontIdx);
|
|
m_fontSizeSpin->setValue(s.fontSize());
|
|
m_zoomSpin->setValue(s.viewZoom());
|
|
|
|
// Debug
|
|
m_debugLoggingCheck->setChecked(s.debugLoggingEnabled());
|
|
m_verboseParsingCheck->setChecked(s.verboseParsingEnabled());
|
|
m_logToFileCheck->setChecked(s.logToFileEnabled());
|
|
|
|
// Tree
|
|
m_showCountsCheck->setChecked(s.showItemCounts());
|
|
m_collapseDefaultCheck->setChecked(s.collapseByDefault());
|
|
m_groupByExtCheck->setChecked(s.groupByExtension());
|
|
m_naturalSortCheck->setChecked(s.naturalSorting());
|
|
|
|
// Previews
|
|
m_audioAutoPlayCheck->setChecked(s.audioAutoPlay());
|
|
m_imageShowGridCheck->setChecked(s.imageShowGrid());
|
|
m_imageAutoZoomCheck->setChecked(s.imageAutoZoom());
|
|
}
|
|
|
|
void PreferenceEditor::saveSettings()
|
|
{
|
|
Settings &s = Settings::instance();
|
|
|
|
// Appearance
|
|
s.setCurrentTheme(m_themeCombo->currentText());
|
|
|
|
// General
|
|
s.setExportDirectory(m_exportDirEdit->text());
|
|
s.setAutoExportOnParse(m_autoExportCheck->isChecked());
|
|
s.setFontFamily(m_fontFamilyCombo->currentText());
|
|
s.setFontSize(m_fontSizeSpin->value());
|
|
s.setViewZoom(m_zoomSpin->value());
|
|
|
|
// Debug
|
|
s.setDebugLoggingEnabled(m_debugLoggingCheck->isChecked());
|
|
s.setVerboseParsingEnabled(m_verboseParsingCheck->isChecked());
|
|
s.setLogToFileEnabled(m_logToFileCheck->isChecked());
|
|
|
|
// Tree
|
|
s.setShowItemCounts(m_showCountsCheck->isChecked());
|
|
s.setCollapseByDefault(m_collapseDefaultCheck->isChecked());
|
|
s.setGroupByExtension(m_groupByExtCheck->isChecked());
|
|
s.setNaturalSorting(m_naturalSortCheck->isChecked());
|
|
|
|
// Previews
|
|
s.setAudioAutoPlay(m_audioAutoPlayCheck->isChecked());
|
|
s.setImageShowGrid(m_imageShowGridCheck->isChecked());
|
|
s.setImageAutoZoom(m_imageAutoZoomCheck->isChecked());
|
|
|
|
s.sync();
|
|
}
|
|
|
|
void PreferenceEditor::applyStylesheet()
|
|
{
|
|
setStyleSheet(R"(
|
|
QDialog {
|
|
background-color: #1e1e1e;
|
|
color: #d4d4d4;
|
|
}
|
|
QListWidget {
|
|
background-color: #252526;
|
|
border: 1px solid #3c3c3c;
|
|
border-radius: 4px;
|
|
padding: 5px;
|
|
}
|
|
QListWidget::item {
|
|
padding: 8px;
|
|
border-radius: 3px;
|
|
}
|
|
QListWidget::item:selected {
|
|
background-color: #ad0c0c;
|
|
color: white;
|
|
}
|
|
QListWidget::item:hover:!selected {
|
|
background-color: #2d2d30;
|
|
}
|
|
QGroupBox {
|
|
font-weight: bold;
|
|
border: 1px solid #3c3c3c;
|
|
border-radius: 4px;
|
|
margin-top: 10px;
|
|
padding-top: 10px;
|
|
}
|
|
QGroupBox::title {
|
|
subcontrol-origin: margin;
|
|
left: 10px;
|
|
padding: 0 5px;
|
|
}
|
|
QCheckBox {
|
|
spacing: 8px;
|
|
}
|
|
QCheckBox::indicator {
|
|
width: 16px;
|
|
height: 16px;
|
|
}
|
|
QCheckBox::indicator:unchecked {
|
|
border: 1px solid #5c5c5c;
|
|
background-color: #2d2d30;
|
|
border-radius: 3px;
|
|
}
|
|
QCheckBox::indicator:checked {
|
|
background-color: #ad0c0c;
|
|
border: 1px solid #ad0c0c;
|
|
border-radius: 3px;
|
|
}
|
|
QLineEdit, QComboBox, QSpinBox {
|
|
background-color: #2d2d30;
|
|
border: 1px solid #3c3c3c;
|
|
border-radius: 3px;
|
|
padding: 5px;
|
|
min-height: 20px;
|
|
}
|
|
QLineEdit:focus, QComboBox:focus, QSpinBox:focus {
|
|
border-color: #ad0c0c;
|
|
}
|
|
QComboBox::drop-down {
|
|
border: none;
|
|
padding-right: 5px;
|
|
}
|
|
QPushButton {
|
|
background-color: #3c3c3c;
|
|
border: 1px solid #5c5c5c;
|
|
border-radius: 3px;
|
|
padding: 6px 15px;
|
|
min-width: 70px;
|
|
}
|
|
QPushButton:hover {
|
|
background-color: #4c4c4c;
|
|
}
|
|
QPushButton:pressed {
|
|
background-color: #ad0c0c;
|
|
}
|
|
QDialogButtonBox QPushButton {
|
|
min-width: 80px;
|
|
}
|
|
)");
|
|
}
|
|
|
|
void PreferenceEditor::onCategoryChanged()
|
|
{
|
|
m_pageStack->setCurrentIndex(m_categoryList->currentRow());
|
|
}
|
|
|
|
void PreferenceEditor::onApply()
|
|
{
|
|
saveSettings();
|
|
}
|
|
|
|
void PreferenceEditor::onAccept()
|
|
{
|
|
saveSettings();
|
|
accept();
|
|
}
|
|
|
|
void PreferenceEditor::onBrowseExportDir()
|
|
{
|
|
QString dir = QFileDialog::getExistingDirectory(this, "Select Export Directory",
|
|
m_exportDirEdit->text());
|
|
if (!dir.isEmpty()) {
|
|
m_exportDirEdit->setText(dir);
|
|
}
|
|
}
|
|
|
|
void PreferenceEditor::onResetSettings()
|
|
{
|
|
QMessageBox::StandardButton reply = QMessageBox::question(
|
|
this,
|
|
"Reset Settings",
|
|
"Are you sure you want to reset all settings to defaults?\n\n"
|
|
"This will restore the default theme and clear all customizations.",
|
|
QMessageBox::Yes | QMessageBox::No,
|
|
QMessageBox::No
|
|
);
|
|
|
|
if (reply == QMessageBox::Yes) {
|
|
Settings::instance().resetToDefaults();
|
|
loadSettings(); // Reload UI with defaults
|
|
QMessageBox::information(this, "Settings Reset", "All settings have been reset to defaults.");
|
|
}
|
|
}
|