| 69 | } // namespace |
| 70 | |
| 71 | PreferencesDialog::PreferencesDialog(Theme& theme, QWidget* parent) |
| 72 | : Dialog(parent), |
| 73 | ui_(new Ui::PreferencesContent), |
| 74 | theme_(theme), |
| 75 | original_theme_(theme.currentTheme()), |
| 76 | original_metrics_( |
| 77 | qobject_cast<MainWindow*>(parent) != nullptr ? qobject_cast<MainWindow*>(parent)->chromeMetrics() |
| 78 | : ChromeMetrics{}) { |
| 79 | setDialogTitle(tr("Preferences")); |
| 80 | // The Dialog content area already has its own (zero-margin) layout, so |
| 81 | // we instantiate the .ui onto a child body widget rather than setupUi(this). |
| 82 | auto* body = new QWidget; |
| 83 | ui_->setupUi(body); |
| 84 | contentLayout()->addWidget(body); |
| 85 | // Free the dialog to resize down. The base Dialog's top-level layout uses Qt's |
| 86 | // default SetDefaultConstraint, which on every activation forces the window's |
| 87 | // minimum size up to the layout's computed minimum — and with the Appearance |
| 88 | // page's Fixed-height scrubber rows that minimum is tall enough to block |
| 89 | // shrinking (and to override a smaller restored/explicit size). SetNoConstraint |
| 90 | // stops the layout from imposing that minimum (children still fill via their |
| 91 | // own layouts); the explicit minimum below is then the only floor. |
| 92 | if (auto* root = layout()) { |
| 93 | root->setSizeConstraint(QLayout::SetNoConstraint); |
| 94 | } |
| 95 | setMinimumSize(420, 300); |
| 96 | // Restore the user's last dialog size if they resized it before; otherwise a |
| 97 | // sensible default (room for the 160 px nav column + a comfortable page body). |
| 98 | // The dialog is resizable (edge-drag handled by the base class); geometry is |
| 99 | // saved on close (see the destructor). |
| 100 | { |
| 101 | QSettings settings; |
| 102 | const QByteArray geometry = settings.value(QStringLiteral("Preferences::dialog_geometry")).toByteArray(); |
| 103 | // A stale/corrupt blob (Qt upgrade, truncated .ini) makes restoreGeometry |
| 104 | // return false and apply nothing — fall back to the default size rather than |
| 105 | // opening off-screen or at 0x0. |
| 106 | if (geometry.isEmpty() || !restoreGeometry(geometry)) { |
| 107 | resize(560, 400); |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | // Populate the left-hand nav column. Each row is a click-target that |
| 112 | // switches pagesStack to the matching index. The trailing stretch in |
| 113 | // navLayout (added in .ui) pushes the rows to the top. |
| 114 | auto* nav_layout = qobject_cast<QVBoxLayout*>(ui_->navContainer->layout()); |
| 115 | const std::array<std::pair<QString, int>, 5> nav_entries{{ |
| 116 | {tr("Appearance"), 0}, |
| 117 | {tr("Plotting"), 1}, |
| 118 | {tr("Scene 2D"), 2}, |
| 119 | {tr("Scene 3D"), 3}, |
| 120 | {tr("Plugins"), 4}, |
| 121 | }}; |
| 122 | nav_rows_.reserve(nav_entries.size()); |
| 123 | for (const auto& [label, index] : nav_entries) { |
| 124 | auto* row = new PreferencesNavRow(label, ui_->navContainer); |
| 125 | nav_layout->insertWidget(static_cast<int>(nav_rows_.size()), row); |
| 126 | nav_rows_.push_back(row); |
| 127 | connect(row, &PreferencesNavRow::clicked, this, [this, row, index]() { |
| 128 | for (auto* other : nav_rows_) { |
nothing calls this directly
no test coverage detected