This is making me question the usefulness of application-global
shortcuts, but for now let's just prevent them from triggering while
you're looking at a modal message box..
This makes most operations thread safe, especially so that they
can safely be used in the Kernel. This includes obtaining a strong
reference from a weak reference, which now requires an explicit
call to WeakPtr::strong_ref(). Another major change is that
Weakable::make_weak_ref() may require the explicit target type.
Previously we used reinterpret_cast in WeakPtr, assuming that it
can be properly converted. But WeakPtr does not necessarily have
the knowledge to be able to do this. Instead, we now ask the class
itself to deliver a WeakPtr to the type that we want.
Also, WeakLink is no longer specific to a target type. The reason
for this is that we want to be able to safely convert e.g. WeakPtr<T>
to WeakPtr<U>, and before this we just reinterpret_cast the internal
WeakLink<T> to WeakLink<U>, which is a bold assumption that it would
actually produce the correct code. Instead, WeakLink now operates
on just a raw pointer and we only make those constructors/operators
available if we can verify that it can be safely cast.
In order to guarantee thread safety, we now use the least significant
bit in the pointer for locking purposes. This also means that only
properly aligned pointers can be used.
Set the max height of the text_rect to be the height difference
between two icons. Calculate the number of text lines that can be
displayed in this height, and display only that many.
...instead of maybe bitmap + a single mime type and its corresponding data.
This allows drag&drop operations to hold multiple different kinds of
data, and the views/applications to choose between those.
For instance, Spreadsheet can keep the structure of the dragged cells,
and still provide text-only data to be passed to different unrelated editors.
The current implementation is lying, it returns negative values if the
inner rect has a zero width or height but also a scrollbar - which
doesn't mean there's a "negative size" available though; it's still "no
size available", i.e. 0.
Views would previously require that an item be selected before it could
be dragged. This patch makes us consider initiating a drag immediately
after the view has been selected, without requiring a mouseup event in
between.
This is sad (since it would be nice to preserve the cursor+selection)
but until we implement persistent model indexes, this at least prevents
us from keeping a stale cursor index.
This returns true if the widget has focus, or if one of its descendant
widgets does. Use this in StackWidget and TabWidget.
This also fixes HackStudio crashing on startup in StackWidget, due to
running before the window has a focused widget.
When computing the chain of focusable widgets in a window, only include
each widget once (to avoid loops) and resolve focus proxies immediately
instead of lazily. This prevents the focus from getting stuck when
cycling backwards and hitting a proxy that points forward.
When opening a new window, we'll now try to find a suitable widget for
initial focus by picking the first available mouse-focusable one.
Whenever you press the tab key in a window with no focused widget,
we'll attempt to find a keyboard-focusable widget and give it focus.
This should make all applications keyboard-interactive immediately
without having to manually place focus with the mouse.
This one is a bit sketchy. While a window is inactive, none of its
widgets are considered focused (Widget::is_focused() will return false)
but this caused programmatic changes of the active widget in a tab
or stack widget to fail focus propagation from old child to new child.
Work around this by checking against Window::focused_widget() directly
instead of asking Widget::is_focused().
You can now focus a TabWidget by tabbing (with the keyboard!) to it.
Once focused, you can switch the active tab by pressing the left/right
keyboard keys.
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.
Some of the indexes generated during cursor movement were using column
instead of model_column(), which caused inconsistent display of items
under the cursor.
If an AbstractView receives focus without a valid cursor index, we now
ask it to move its cursor to the home position. This way, the user can
actually start moving the cursor after tabbing to a view.
TreeView was still partly sticking to the pre-cursor way of using the
first index in the selection as the implied cursor. This patch fixes
all of the TreeView code to operate on the cursor instead.
This makes trees behave much more intuitively when alternating between
mouse and keyboard interaction.
Instead of filling the whole row with selection color, only fill behind
the text. This gives a snugger, more focused appearance.
For embedders that want the entire row to get filled with the selection
color when selected, they can opt in to the old behavior by calling
TreeView::set_should_fill_selected_rows(). This is used by Profiler.
Move the wrapping logic to get_item_rects(). This makes mouse events
able to hit the wrapped labels, and various other little things stop
glitching out as well.
Also, instead of having a per-line width when wrapping icon names,
make the text rect wide enough to fit every line.
The qualified name of a font is "<Family> <Size> <Weight>". You can
get the QN of a Font via the Font::qualified_name() API, and you can
get any system font by QN from the GUI::FontDatabase. :^)