From 05487d37b1f3b0bd8440b86b43d26e310182f87b Mon Sep 17 00:00:00 2001 From: Ben Haller Date: Sun, 19 Jan 2025 10:29:14 -0600 Subject: [PATCH] add a "page guide" pref in SLiMgui, at a specified column --- QtSLiM/QtSLiMPreferences.cpp | 42 +++++++++++++++++++++++ QtSLiM/QtSLiMPreferences.h | 5 +++ QtSLiM/QtSLiMPreferences.ui | 60 ++++++++++++++++++++++++++++++--- QtSLiM/QtSLiMScriptTextEdit.cpp | 57 +++++++++++++++++++++++++++++++ QtSLiM/QtSLiMScriptTextEdit.h | 1 + VERSIONS | 1 + 6 files changed, 162 insertions(+), 4 deletions(-) diff --git a/QtSLiM/QtSLiMPreferences.cpp b/QtSLiM/QtSLiMPreferences.cpp index 402ae7f0..5dc7cd0a 100644 --- a/QtSLiM/QtSLiMPreferences.cpp +++ b/QtSLiM/QtSLiMPreferences.cpp @@ -41,6 +41,8 @@ static const char *QtSLiMDisplayFontSize = "QtSLiMDisplayFontSize"; static const char *QtSLiMSyntaxHighlightScript = "QtSLiMSyntaxHighlightScript"; static const char *QtSLiMSyntaxHighlightOutput = "QtSLiMSyntaxHighlightOutput"; static const char *QtSLiMShowLineNumbers = "QtSLiMShowLineNumbers"; +static const char *QtSLiMShowPageGuide = "QtSLiMShowPageGuide"; +static const char *QtSLiMPageGuideColumn = "QtSLiMPageGuideColumn"; static const char *QtSLiMHighlightCurrentLine = "QtSLiMHighlightCurrentLine"; static const char *QtSLiMAutosaveOnRecycle = "QtSLiMAutosaveOnRecycle"; static const char *QtSLiMShowSaveInUntitled = "QtSLiMShowSaveInUntitled"; @@ -194,6 +196,20 @@ bool QtSLiMPreferencesNotifier::highlightCurrentLinePref(void) const return settings.value(QtSLiMHighlightCurrentLine, QVariant(true)).toBool(); } +bool QtSLiMPreferencesNotifier::showPageGuidePref(void) const +{ + QSettings settings; + + return settings.value(QtSLiMShowPageGuide, QVariant(false)).toBool(); +} + +int QtSLiMPreferencesNotifier::pageGuideColumnPref(void) const +{ + QSettings settings; + + return settings.value(QtSLiMPageGuideColumn, QVariant(80)).toInt(); +} + bool QtSLiMPreferencesNotifier::autosaveOnRecyclePref(void) const { QSettings settings; @@ -368,6 +384,25 @@ void QtSLiMPreferencesNotifier::highlightCurrentLineToggled() emit highlightCurrentLinePrefChanged(); } +void QtSLiMPreferencesNotifier::showPageGuideToggled() +{ + QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance(); + QSettings settings; + + settings.setValue(QtSLiMShowPageGuide, QVariant(prefsUI.ui->showPageGuide->isChecked())); + + emit pageGuidePrefsChanged(); +} + +void QtSLiMPreferencesNotifier::pageGuideColumnChanged(int newColumn) +{ + QSettings settings; + + settings.setValue(QtSLiMPageGuideColumn, QVariant(newColumn)); + + emit pageGuidePrefsChanged(); +} + void QtSLiMPreferencesNotifier::autosaveOnRecycleToggled() { QtSLiMPreferences &prefsUI = QtSLiMPreferences::instance(); @@ -454,6 +489,11 @@ QtSLiMPreferences::QtSLiMPreferences(QWidget *p_parent) : QDialog(p_parent), ui( ui->showLineNumbers->setChecked(notifier->showLineNumbersPref()); ui->highlightCurrentLine->setChecked(notifier->highlightCurrentLinePref()); + // the presence of this hidden widget fixes a padding bug; see https://forum.qt.io/topic/10757/unwanted-padding-around-qhboxlayout + ui->pageGuideNoPadWidget->hide(); + ui->showPageGuide->setChecked(notifier->showPageGuidePref()); + ui->pageGuideSpinBox->setValue(notifier->pageGuideColumnPref()); + ui->autosaveOnRecycle->setChecked(notifier->autosaveOnRecyclePref()); ui->showSaveIfUntitled->setChecked(notifier->showSaveIfUntitledPref()); ui->showSaveIfUntitled->setEnabled(notifier->autosaveOnRecyclePref()); @@ -472,6 +512,8 @@ QtSLiMPreferences::QtSLiMPreferences(QWidget *p_parent) : QDialog(p_parent), ui( connect(ui->showLineNumbers, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::showLineNumbersToggled); connect(ui->highlightCurrentLine, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::highlightCurrentLineToggled); + connect(ui->showPageGuide, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::showPageGuideToggled); + connect(ui->pageGuideSpinBox, QOverload::of(&QSpinBox::valueChanged), notifier, &QtSLiMPreferencesNotifier::pageGuideColumnChanged); connect(ui->autosaveOnRecycle, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::autosaveOnRecycleToggled); connect(ui->showSaveIfUntitled, &QCheckBox::toggled, notifier, &QtSLiMPreferencesNotifier::showSaveIfUntitledToggled); diff --git a/QtSLiM/QtSLiMPreferences.h b/QtSLiM/QtSLiMPreferences.h index 724d6bb4..82b0bbc5 100644 --- a/QtSLiM/QtSLiMPreferences.h +++ b/QtSLiM/QtSLiMPreferences.h @@ -42,6 +42,8 @@ class QtSLiMPreferencesNotifier : public QObject bool scriptSyntaxHighlightPref(void) const; bool outputSyntaxHighlightPref(void) const; bool showLineNumbersPref(void) const; + bool showPageGuidePref(void) const; + int pageGuideColumnPref(void) const; bool highlightCurrentLinePref(void) const; bool autosaveOnRecyclePref(void) const; bool reloadOnSafeExternalEditsPref(void) const; @@ -59,6 +61,7 @@ class QtSLiMPreferencesNotifier : public QObject void scriptSyntaxHighlightPrefChanged(void); void outputSyntaxHighlightPrefChanged(void); void showLineNumbersPrefChanged(void); + void pageGuidePrefsChanged(void); void highlightCurrentLinePrefChanged(void); void autosaveOnRecyclePrefChanged(void); void reloadOnSafeExternalEditsChanged(void); @@ -81,6 +84,8 @@ private slots: void syntaxHighlightScriptToggled(); void syntaxHighlightOutputToggled(); void showLineNumbersToggled(); + void showPageGuideToggled(); + void pageGuideColumnChanged(int newColumn); void highlightCurrentLineToggled(); void autosaveOnRecycleToggled(); void reloadOnSafeExternalEditsToggled(); diff --git a/QtSLiM/QtSLiMPreferences.ui b/QtSLiM/QtSLiMPreferences.ui index 37f21a62..6a8b7e17 100644 --- a/QtSLiM/QtSLiMPreferences.ui +++ b/QtSLiM/QtSLiMPreferences.ui @@ -7,7 +7,7 @@ 0 0 303 - 747 + 780 @@ -279,7 +279,7 @@ - Qt::NoFocus + Qt::StrongFocus the font size to use for script and output views @@ -419,9 +419,9 @@ QGroupBox { font-weight: bold; } - Line numbering: + Script view appearance: - + 6 @@ -457,6 +457,58 @@ + + + + + + + + + Page guide at column: + + + + + + + + 55 + 0 + + + + Qt::StrongFocus + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1 + + + 999 + + + 80 + + + + + + + Qt::Horizontal + + + + 5 + 5 + + + + + + diff --git a/QtSLiM/QtSLiMScriptTextEdit.cpp b/QtSLiM/QtSLiMScriptTextEdit.cpp index 19e8abef..85c522ec 100644 --- a/QtSLiM/QtSLiMScriptTextEdit.cpp +++ b/QtSLiM/QtSLiMScriptTextEdit.cpp @@ -2548,6 +2548,11 @@ void QtSLiMScriptTextEdit::sharedInit(void) setCenterOnScroll(true); initializeLineNumbers(); + + // set up to listen to changes to page guide prefs + QtSLiMPreferencesNotifier &prefsNotifier = QtSLiMPreferencesNotifier::instance(); + + connect(&prefsNotifier, &QtSLiMPreferencesNotifier::pageGuidePrefsChanged, this, [this]() { viewport()->update(); }); } void QtSLiMScriptTextEdit::initializeLineNumbers(void) @@ -3391,6 +3396,58 @@ QString QtSLiMScriptTextEdit::exportAsHtml(void) return html; } +void QtSLiMScriptTextEdit::paintEvent(QPaintEvent *event) +{ + // If the user wants a "page guide", show a slightly dimmed margin beyond a threshold column + // Note that Qt has already cleared to the white background of the QTextEdit + QtSLiMPreferencesNotifier &prefs = QtSLiMPreferencesNotifier::instance(); + bool showPageGuide = prefs.showPageGuidePref(); + + if (showPageGuide) + { + QFont displayFont = prefs.displayFontPref(); + QFontMetricsF fm(displayFont); + double marginStart; + QString marginString(prefs.pageGuideColumnPref(), ' '); + +#if (QT_VERSION < QT_VERSION_CHECK(5, 11, 0)) + marginStart = fm.width(marginString); // deprecated in 5.11 +#else + marginStart = fm.horizontalAdvance(marginString); // added in Qt 5.11 +#endif + + // adjust by the document margin, which is built into QTextDocument; this took a while to find! + // this is an inset of the QTextEdit's contents, on all four sides; it defaults to 4, which we do not change + QTextDocument *doc = document(); + double docMargin = doc->documentMargin(); + + marginStart += docMargin; + marginStart = round(marginStart); + + QRect bounds = rect(); + + if (bounds.width() >= marginStart) + { + // Because QTextEdit's display lives inside a scrollable area, we use viewport() + QPainter painter(this->viewport()); + + QRect margin = bounds.adjusted(marginStart, 0, 0, 0); + QRect marginEdge = margin; + + // draw a one-pixel darker line at the border + marginEdge.setWidth(1); + margin.adjust(1, 0, 0, 0); + + painter.fillRect(marginEdge, QtSLiMColorWithWhite(0.918, 1.0)); + painter.fillRect(margin, QtSLiMColorWithWhite(0.980, 1.0)); + } + } + + // call super to have it paint; this draws all the text and everything + QtSLiMTextEdit::paintEvent(event); +} + + diff --git a/QtSLiM/QtSLiMScriptTextEdit.h b/QtSLiM/QtSLiMScriptTextEdit.h index 282c875e..5db87277 100644 --- a/QtSLiM/QtSLiMScriptTextEdit.h +++ b/QtSLiM/QtSLiMScriptTextEdit.h @@ -221,6 +221,7 @@ public slots: void sharedInit(void); void initializeLineNumbers(void); virtual void resizeEvent(QResizeEvent *p_event) override; + virtual void paintEvent(QPaintEvent *event) override; protected slots: virtual void displayFontPrefChanged() override; diff --git a/VERSIONS b/VERSIONS index 20728ba0..43b00f8b 100644 --- a/VERSIONS +++ b/VERSIONS @@ -7,6 +7,7 @@ Note that not every commit will be logged here; that is what the Github commit h development head (in the master branch): fix the wiring for calcPi() and calcTajimasD() to call the correct code; they were broken in SLiM 4.3 + add a "page guide at column" pref to SLiMgui, for those trying to lay out code to a maximum width multi-chromosome transition: API changes: x class Genome -> class Haplosome