diff --git a/mainwindow.cpp b/mainwindow.cpp index fda3072..2852fc2 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -341,6 +341,8 @@ MainWindow::MainWindow(QTranslator* startupTranslator, QWidget* parent) // remove this override — see settingsdialog.cpp buildUi. m_settings.xMinimizesApp = false; m_settings.launchOnStartup = m_persist.value("window/launchOnStartup", false).toBool(); + m_settings.minimalWidth = m_persist.value("window/minimalWidth", false).toBool(); + m_settings.minimalWidthPx = m_persist.value("window/minimalWidthPx", 0).toInt(); m_settings.audioFeedback = m_persist.value("audio/enabled", false).toBool(); m_settings.showClickIndicator = m_persist.value("visual/clickIndicator", AppSettings{}.showClickIndicator).toBool(); m_settings.audioClickEnabled = m_persist.value("audioClick/enabled", false).toBool(); @@ -1130,6 +1132,16 @@ void MainWindow::rebuildButtons() lay->activate(); adjustSize(); + + // Minimal width with an explicit pixel limit overrides the natural + // (sizeHint-driven) width computed by adjustSize() above. Floored to the + // title bar's own minimum so its controls (settings/exit/status dot) + // never become unreachable — that floor is the one clipping guarantee + // that survives a user-chosen limit; button/label text is not protected. + if (m_settings.minimalWidth && m_settings.minimalWidthPx > 0) { + const int floorPx = m_titleBar ? m_titleBar->minimumSizeHint().width() : 0; + resize(qMax(m_settings.minimalWidthPx, floorPx), height()); + } } ClickButton* MainWindow::makeButton(const QString& label, const QString& tooltip, ClickType type, const QString& iconName) @@ -1295,6 +1307,13 @@ MainWindow::ResizeEdge MainWindow::edgeAt(QPoint p) const const bool onR = p.x() >= r.width() - m; const bool onT = p.y() <= m; const bool onB = p.y() >= r.height() - m; + if (m_settings.minimalWidth) { + // Width is locked to its natural minimum: offer vertical-only resize, + // never the horizontal (or diagonal) edges/corners. + if (onT) return ResizeEdge::Top; + if (onB) return ResizeEdge::Bottom; + return ResizeEdge::None; + } if (onT && onL) return ResizeEdge::TopLeft; if (onT && onR) return ResizeEdge::TopRight; if (onB && onL) return ResizeEdge::BottomLeft; @@ -1998,6 +2017,8 @@ void MainWindow::applySettings(const AppSettings& s) m_persist.setValue("window/startMin", s.startMinimized); m_persist.setValue("window/xMinimizesApp", s.xMinimizesApp); m_persist.setValue("window/launchOnStartup", s.launchOnStartup); + m_persist.setValue("window/minimalWidth", s.minimalWidth); + m_persist.setValue("window/minimalWidthPx", s.minimalWidthPx); // Reconcile unconditionally: the registry/autostart entry must match the // setting even when it is unchanged here but was lost externally, never // written by an older build, or points at a stale executable path. diff --git a/settingsdialog.cpp b/settingsdialog.cpp index a4caa4b..54c165c 100644 --- a/settingsdialog.cpp +++ b/settingsdialog.cpp @@ -650,6 +650,9 @@ void SettingsDialog::retranslateUi() m_chkStartMinimized->setText(tr("Start minimized to tray")); m_chkXMinimizesApp->setText(tr("Top X minimizes app")); m_chkLaunchOnStartup->setText(tr("Launch on system startup (Windows)")); + m_chkMinimalWidth->setText(tr("Minimal width")); + m_lblMinimalWidthPx->setText(tr("Width limit (px):")); + m_spinMinimalWidthPx->setSpecialValueText(tr("Auto (fit content)")); m_chkAudio->setText(tr("Audio feedback on click")); m_chkClickIndicator->setText(tr("Show click indicator ring (Windows)")); m_chkShowLabels->setText(tr("Show button labels")); @@ -1045,6 +1048,18 @@ void SettingsDialog::buildUi() m_chkStartMinimized = new QCheckBox(tr("Start minimized to tray")); m_chkXMinimizesApp = new QCheckBox(tr("Top X minimizes app")); m_chkLaunchOnStartup= new QCheckBox(tr("Launch on system startup (Windows)")); + m_chkMinimalWidth = new QCheckBox(tr("Minimal width")); + m_lblMinimalWidthPx = new QLabel(tr("Width limit (px):")); + m_spinMinimalWidthPx = new QSpinBox; + m_spinMinimalWidthPx->setRange(0, 2000); + m_spinMinimalWidthPx->setSingleStep(10); + m_spinMinimalWidthPx->setSpecialValueText(tr("Auto (fit content)")); + m_lblMinimalWidthPx->setEnabled(false); + m_spinMinimalWidthPx->setEnabled(false); + connect(m_chkMinimalWidth, &QCheckBox::toggled, this, [this](bool on){ + m_lblMinimalWidthPx->setEnabled(on); + m_spinMinimalWidthPx->setEnabled(on); + }); behForm->addRow(m_lblEdgeLock, m_cmbEdgeLock); behForm->addRow(m_chkEdgeHide); @@ -1054,6 +1069,8 @@ void SettingsDialog::buildUi() // (load/save/retranslate refs) but are hidden from the UI — the top X always // quits. To restore the option, add it back to the layout here. behForm->addRow(m_chkLaunchOnStartup); + behForm->addRow(m_chkMinimalWidth); + behForm->addRow(m_lblMinimalWidthPx, m_spinMinimalWidthPx); winCol->addWidget(m_grpWinBehavior); // ── Section: Button Controls ────────────────────────────── @@ -1632,6 +1649,10 @@ void SettingsDialog::loadFrom(const AppSettings& s) // Top X minimizes app is intentionally left read-only and unchecked (see // buildUi); don't drive it from settings. Restore this line to re-enable. m_chkLaunchOnStartup->setChecked(s.launchOnStartup); + m_chkMinimalWidth->setChecked(s.minimalWidth); + m_spinMinimalWidthPx->setValue(s.minimalWidthPx); + m_lblMinimalWidthPx->setEnabled(s.minimalWidth); + m_spinMinimalWidthPx->setEnabled(s.minimalWidth); m_chkAudio->setChecked(s.audioFeedback); m_chkClickIndicator->setChecked(s.showClickIndicator); m_chkShowLabels->setChecked(!s.iconsOnly); // checked = labels shown @@ -1695,6 +1716,8 @@ AppSettings SettingsDialog::readUi() const s.startMinimized = m_chkStartMinimized->isChecked(); s.xMinimizesApp = m_chkXMinimizesApp->isChecked(); s.launchOnStartup = m_chkLaunchOnStartup->isChecked(); + s.minimalWidth = m_chkMinimalWidth->isChecked(); + s.minimalWidthPx = m_spinMinimalWidthPx->value(); s.audioFeedback = m_chkAudio->isChecked(); s.showClickIndicator = m_chkClickIndicator->isChecked(); s.iconsOnly = !m_chkShowLabels->isChecked(); // unchecked = icons only diff --git a/settingsdialog.h b/settingsdialog.h index 6cd500f..fa7cb36 100644 --- a/settingsdialog.h +++ b/settingsdialog.h @@ -75,6 +75,13 @@ struct AppSettings { bool startMinimized = false; bool xMinimizesApp = false; bool launchOnStartup = false; + // Locks the window width and disables horizontal edge/corner resizing. + // minimalWidthPx == 0 means "auto": fit the natural content width + // (sizeHint) with no clipping. A positive value forces that exact width + // instead — the user's explicit choice, so unlike the auto case it is not + // guaranteed clip-free (only floored to keep the title bar controls usable). + bool minimalWidth = false; + int minimalWidthPx = 0; // Audio feedback bool audioFeedback = false; @@ -243,6 +250,9 @@ class SettingsDialog : public QDialog QCheckBox* m_chkStartMinimized; QCheckBox* m_chkXMinimizesApp; QCheckBox* m_chkLaunchOnStartup; + QCheckBox* m_chkMinimalWidth; + QLabel* m_lblMinimalWidthPx = nullptr; + QSpinBox* m_spinMinimalWidthPx = nullptr; QCheckBox* m_chkAudio; QCheckBox* m_chkClickIndicator; // "Show button labels" — the inverse of AppSettings::iconsOnly (checked = diff --git a/translations/trackclick_ar.ts b/translations/trackclick_ar.ts index d15446a..46f607c 100644 --- a/translations/trackclick_ar.ts +++ b/translations/trackclick_ar.ts @@ -114,6 +114,9 @@ Top X minimizes appزر X العلوي يصغّر التطبيق Close applicationإغلاق التطبيق Launch on system startup (Windows)التشغيل عند بدء تشغيل النظام (Windows) + Minimal widthالحد الأدنى للعرض + Width limit (px):حد العرض (بكسل): + Auto (fit content)تلقائي (يلائم المحتوى) Audio feedback on clickردود فعل صوتية عند النقر Icons only (hide button labels)أيقونات فقط (إخفاء تسميات الأزرار) Large buttonsأزرار كبيرة diff --git a/translations/trackclick_bn.ts b/translations/trackclick_bn.ts index 8df1ee7..4a04b0c 100644 --- a/translations/trackclick_bn.ts +++ b/translations/trackclick_bn.ts @@ -114,6 +114,9 @@ Top X minimizes appউপরের X অ্যাপ ছোট করে Close applicationঅ্যাপ্লিকেশন বন্ধ করুন Launch on system startup (Windows)সিস্টেম স্টার্টআপে চালু করুন (Windows) + Minimal widthসর্বনিম্ন প্রস্থ + Width limit (px):প্রস্থের সীমা (px): + Auto (fit content)স্বয়ংক্রিয় (বিষয়বস্তু অনুযায়ী) Audio feedback on clickক্লিকে অডিও ফিডব্যাক Icons only (hide button labels)শুধু আইকন (বোতামের লেবেল লুকান) Large buttonsবড় বোতাম diff --git a/translations/trackclick_cs.ts b/translations/trackclick_cs.ts index 7b99db6..abc712f 100644 --- a/translations/trackclick_cs.ts +++ b/translations/trackclick_cs.ts @@ -115,6 +115,9 @@ Scroll repeat:Opakování rolování: Repeat click:Opakovat kliknutí: Launch on system startup (Windows)Spustit při startu systému (Windows) + Minimal widthMinimální šířka + Width limit (px):Omezení šířky (px): + Auto (fit content)Automaticky (podle obsahu) Open On-Screen KeyboardOtevřít klávesnici na obrazovce No on-screen keyboard was found. Please install 'onboard' or 'florence'.Klávesnice na obrazovce nebyla nalezena. diff --git a/translations/trackclick_es.ts b/translations/trackclick_es.ts index bf497c4..e9639cd 100644 --- a/translations/trackclick_es.ts +++ b/translations/trackclick_es.ts @@ -113,6 +113,9 @@ Scroll repeat:Repetición de desplazamiento: Repeat click:Repetir clic: Launch on system startup (Windows)Iniciar con el sistema (Windows) + Minimal widthAncho mínimo + Width limit (px):Límite de ancho (px): + Auto (fit content)Automático (ajustar al contenido) Open On-Screen KeyboardAbrir teclado en pantalla No on-screen keyboard was found. Please install 'onboard' or 'florence'.No se encontró ningún teclado en pantalla. diff --git a/translations/trackclick_fr.ts b/translations/trackclick_fr.ts index 3254daa..f86cded 100644 --- a/translations/trackclick_fr.ts +++ b/translations/trackclick_fr.ts @@ -113,6 +113,9 @@ Scroll repeat:Répétition du défilement : Repeat click:Répétition du clic : Launch on system startup (Windows)Lancer au démarrage du système (Windows) + Minimal widthLargeur minimale + Width limit (px):Largeur limite (px) : + Auto (fit content)Auto (ajusté au contenu) Open On-Screen KeyboardOuvrir le clavier virtuel No on-screen keyboard was found. Please install 'onboard' or 'florence'.Aucun clavier virtuel trouvé. diff --git a/translations/trackclick_hi.ts b/translations/trackclick_hi.ts index 1710e0b..b3f061c 100644 --- a/translations/trackclick_hi.ts +++ b/translations/trackclick_hi.ts @@ -114,6 +114,9 @@ Top X minimizes appऊपरी X एप्प को छोटा करता है Close applicationएप्लिकेशन बंद करें Launch on system startup (Windows)सिस्टम स्टार्टअप पर लॉन्च करें (Windows) + Minimal widthन्यूनतम चौड़ाई + Width limit (px):चौड़ाई सीमा (px): + Auto (fit content)स्वतः (सामग्री के अनुरूप) Audio feedback on clickक्लिक पर ऑडियो फीडबैक Icons only (hide button labels)केवल आइकन (बटन लेबल छुपाएं) Large buttonsबड़े बटन diff --git a/translations/trackclick_ja.ts b/translations/trackclick_ja.ts index 00ac740..5f932e0 100644 --- a/translations/trackclick_ja.ts +++ b/translations/trackclick_ja.ts @@ -113,6 +113,9 @@ Scroll repeat:スクロール繰り返し: Repeat click:クリック繰り返し: Launch on system startup (Windows)システム起動時に起動 (Windows) + Minimal width最小幅 + Width limit (px):幅の上限 (px): + Auto (fit content)自動(内容に合わせる) Open On-Screen Keyboardスクリーンキーボードを開く No on-screen keyboard was found. Please install 'onboard' or 'florence'.スクリーンキーボードが見つかりませんでした。 diff --git a/translations/trackclick_ko.ts b/translations/trackclick_ko.ts index d1e0460..75ec193 100644 --- a/translations/trackclick_ko.ts +++ b/translations/trackclick_ko.ts @@ -113,6 +113,9 @@ Scroll repeat:스크롤 반복: Repeat click:클릭 반복: Launch on system startup (Windows)시스템 시작 시 실행 (Windows) + Minimal width최소 너비 + Width limit (px):너비 제한 (px): + Auto (fit content)자동 (내용에 맞춤) Open On-Screen Keyboard화상 키보드 열기 No on-screen keyboard was found. Please install 'onboard' or 'florence'.화상 키보드를 찾을 수 없습니다. diff --git a/translations/trackclick_pt.ts b/translations/trackclick_pt.ts index a0959f7..c85854a 100644 --- a/translations/trackclick_pt.ts +++ b/translations/trackclick_pt.ts @@ -114,6 +114,9 @@ Top X minimizes appX superior minimiza o app Close applicationFechar aplicação Launch on system startup (Windows)Iniciar com o sistema (Windows) + Minimal widthLargura mínima + Width limit (px):Limite de largura (px): + Auto (fit content)Automático (ajustar ao conteúdo) Audio feedback on clickFeedback de áudio ao clicar Icons only (hide button labels)Apenas ícones (ocultar rótulos) Large buttonsBotões grandes diff --git a/translations/trackclick_ru.ts b/translations/trackclick_ru.ts index 9aeb382..f17c861 100644 --- a/translations/trackclick_ru.ts +++ b/translations/trackclick_ru.ts @@ -114,6 +114,9 @@ Top X minimizes appКрестик сворачивает приложение Close applicationЗакрыть приложение Launch on system startup (Windows)Запускать при старте системы (Windows) + Minimal widthМинимальная ширина + Width limit (px):Ограничение ширины (px): + Auto (fit content)Авто (по содержимому) Audio feedback on clickЗвуковой отклик при нажатии Icons only (hide button labels)Только иконки (скрыть надписи кнопок) Large buttonsКрупные кнопки diff --git a/translations/trackclick_ur.ts b/translations/trackclick_ur.ts index 5a529a3..e1a2158 100644 --- a/translations/trackclick_ur.ts +++ b/translations/trackclick_ur.ts @@ -114,6 +114,9 @@ Top X minimizes appاوپر X ایپ کو چھوٹا کرتا ہے Close applicationایپلیکیشن بند کریں Launch on system startup (Windows)سسٹم اسٹارٹ پر لانچ کریں (Windows) + Minimal widthکم از کم چوڑائی + Width limit (px):چوڑائی کی حد (px): + Auto (fit content)خودکار (مواد کے مطابق) Audio feedback on clickکلک پر آڈیو فیڈبیک Icons only (hide button labels)صرف آئیکن (بٹن لیبل چھپائیں) Large buttonsبڑے بٹن diff --git a/translations/trackclick_zh_CN.ts b/translations/trackclick_zh_CN.ts index ac3b51b..b3f2f6c 100644 --- a/translations/trackclick_zh_CN.ts +++ b/translations/trackclick_zh_CN.ts @@ -113,6 +113,9 @@ Scroll repeat:滚动重复次数: Repeat click:重复点击: Launch on system startup (Windows)开机自动启动 (Windows) + Minimal width最小宽度 + Width limit (px):宽度限制(像素): + Auto (fit content)自动(适应内容) Open On-Screen Keyboard打开屏幕键盘 No on-screen keyboard was found. Please install 'onboard' or 'florence'.未找到屏幕键盘。