GApplication now has a palette. This palette contains all the system
theme colors by default, and is inherited by a new top-level GWidget.
New child widgets inherit their parents palette.
It is possible to override the GApplication palette, and the palette
of any GWidget.
The Palette object contains a bunch of colors, each corresponding to
a ColorRole. Each role has a convenience getter as well.
Each GWidget now has a background_role() and foreground_role(), which
are then looked up in their current palette when painting. This means
that you no longer alter the background color of a widget by setting
it directly, rather you alter either its background role, or the
widget's palette.
Using int was a mistake. This patch changes String, StringImpl,
StringView and StringBuilder to use size_t instead of int for lengths.
Obviously a lot of code needs to change as a result of this.
This patch adds InsertTextCommand and RemoveTextCommand.
These two commands are used to ... insert and remove text :^)
The bulk of the logic is moved into GTextDocument, and we now use the
command's redo() virtual to perform the action. Or in other words, when
you type into the text editor, we create an InsertTextCommand, push it
onto the undo stack, and call redo() on it immediately. That's how the
text gets inserted.
This makes it quite easy to implement more commands, as there is no
distinction between a redo() and the initial application.
This works for C++ syntax highlighted text documents by caching the C++
token type in a new "arbitrary data" member of GTextDocumentSpan.
When the cursor is placed immediately before a '{' or immediately after
a '}', we highlight both of these brace buddies by changing their
corresponding spans to have a different background color.
..and spans can also now have a custom background color. :^)
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 :^)