From 47068f41971658a552c2495052028f3db8e68524 Mon Sep 17 00:00:00 2001 From: jackson <63016612+fairybow@users.noreply.github.com> Date: Fri, 24 Feb 2023 11:06:52 -0500 Subject: [PATCH] Typewriter & center on scroll :tophat: - Updated Readme - Added UserData / MainWindow menu options for Cursor "center on scroll" and "Typewriter" positioning - Rewrote how Splitter/SplitterHandle handle initialization - Added Splitter::hasHover check - Added the toggling methods for Cursor COS/Typewriter to PlainTextEdit/Editor --- Fernanda/docs/Notes.md | 9 ++++++- Fernanda/docs/To-do.md | 3 +++ Fernanda/source/Editor.cpp | 23 +++++++++++++----- Fernanda/source/Editor.h | 8 +++++-- Fernanda/source/MainWindow.cpp | 14 ++++++++--- Fernanda/source/PlainTextEdit.cpp | 12 ++++++++-- Fernanda/source/PlainTextEdit.h | 7 ++++-- Fernanda/source/Splitter.cpp | 39 ++++++++++++++----------------- Fernanda/source/Splitter.h | 3 ++- Fernanda/source/SplitterHandle.h | 5 ++-- Fernanda/source/UserData.cpp | 6 +++++ Fernanda/source/UserData.h | 2 ++ Fernanda/source/Version.h | 4 ++-- README.md | 19 ++++++++------- 14 files changed, 101 insertions(+), 53 deletions(-) diff --git a/Fernanda/docs/Notes.md b/Fernanda/docs/Notes.md index 4b1e600..71f9060 100644 --- a/Fernanda/docs/Notes.md +++ b/Fernanda/docs/Notes.md @@ -13,4 +13,11 @@ C++20
-

\ No newline at end of file +

+ +``` +auto view = viewport(); +auto height = view->height(); +auto y = (height / 2) - cursorRect().y(); +viewport()->setGeometry(view->x(), y, view->width(), height); +``` diff --git a/Fernanda/docs/To-do.md b/Fernanda/docs/To-do.md index d9d57ca..e42c0e2 100644 --- a/Fernanda/docs/To-do.md +++ b/Fernanda/docs/To-do.md @@ -82,6 +82,8 @@ - [x] ~~Probably should combine `elements()` and `elementsByAttribute()`~~ ### Editor / PlainTextEdit / LineNumberArea +- [ ] "Ribbon" mode +- [ ] A toggleable for every relevant `QPlainTextEdit` toggleable (`centerOnScroll` for example) - [ ] It is not clear to me that `updateLineNumberAreaWidth(int newBlockCount)` actually uses `newBlockCount` arg - [ ] Save undo/redo stacks - [ ] Editor spacing and kerning sliders @@ -91,6 +93,7 @@ - [ ] Wrap for parentheses and other closables - [ ] If a filter was just applied, backspace should function as undo - [ ] Make thin cursor change color when there's a selection? +- [x] ~~Typewriter mode~~ - [x] ~~Avoid passing entire document for cursor underpaint lol~~ - [x] ~~Toggle chonky cursor vs regular~~ - [x] ~~Style horizontal scrollbar~~ diff --git a/Fernanda/source/Editor.cpp b/Fernanda/source/Editor.cpp index 4373fea..5452bb3 100644 --- a/Fernanda/source/Editor.cpp +++ b/Fernanda/source/Editor.cpp @@ -58,16 +58,25 @@ void Editor::devRemoveStyle() void Editor::toggle(bool checked, Has has) { switch (has) { - case Has::BlockCursor: - hasBlockCursor = checked; - plainTextEdit->cursorPositionChanged(); - UserData::saveConfig(UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorBlock, checked); - break; case Has::CursorBlink: hasCursorBlink = checked; startBlinker(); UserData::saveConfig(UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorBlink, checked); break; + case Has::CursorBlock: + hasCursorBlock = checked; + plainTextEdit->cursorPositionChanged(); + UserData::saveConfig(UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorBlock, checked); + break; + case Has::CursorCenterOnScroll: + askToggleCenterOnScroll(checked); + UserData::saveConfig(UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorCenterOnScroll, checked); + break; + case Has::CursorTypewriter: + hasCursorTypewriter = checked; + plainTextEdit->textChanged(); + UserData::saveConfig(UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorTypewriter, checked); + break; case Has::ExtraScrolls: askToggleExtraScrolls(checked); UserData::saveConfig(UserData::IniGroup::Editor, UserData::IniValue::ToggleScrollsPrevNext, checked); @@ -185,6 +194,7 @@ void Editor::close(bool isFinal) void Editor::connections() { + connect(this, &Editor::askToggleCenterOnScroll, plainTextEdit, &PlainTextEdit::toggleCenterOnScroll); connect(this, &Editor::askToggleLineNumberArea, plainTextEdit, &PlainTextEdit::toggleLineNumberArea); connect(this, &Editor::askToggleScrolls, plainTextEdit, &PlainTextEdit::toggleScrolls); connect(this, &Editor::askToggleExtraScrolls, plainTextEdit, &PlainTextEdit::toggleExtraScrolls); @@ -205,7 +215,8 @@ void Editor::connections() connect(plainTextEdit, &PlainTextEdit::askHasLineHighlight, this, [&]() { return hasLineHighlight; }); connect(plainTextEdit, &PlainTextEdit::askHasKeyFilter, this, [&]() { return hasKeyFilter; }); connect(plainTextEdit, &PlainTextEdit::askHasCursorBlink, this, [&]() { return hasCursorBlink; }); - connect(plainTextEdit, &PlainTextEdit::askHasBlockCursor, this, [&]() { return hasBlockCursor; }); + connect(plainTextEdit, &PlainTextEdit::askHasCursorBlock, this, [&]() { return hasCursorBlock; }); + connect(plainTextEdit, &PlainTextEdit::askHasCursorTypewriter, this, [&]() { return hasCursorTypewriter; }); connect(plainTextEdit, &PlainTextEdit::askCursorVisible, this, [&]() { return cursorVisible; }); connect(plainTextEdit, &PlainTextEdit::cursorPositionChanged, this, [&]() { cursorPositionChanged(); }); connect(plainTextEdit, &PlainTextEdit::selectionChanged, this, [&]() { selectionChanged(); }); diff --git a/Fernanda/source/Editor.h b/Fernanda/source/Editor.h index acfd912..7d2e7bb 100644 --- a/Fernanda/source/Editor.h +++ b/Fernanda/source/Editor.h @@ -37,8 +37,10 @@ class Editor : public QWidget AcceptNew }; enum class Has { - BlockCursor, CursorBlink, + CursorBlock, + CursorCenterOnScroll, + CursorTypewriter, ExtraScrolls, KeyFilter, LineHighlight, @@ -92,7 +94,8 @@ public slots: bool hasLineHighlight = true; bool hasKeyFilter = true; bool hasCursorBlink = true; - bool hasBlockCursor = true; + bool hasCursorBlock = true; + bool hasCursorTypewriter = false; bool cursorVisible = true; void connections(); @@ -109,6 +112,7 @@ public slots: bool askHasProject(); QAction* askTheme(); QActionGroup* askThemes(); + void askToggleCenterOnScroll(bool checked); void askToggleExtraScrolls(bool checked); void askToggleLineNumberArea(bool checked); void askToggleScrolls(bool checked); diff --git a/Fernanda/source/MainWindow.cpp b/Fernanda/source/MainWindow.cpp index be2dff6..14d4696 100644 --- a/Fernanda/source/MainWindow.cpp +++ b/Fernanda/source/MainWindow.cpp @@ -382,6 +382,8 @@ void MainWindow::makeToggleMenu() auto load_most_recent_toggle = new QAction(tr("&Load most recent project on open"), this); auto cursor_blink_toggle = new QAction(tr("&Blink"), this); auto cursor_block_toggle = new QAction(tr("&Block"), this); + auto cursor_center_on_scroll_toggle = new QAction(tr("&Center on scroll"), this); + auto cursor_typewriter_toggle = new QAction(tr("&Typewriter"), this); auto current_line_highlight_toggle = new QAction(tr("&Current line highlight"), this); auto editor_shadow_toggle = new QAction(tr("&Editor shadow"), this); auto editor_theme_toggle = new QAction(tr("&Editor theme"), this); @@ -393,7 +395,7 @@ void MainWindow::makeToggleMenu() auto indicator_toggle = new QAction(tr("&Indicator"), this); auto preview_toggle = new QAction(tr("&Preview"), this); auto status_bar_toggle = new QAction(tr("&Status bar"), this); - auto aot_toggle = new QAction(tr("&Always-on-top"), this); + auto aot_toggle = new QAction(tr("&Always on top"), this); auto stay_awake_toggle = new QAction(tr("&Stay awake"), this); auto timer_toggle = new QAction(tr("&Timer"), this); auto window_theme_toggle = new QAction(tr("&Window theme"), this); @@ -402,7 +404,9 @@ void MainWindow::makeToggleMenu() UserData::saveConfig(UserData::IniGroup::Data, UserData::IniValue::ToggleLoadMostRecent, checked); // move to story? }); connect(cursor_blink_toggle, &QAction::toggled, this, [&](bool checked) { editor->toggle(checked, Editor::Has::CursorBlink); }); - connect(cursor_block_toggle, &QAction::toggled, this, [&](bool checked) { editor->toggle(checked, Editor::Has::BlockCursor); }); + connect(cursor_block_toggle, &QAction::toggled, this, [&](bool checked) { editor->toggle(checked, Editor::Has::CursorBlock); }); + connect(cursor_center_on_scroll_toggle, &QAction::toggled, this, [&](bool checked) { editor->toggle(checked, Editor::Has::CursorCenterOnScroll); }); + connect(cursor_typewriter_toggle, &QAction::toggled, this, [&](bool checked) { editor->toggle(checked, Editor::Has::CursorTypewriter); }); connect(current_line_highlight_toggle, &QAction::toggled, this, [&](bool checked) { editor->toggle(checked, Editor::Has::LineHighlight); }); connect(editor_shadow_toggle, &QAction::toggled, this, [&](bool checked) { editor->toggle(checked, Editor::Has::Shadow); }); connect(editor_theme_toggle, &QAction::toggled, this, [&](bool checked) { editor->toggle(checked, Editor::Has::Theme); }); @@ -436,6 +440,8 @@ void MainWindow::makeToggleMenu() load_most_recent_toggle, cursor_blink_toggle, cursor_block_toggle, + cursor_center_on_scroll_toggle, + cursor_typewriter_toggle, current_line_highlight_toggle, editor_shadow_toggle, editor_theme_toggle, @@ -456,6 +462,8 @@ void MainWindow::makeToggleMenu() loadMenuToggle(load_most_recent_toggle, UserData::IniGroup::Data, UserData::IniValue::ToggleLoadMostRecent, false); loadMenuToggle(cursor_blink_toggle, UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorBlink, true); loadMenuToggle(cursor_block_toggle, UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorBlock, true); + loadMenuToggle(cursor_center_on_scroll_toggle, UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorCenterOnScroll, false); + loadMenuToggle(cursor_typewriter_toggle, UserData::IniGroup::Editor, UserData::IniValue::ToggleCursorTypewriter, false); loadMenuToggle(current_line_highlight_toggle, UserData::IniGroup::Editor, UserData::IniValue::ToggleLineHighlight, true); loadMenuToggle(editor_shadow_toggle, UserData::IniGroup::Editor, UserData::IniValue::ToggleEditorShadow, true); loadMenuToggle(editor_theme_toggle, UserData::IniGroup::Editor, UserData::IniValue::ToggleEditorTheme, true); @@ -475,7 +483,7 @@ void MainWindow::makeToggleMenu() toggle->addAction(load_most_recent_toggle); toggle->addSeparator(); auto cursor = toggle->addMenu(tr("&Cursor")); - for (const auto& action : { cursor_blink_toggle, cursor_block_toggle }) + for (const auto& action : { cursor_blink_toggle, cursor_block_toggle, cursor_center_on_scroll_toggle, cursor_typewriter_toggle }) cursor->addAction(action); for (const auto& action : { current_line_highlight_toggle, editor_shadow_toggle, editor_theme_toggle, key_filter_toggle, line_number_area_toggle, scrolls_previous_next_toggle }) toggle->addAction(action); diff --git a/Fernanda/source/PlainTextEdit.cpp b/Fernanda/source/PlainTextEdit.cpp index ca0b025..ec6d025 100644 --- a/Fernanda/source/PlainTextEdit.cpp +++ b/Fernanda/source/PlainTextEdit.cpp @@ -184,7 +184,7 @@ void PlainTextEdit::paintEvent(QPaintEvent* event) auto current_char = currentChar(); auto rect = reshapeCursor(current_char); painter.fillRect(rect, recolorCursor()); - if (!current_char.isNull() && askHasBlockCursor()) + if (!current_char.isNull() && askHasCursorBlock()) { painter.setPen(recolorCursor(true)); painter.drawText(rect, current_char); @@ -315,6 +315,8 @@ void PlainTextEdit::connections() connect(this, &PlainTextEdit::blockCountChanged, this, &PlainTextEdit::updateLineNumberAreaWidth); connect(this, &PlainTextEdit::updateRequest, this, &PlainTextEdit::updateLineNumberArea); connect(this, &PlainTextEdit::cursorPositionChanged, this, &PlainTextEdit::highlightCurrentLine); + connect(this, &PlainTextEdit::cursorPositionChanged, this, &PlainTextEdit::typewriter); + connect(this, &PlainTextEdit::textChanged, this, &PlainTextEdit::typewriter); connect(verticalScrollBar(), &QScrollBar::rangeChanged, this, &PlainTextEdit::scrollButtonEnabledHandler); connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &PlainTextEdit::scrollButtonEnabledHandler); connect(verticalScrollBar(), &QScrollBar::valueChanged, this, [&]() { sendBlockNumber(firstVisibleBlock().blockNumber()); }); @@ -334,7 +336,7 @@ void PlainTextEdit::connections() const QRect PlainTextEdit::reshapeCursor(QChar currentChar) { - if (askHasBlockCursor()) + if (askHasCursorBlock()) { QFontMetrics metrics(font()); currentChar.isNull() @@ -386,4 +388,10 @@ void PlainTextEdit::updateLineNumberArea(const QRect& rect, int dy) updateLineNumberAreaWidth(0); } +void PlainTextEdit::typewriter() +{ + if (!askHasCursorTypewriter()) return; + centerCursor(); +} + // PlainTextEdit.cpp, Fernanda diff --git a/Fernanda/source/PlainTextEdit.h b/Fernanda/source/PlainTextEdit.h index 2df63b8..cd434bb 100644 --- a/Fernanda/source/PlainTextEdit.h +++ b/Fernanda/source/PlainTextEdit.h @@ -72,6 +72,8 @@ public slots: void toggleScrolls(bool checked); void toggleExtraScrolls(bool checked); + void toggleCenterOnScroll(bool checked) { setCenterOnScroll(checked); } + protected: void resizeEvent(QResizeEvent* event) override; void paintEvent(QPaintEvent* event) override; @@ -103,6 +105,7 @@ public slots: private slots: void scrollButtonEnabledHandler(); void updateLineNumberArea(const QRect& rect, int dy); + void typewriter(); void updateLineNumberAreaWidth(int newBlockCount) { setViewportMargins(lineNumberAreaWidth(), 0, 0, 0); } @@ -111,8 +114,9 @@ private slots: void askFontSliderZoom(Zoom direction); void askGoNext(); void askGoPrevious(); - bool askHasBlockCursor(); bool askHasCursorBlink(); + bool askHasCursorBlock(); + bool askHasCursorTypewriter(); bool askHasKeyFilter(); bool askHasLineHighlight(); bool askHasProject(); @@ -122,7 +126,6 @@ private slots: class LineNumberArea : public QWidget { - public: LineNumberArea(PlainTextEdit* parent) : QWidget(parent), parent(parent) {} diff --git a/Fernanda/source/Splitter.cpp b/Fernanda/source/Splitter.cpp index f8ef869..f8cb516 100644 --- a/Fernanda/source/Splitter.cpp +++ b/Fernanda/source/Splitter.cpp @@ -93,7 +93,6 @@ SplitterHandle* Splitter::createHandle() { auto handle = new SplitterHandle(orientation(), this); connect(handle, &SplitterHandle::askHoverExpand, this, &Splitter::hoverExpand); - connect(handle, &SplitterHandle::askIsInitialized, this, &Splitter::initialize); connect(handle, &SplitterHandle::askStoreWidths, this, &Splitter::storeWidths); connect(handle, &SplitterHandle::askToggleExpansion, this, &Splitter::toggleExpansion); connect(handle, &SplitterHandle::askUnhoverAll, this, &Splitter::unhoverAll); @@ -147,6 +146,16 @@ bool Splitter::eventFilter(QObject* watched, QEvent* event) return false; } +void Splitter::initialize() +{ + for (auto& widget_info : widgets) + { + if (widget_info.width) continue; + widget_info.state = State::Collapsed; + isInitialized = true; + } +} + void Splitter::checkStates(int position, int index) { for (auto& widget_info : widgets) @@ -157,11 +166,11 @@ void Splitter::checkStates(int position, int index) auto& widget_state = widget_info.state; (handle_index < 2) ? (position != 0) - ? widget_state = State::Expanded - : widget_state = State::Collapsed + ? widget_state = State::Expanded + : widget_state = State::Collapsed : (position != (askWindowSize().width() - handleWidth())) - ? widget_state = State::Expanded - : widget_state = State::Collapsed; + ? widget_state = State::Expanded + : widget_state = State::Collapsed; } } @@ -175,24 +184,10 @@ void Splitter::hoverExpand(SplitterHandle* handlePtr) } } -void Splitter::initialize() -{ - if (isInitialized) - { - storeWidths(); - return; - } - for (auto& widget_info : widgets) - { - if (widget_info.width) continue; - widget_info.state = State::Collapsed; - } - storeWidths(); - isInitialized = true; -} - void Splitter::storeWidths() { + if (!isInitialized) + initialize(); for (auto& widget_info : widgets) { if (!isExpanded(widget_info)) continue; @@ -220,7 +215,7 @@ void Splitter::unhoverAll() if (!isHoverExpanded(widget_info)) continue; QTimer::singleShot(250, this, [&]() { - if (!widget(widget_info.index)->underMouse() && !handle(widget_info.handleIndex)->underMouse()) + if (!hasHover(widget_info)) collapse(widget_info); }); } diff --git a/Fernanda/source/Splitter.h b/Fernanda/source/Splitter.h index 3bef538..b2c1d11 100644 --- a/Fernanda/source/Splitter.h +++ b/Fernanda/source/Splitter.h @@ -66,18 +66,19 @@ class Splitter : public QSplitter void expand(Info& widgetInfo, bool isHover = false); void uncollapseAll(); bool eventFilter(QObject* watched, QEvent* event); + void initialize(); int toWindowX(int index, int size) { return (index < 2) ? size : askWindowSize().width() - size; } bool match(SplitterHandle* handlePtr, Info& widgetInfo) const { return (handlePtr == handle(widgetInfo.handleIndex)); } bool isCollapsed(Info& widgetInfo) const { return (widgetInfo.state == State::Collapsed); } bool isExpanded(Info& widgetInfo) const { return (widgetInfo.state == State::Expanded); } bool isHoverExpanded(Info& widgetInfo) const { return (widgetInfo.state == State::HoverExpanded); } + bool hasHover(Info& widgetInfo) const { return (widget(widgetInfo.index)->underMouse() || handle(widgetInfo.handleIndex)->underMouse()); } private slots: void checkStates(int position, int index); void hoverExpand(SplitterHandle* handlePtr); - void initialize(); void storeWidths(); void toggleExpansion(SplitterHandle* handlePtr); void unhoverAll(); diff --git a/Fernanda/source/SplitterHandle.h b/Fernanda/source/SplitterHandle.h index b8a7966..6922487 100644 --- a/Fernanda/source/SplitterHandle.h +++ b/Fernanda/source/SplitterHandle.h @@ -31,7 +31,7 @@ class SplitterHandle : public QSplitterHandle expanding->setDuration(100); expanding->setEasingCurve(QEasingCurve::OutQuad); expanding->setStartValue(splitter()->handleWidth()); - expanding->setEndValue(splitter()->handleWidth() * 1.5); + expanding->setEndValue(splitter()->handleWidth() * 1.6); connect(hoverTrigger, &QTimer::timeout, this, [&]() { askHoverExpand(this); @@ -62,7 +62,7 @@ class SplitterHandle : public QSplitterHandle result = true; break; case QEvent::MouseButtonRelease: - askIsInitialized(); + askStoreWidths(); result = true; break; case QEvent::MouseButtonDblClick: @@ -78,7 +78,6 @@ class SplitterHandle : public QSplitterHandle signals: void askHoverExpand(SplitterHandle* handlePtr); - void askIsInitialized(); void askStoreWidths(); void askToggleExpansion(SplitterHandle* handlePtr); void askUnhoverAll(); diff --git a/Fernanda/source/UserData.cpp b/Fernanda/source/UserData.cpp index ba7e936..8cee1d8 100644 --- a/Fernanda/source/UserData.cpp +++ b/Fernanda/source/UserData.cpp @@ -171,6 +171,12 @@ const QString UserData::valueName(IniValue valueType) case IniValue::ToggleCursorBlock: result = "toggle__cursor_block"; break; + case IniValue::ToggleCursorCenterOnScroll: + result = "toggle__cursor_center_on_scroll"; + break; + case IniValue::ToggleCursorTypewriter: + result = "toggle__cursor_typewriter"; + break; case IniValue::ToggleEditorShadow: result = "toggle__editor_shadow"; break; diff --git a/Fernanda/source/UserData.h b/Fernanda/source/UserData.h index e20d89d..434cb76 100644 --- a/Fernanda/source/UserData.h +++ b/Fernanda/source/UserData.h @@ -53,6 +53,8 @@ namespace UserData ToggleColorBar, ToggleCursorBlink, ToggleCursorBlock, + ToggleCursorCenterOnScroll, + ToggleCursorTypewriter, ToggleEditorShadow, ToggleEditorTheme, ToggleIndicator, diff --git a/Fernanda/source/Version.h b/Fernanda/source/Version.h index 029e5dc..5539055 100644 --- a/Fernanda/source/Version.h +++ b/Fernanda/source/Version.h @@ -13,8 +13,8 @@ #pragma once -#define VER_FILEVERSION 0,24,4,53 -#define VER_FILEVERSION_STR "v0.24.4-beta53" +#define VER_FILEVERSION 0,25,0,54 +#define VER_FILEVERSION_STR "v0.25.0-beta54" #define VER_PRODUCTVERSION VER_FILEVERSION #define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR #define VER_COMPANYNAME_STR "fairybow" diff --git a/README.md b/README.md index 5770a1a..36d48b0 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# Colorful conch shell icon. Fernanda +# Colorful conch shell icon. Fernanda

@@ -8,18 +8,19 @@

- Latest Release - License: GPL-3.0 + Latest Release + License: GPL-3.0
- 7zip v22.01 - Bit7z v4.0.0-RC - Qt v6.4.2 + 7zip v22.01 + Bit7z v4.0.0-RC + Qt v6.4.2
- Platform Windows (x64) - Platform Arch Linux + Platforms: Windows / Arch Linux - x64

## :tea: **Hello** + + Fernanda is a plain text editor for drafting long-form fiction. (At least, that's the plan.) @@ -172,7 +173,7 @@ Fernanda comes with several two-tone editor themes inspired by retro displays an **Tools:** -- :pushpin: **Always-on-top:** +- :pushpin: **Always on top:** - Pin Fernanda to the top of your window order (will interfere with popups!) - :bubble_tea: **Stay awake:** - Keep the screen awake without input (Windows only)