When clicking empty space (beneath any used lines) in the TextEditor,
the cursor would jump to the start of the last line, rather than the
correct column, or the end of the line where appropriate. This was
because in the for_each_visual_line callback would return
IterationDecision::Continue if the clicked point wasn't in the line's
rect. Thus the callback would continue on each iteration and at the
end, would set the cursor to the default column of 0. To fix this I
added a bool to the callback's signature which tells the callback if
the for_each_visual_line method is on the last visual line. The
callback now does not return IterationDecision:Continue if
for_each_visual_line method is on the last line and the correct column
is then calculated with the line passed.
Every widget now has a GUI::FocusPolicy that determines how it can
receive focus:
- NoFocus: The widget is not focusable (default)
- TabFocus: The widget can be focused using the tab key.
- ClickFocus: The widget can be focused by clicking on it.
- StrongFocus: Both of the above.
For widgets that have a focus proxy, getting/setting the focus policy
will affect the proxy instead.
This matches behavior on Linux, macOS, Windows, and it makes it possible
to hit ctrl-L arrow-right ctrl-backspace to edit the last component of
an URL in browser, or of the current path in File Manager.
Also make it so that ctrl-left/right does a word movement that starts
at the edge of the selection. This matches Linux and macOS, but not
Windows (which instead does a word movement relative to the cursor,
not the selection edge).
The language server keeps track of the content of currently edited
files by receiving updates about edit actions.
Also, C++ autocompletion is no longer tied to HackStudio itself and
moved to be part of the language server.
This patch adds an optional mode where TextEditor highlights trailing
whitespace characters on each line with a nice reddish dither pattern.
We should probably make this themable and I'm sure it could be nicer
somehow, but this is just a first cut and I do kinda like it. :^)
This patch adds GUI::FocusEvent which has a GUI::FocusSource.
The focus source is one of three things:
- Programmatic
- Mouse
- Keyboard
This allows receivers of focus events to implement different behaviors
depending on how they receive/lose focus.
Instead of setting m_cursor directly to reset the cursor position,
TextEditor::set_document() now uses set_cursor() which will call cursor
change callback functions, if any.
This fixes a bug in HackStudio where the cursor information text would
not update immediately after changing the active TextDocument, even
though the cursor is always visibly being reset to 0, 0.
Adds a new highlighting effect to the actively selected row in
ComboBox ListView. ComboBoxEditor can now be controlled with
page up, page down, and the up and down arrow keys. ESC and loss
of focus now cause comboboxes to close. Now activates on mouseup
as well as return.
Adds a new, more restrictive read-only state to TextEditor which
forbids copying, selecting, editor cursors, and context menus.
Provides a unique appearance on focus which accomodates ComboBox
widgets. All TextEditor modes are now accessed by enum and
set_mode() which sets the editor to Editable, ReadOnly or
DisplayOnly. Updates applications still using set_readonly().
Get rid of the weird old signature:
- int StringType::to_int(bool& ok) const
And replace it with sensible new signature:
- Optional<int> StringType::to_int() const
Previously, if the cursor moved out of the visible area while text
was being inserted, the text editor would never scroll the cursor
back into view until the arrow keys were pressed to move the cursor.
This was caused by the TextEditor's reflow deferral system stopping
visual line recomputation until the end of text insertion, so now
when reflow deferral is completed, the TextEditor will make sure
the cursor is visible.
Previously, the TextEditor would crash when selecting a line with
no codepoints due to a null dereference, so this patch makes sure
there is actually any text to render before giving it to the painter.
Add a deferral counter and defer reflowing the visual lines until the
counter is at zero. Use this to defer reflow when inserting text.
This fixes glacial slowdown while paste large amounts of text.
TextDocument::first_word_break_before was refactored out to be able
to be used in multiple places throughout the project. It turns out
that its behaviour needs to be slightly different depending on
where its called, so it now has a start_at_column_before flag
to decide which letter it "thinks" was clicked.