Qownnotes: Feature request: Typewriter mode (typewriter scrolling)

Created on 22 Sep 2019  路  29Comments  路  Source: pbek/QOwnNotes

Hello,

For more comfortable writing, I'd like to propose adding typewriter scrolling, i.e. always centering the active line. Typewriter mode means the vertical cursor position (Y coordinate) is always in the vertical middle of the editor. It would be cool to add typewriter mode switcher to the Main Menu -> Window -> Toggle typewriter mode.

Here are some examples and descriptions:
https://www.youtube.com/watch?v=hcyHEaX0m0I
http://www.inkitpub.com/2018/01/23/scriveners-typewriter-scrolling-mode/
https://ulysses.app/tutorials/typewriter-mode

I made research. You can use centerOnScroll property of the QPlainTextEdit control.

This property holds whether the cursor should be centered on screen. If set to true, the plain text edit scrolls the document vertically to make the cursor visible at the center of the viewport. This also allows the text edit to scroll below the end of the document.

Another solution is manipulate the position of the scroll bars directly to keep the cursor position. This solution is for the QTextEdit control, but it is also suitable for the QPlainTextEdit class.

Thanks in advance.
Best regards.

Feature

Most helpful comment

There now is a new release, could you please test it and report if it works for you?
(Does not work for the top of the note yet.)

Perfect! This is exactly what I needed!
Thank you very much. Now freewriting brings me even more pleasure than before :)

All 29 comments

How would it behave at the end or beginning of the document or if someone scrolls in the document?

There is two options:

  1. Always centering the current line. At the beginning and at the end of the document. And also when the user scrolls. It's good.

  2. Another option is the same as the first, but at the beginning of the document, the cursor is at the top of the editor until it reaches the middle of the document. Then, the cursor always stays in the middle, even when it reaches the end of the document.

Both options are convenient. But from a programming point of view the first option is simpler I think =)

For some reason setting centerOnScroll isn't doing anything. :disappointed:

So we have to set the scrollbar position values directly:

int cursorY = textEdit->cursorRect().top();
QScrollBar *vbar = textEdit->verticalScrollBar();
vbar->setValue(vbar->value() + cursorY - targetYPosition);

FocusWriter uses this function:

void Document::centerCursor(bool force)
{
    QRect cursor = m_text->cursorRect();
    QRect viewport = m_text->viewport()->rect();
    if (force || m_always_center || (cursor.bottom() >= viewport.bottom()) || (cursor.top() <= viewport.top())) {
        QPoint offset = viewport.center() - cursor.center();
        QScrollBar* scrollbar = m_text->verticalScrollBar();
        scrollbar->setValue(scrollbar->value() - offset.y());
    }
}

Above code didn't work out. It was quite tricky, had to reimplement it over and over again until I found a solution that finally worked.

19.9.19

  • there now is a typewriter mode that you can turn on in the Window menu

There now is a new release, could you please test it and report if it works for you?

It does not work as it should. Typewriter mode is needed for centering the current line when the cursor is at the end of the document. That鈥檚 why I love the typewriter mode. It is very convenient to look at the center of the screen all the time while typing.

https://youtu.be/Iz8Ff-PPksA

I have a crazy idea. What about add a special invisible marker at the end of the document, beyond which the cursor should not go. After this marker add a lot of line breaks (CRLF).

In the code do a check that does not let the cursor go beyond the marker. Marker is an invisible char from UTF-8. And trim line breaks when a document is saved.

If the current cursor centering code is left unchanged (ver 19.9.19) and line breaks are added to the end of the document, then we get what we need!

super-tricky. spent 3h on it without getting the exact algorithm to manipulate the viewport margins...

the problem (beside other processes already setting those margins) is calculating the correct margin, because of what information I get from Qt (because adding those "margins" changes all measurements)

If I understand correctly, you want to dynamically change the top and bottom margins?

Yes, you can either do that by adding a css padding (which also has effects on the scrollbars and sometimes will clip the text for some reason and thus will not work well for us) or by setting viewport margins.

As far as I understand, you need to make some pre-calculations and store results before you will change margins:

  1. Line height in pixels
  2. Lines per screen: round (editor height / line height)
  3. Top and bottom coordinates of vertical middle: top = (lines per screen / 2) * line height; bottom = top + line height;

Re-calculation of these variables needed just if user changes the editor height.

Then we need a function that returns current number of text lines. And function that returns current line where cursor is located.

For example, we have 10 lines of text. Cursor is located at 4th line from the beginning.
The goal is to calculate both top and bottom margins. 4th line of text need to be placed in the vertical middle of the editor.

1th line
2th line
3th line
4th line is current one. Cursor is here!
5th line
6th line
7th line
8th line
9th line
10th line

Here is super-raw algorithm:

Step 1. How many lines before the current line?
lines before = current line num - 1;

Step 2. How many lines after the current line?
lines after = number of text lines - current line num;

Step 3. Calculate margins

if lines before > Lines per screen / 2 then
    top margin = 0
else
    top margin = ((Lines per screen / 2) - lines before) * line height in pixels

if lines after > Lines per screen / 2 then
    bottom margin = 0
else
    bottom margin = ((Lines per screen / 2) - lines after) * line height in pixels

if top margin = 0 AND bottom margin = 0 then
    set scrollbar to the middle


For more accurate calculations algorithm must be improved. I just described the essence.

This will not work in the QPlainTextEdit, you don't get this information about lines. And even if you would there is soft-wrap (which causes to wrap lines) and the fact that each line can have a different size.

Ok, I expressed myself wrongly. It's not about the line numbers, because each line can be of different height and because a line number doesn't tell us about what is currently shown on the screen.

19.9.20

  • the typewriter mode was improved

    • in most cases the text will now also be centered if the cursor is at the

      bottom of the note

There now is a new release, could you please test it and report if it works for you?
(Does not work for the top of the note yet.)

Ok, I expressed myself wrongly. It's not about the line numbers, because each line can be of different height and because a line number doesn't tell us about what is currently shown on the screen.

Oh, that's right. I forgot about different font sizes :)

There now is a new release, could you please test it and report if it works for you?
(Does not work for the top of the note yet.)

Perfect! This is exactly what I needed!
Thank you very much. Now freewriting brings me even more pleasure than before :)

Although this doesn't work with the top, just with the bottom.

Although this doesn't work with the top, just with the bottom.

It's ok!

The only thing worth improving is that when user turn on the typewriter mode, you need to place the cursor in the center. Now this happens only after pressing a key.

For example, the cursor is at the bottom of the editor. I turn on typewriter mode and the cursor remains there. When I press a key, centering occurs.

It鈥檚 better to centering right after the typewriter mode is on.

It鈥檚 better to centering right after the typewriter mode is on.

Good idea! Thank you.

19.10.0

  • after turning on the typewriter mode the cursor will now immediately
    be centered

There now is a new release, could you please test it and report if it works for you?

Works amazing! Thank you.
I'm happy :) 馃憤

Great, thank you for testing! 馃樃

Was this page helpful?
0 / 5 - 0 ratings