You can now register a GWidget subclass with REGISTER_GWIDGET(class)
and it will be available for factory construction through the new
GWidgetClassRegistration interface.
To obtain a GWidgetClassRegistration for a given class name, you call
GWidgetClassRegistration::find(class_name). You can also iterate over
all the registered classes using GWCR::for_each(callback).
This will be very useful for implementing a proper GUI designer, and
also in the future for things like script bindings.
NOTE: All of the registrations are done in GWidget.cpp at the moment
since I ran into trouble with the fricken linker pruning the global
constructors this mechanism relies on. :^)
You can now press Ctrl+Shift+Up/Down in a GTextEditor and the currently
selected line(s) will all move together one step up/down.
If there is no selection, we move the line with the cursor on it. :^)
Since on_change handlers can alter the text document we're working on,
we have to make sure they've been run before we try looking at spans.
This fixes some flakiness when a paint happened before HackStudio had
a chance to re-highlight some C++ while editing it.
The design where clients of GTextEditor perform syntax highlighting in
the "arbitrary code execution" on_change callback is not very good.
We should find a way to move highlighting closer to the editor.
With this patch, you can now assign the same GTextDocument to multiple
GTextEditor widgets via GTextEditor::set_document().
The editors have independent cursors and selection, but all changes
are shared, and immediately propagate to all editors.
This is very unoptimized and will do lots of unnecessary invalidation,
especially line re-wrapping and repainting over and over again.
This patch decouples GTextDocument and GTextDocumentLine from the line
wrapping functionality of GTextEditor.
This should basically make it possible to have multiple GTextEditors
editing the same GTextDocument. Of course, that will require a bit more
work since there's no paint invalidation yet.
The idea here is to decouple the document from the editor widget so you
could have multiple editors being views onto the same document.
This doesn't work yet, since the document and editor are coupled in
various ways still (including a per-line back-pointer to the editor.)
This makes double-clicking on a C++ token in HackStudio select the
whole token, which is pretty nice. It's not perfect in all cases,
but a lot nicer than just expanding until we hit whitespace. :^)
This makes the backspace erase backwards until the next soft tab stop.
We currently always use 4 as the soft tab width, but I suppose we could
make it configurable at some point. :^)
It's now possible to give GTextEditor a vector of Span objects.
Spans currently tell the editor which color to use for each character
in the span. This can be used to implement syntax highlighting :^)
There were various little mistakes in the width calculations used by
the line-wrapping layout code.
With this patch, we should no longer see the horizontal scrollbar get
enabled with line-wrapping enabled. I will hide the scrollbar in a
separate patch.
text_position_at() was returning -1 if the position wasn't in
the bounds of a visual line. Now if the position is past the last
line, we simply return the last line index instead of -1.
Fixes#502.
When we update our content size, the width & height is now calculated
from the visual line rect size. Also now after we recompute all visual
lines, if the total height is different, we re-update the content size.
Compute the final file size and ftruncate() the destination file to the
right size immediately instead of incrementally appending to it.
This kind of optimization belongs in the kernel, but until we have it
there, this makes saving text files a whole lot faster. :^)
Pressing right did nothing when the very last characters of the buffer
were selected.
The expected action would be for the cursor to move to the end of the
buffer.
This patch fixes that.
Find_prev returned invalid when the contents of the file were equal to
the contents of the search box.
This is due to the checker walking on an empty character at the end of
a line.
To expand a bit on how the line-wrapping works, each physical line of
text is broken up into multiple visual lines. This is recomputed when
the document changes, or when the widget is resized.
Each GTextEditor::Line keeps track of the visual breaking points, and
also their visual rect in content coordinates. This allows us to do
painting and hit testing reasonably efficiently for now.
This code needs some cleanup, but it's finally in a working state, so
here it goes. :^)
This is not finished, but since the feature is controlled by a runtime
flag, the broken implementation should not affect users of this widget
too much (in theory :^).)
- GTextRange find(const StringView& needle, const GTextPosition& start)
This function searches for the needle in the haystack (the full text)
and returns a GTextRange for the closest match after "start".
If the needle is not found, it returns an invalid GTextRange.
If no "start" position is provided, the search begins at the head of
the text document. :^)