Commit graph

74 commits

Author SHA1 Message Date
Andreas Kling
13d7c09125 Libraries: Move to Userland/Libraries/ 2021-01-12 12:17:46 +01:00
Nico Weber
009c753a12 Playground: Show placeholders for unregistered widgets
With this, Playground can be used to interactively edit e.g.
DisplaySettingsWindow.gml.
2021-01-11 20:12:26 +01:00
asynts
938e5c7719 Everywhere: Replace a bundle of dbg with dbgln.
These changes are arbitrarily divided into multiple commits to make it
easier to find potentially introduced bugs with git bisect.Everything:

The modifications in this commit were automatically made using the
following command:

    find . -name '*.cpp' -exec sed -i -E 's/dbg\(\) << ("[^"{]*");/dbgln\(\1\);/' {} \;
2021-01-09 21:11:09 +01:00
Andreas Kling
67b91d51a7 WindowServer+LibGUI: Pass the set of mime types being dragged to client
Previously the client would only learn the mime type of what was being
dropped on it once the drop occurred. To enable more sophisticated
filtering of drag & drop, we now pass along the list of mime types being
dragged to the client with each MouseMove event.

(Note that MouseMove is translated to the various Drag* events in LibGUI
on the client side.)
2021-01-09 12:02:07 +01:00
Andreas Kling
3b94af2c07 LibGUI: Have widgets signal willingness to accept drops
If a widget accept()'s a "drag enter" event, that widget now becomes
the application-wide "pending drop" widget. That state is cleared if
the drag moves over another widget (or leaves the window entirely.)
2021-01-09 12:02:07 +01:00
Andreas Kling
9acb72e804 LibGUI: Add "drag enter" and "drag leave" events
These events allow widgets to react when a drag enters/leaves their
rectangle. The enter event carries position + mime type, while the
leave event has no information.
2021-01-09 12:02:07 +01:00
Andreas Kling
b03e1b08b5 LibGUI: Add Widget shrink-to-fit layout flag
If this flag is enabled for a widget, it will be automatically sized
based on its children. This only works for widgets using a layout.

This allows you to put widgets inside each other without having to
manually calculate how large the container should be. It's not the
perfect API but it's a decent progression in ergonomics. :^)
2021-01-04 18:17:14 +01:00
Andreas Kling
347e5aa7b5 LibGUI: Hide the tooltip if widget with open tooltip unsets it
If you call set_tooltip({}) on a widget currently showing a tooltip,
we will now remove the tooltip window from screen.
2021-01-03 17:25:06 +01:00
Glenford Williams
b795f582cf LibGUI: Add missing properties to Widget gml
Add a few properties to Widget class for usage when in a gml environment
2021-01-03 10:34:55 +01:00
Andrew Kaster
39908fd569 LibGUI: Move widget registrations to the corresponding cpp file
This gets a lot of unecessary includes out of Widget.cpp. Doing this
didn't work before, but improvements in the C library and using dynamic
libraries have likely un-broken it :^).

Also, move the registration global object to an anonymous namespace. No
reason it has to be an extern symbol.
2021-01-03 10:31:42 +01:00
Andreas Kling
b4af4a4085 LibGUI: Allow widget sibling navigation with arrow keys
There's no spatial navigation here, Left/Up moves to the previous
sibling in the tab order, while Right/Down moves to the next.

The arrow keys keep focus within the same parent widget, unlike the tab
key which cycles through all focusable widgets in the window.

This makes GUI::MessageBox feel a bit nicer since you can now arrow
between the Yes/No/Cancel buttons. :^)
2021-01-02 01:56:59 +01:00
Andreas Kling
7841528cd4 LibCore: Remove Core::Object::is_widget() in favor of RTTI 2021-01-01 16:08:49 +01:00
Andrew Kaster
347bf6459d Applications+LibGUI: Convert all GML consumers to use the LibCore finder
Remove Widget::find_child_by_name and Widget::find_descendant_by_name,
and convert all users to using the type-safer version in Core::Object.
2021-01-01 14:45:09 +01:00
Andreas Kling
f330dc3886 LibGUI: Add a bunch of missing widget registrations 2020-12-31 23:32:13 +01:00
Stephan Unverwerth
b4d1390714 LibGFX: Move default_xxx_font() methods from Font to FontDatabase
When we have an abstract font class it makes no sense to keep
these methods in the Font class.
2020-12-30 20:40:30 +01:00
Andreas Kling
aacab897e8 LibGUI: Add widget registration for GUI::ListView 2020-12-30 20:37:51 +01:00
Andreas Kling
01ccbdb017 LibGUI: Register GUI::ComboBox :^) 2020-12-30 02:45:20 +01:00
Andreas Kling
e07a66d011 LibGUI: Remove unused Widget backcolor/forecolor properties
These were some leftovers from the VisualBuilder times.
2020-12-30 02:45:20 +01:00
Andreas Kling
7dc5a3ead8 LibGUI: Rewrite layout system in terms of min and max sizes
This patch removes size policies and preferred sizes, and replaces them
with min-size and max-size for each widget.

Box layout now works in 3 passes:

    1) Set all items (widgets/spacers) to their min-size
    2) Distribute remaining space evenly, respecting max-size
    3) Place widgets one after the other, adding spacing in between

I've also added convenience helpers for setting a fixed size (which is
the same as setting min-size and max-size to the same value.)

This significantly reduces the verbosity of widget layout and makes GML
a bit more pleasant to write, too. :^)
2020-12-30 01:36:41 +01:00
Andreas Kling
ee85713e52 LibGUI: Add fixed_size/fixed_width/fixed_height helpers to Widget
Fixed sizes are really just shorthands for setting min and max size to
the same value.

This makes it much nicer to express fixed sizes in GML:

Before:

    @GUI::Widget {
        horizontal_size_policy: "Fixed"
        preferred_width: 20
    }

After:

    @GUI::Widget {
        fixed_width: 20
    }
2020-12-30 01:28:28 +01:00
Andreas Kling
60e3f685db LibGUI: Add min/max sizes to GUI::Widget
This patch adds min_size and max_size properties to GUI::Widget. These
can also be accessed as min_width/min_height and max_width/max_height.

Layouts will respect these constraints and size widgets accordingly.
2020-12-30 01:28:28 +01:00
Linus Groh
c4991d969c LibGUI: Register the ImageWidget and LinkLabel widgets 2020-12-29 15:42:30 +01:00
Linus Groh
b8eb1baac8 LibGUI: Move REGISTER_WIDGET(GUI, TabWidget) to Widget.cpp
All the other (GUI) registrations happen here, so it's confusing to have
just one elsewhere ("wait... is TabWidget not registered?!").
2020-12-29 15:42:30 +01:00
Andreas Kling
7e79563bb9 LibGUI: Show tooltip after a small delay
It always felt a bit jarring that tooltips would pop in right away when
you hover over a toolbar button. This patch adds a 700ms delay before
they appear, and a 50ms delay before they disappear.

Once a tooltip is up, moving the cursor between two widgets that both
have tooltips will leave the tooltip on screen without delays.
2020-12-28 21:28:40 +01:00
Andreas Kling
644d5c5404 LibGUI: Switch focus if the currently focused widget is disabled 2020-12-28 01:02:57 +01:00
Andreas Kling
6e0976d858 LibGUI: Make the GML parser a bit more fault-tolerant
It will now fail and whine in the debug log instead of asserting.
2020-12-20 14:30:40 +01:00
Andreas Kling
48b0f4844b LibGUI: Add a couple more Widget registrations
Make it possible to instantiate BreadcrumbBar, ProgressBar and TreeView
from GML. :^)
2020-12-20 12:15:49 +01:00
Andreas Kling
822dc56ef3 LibGUI: Introduce GML - a simple GUI Markup Language :^)
This patch replaces the UI-from-JSON mechanism with a more
human-friendly DSL.

The current implementation simply converts the GML into a JSON object
that can be consumed by GUI::Widget::load_from_json(). The parser is
not very helpful if you make a mistake.

The language offers a very simple way to instantiate any registered
Core::Object class by simply saying @ClassName

@GUI::Label {
    text: "Hello friends!"
    tooltip: ":^)"
}

Layouts are Core::Objects and can be assigned to the "layout" property:

@GUI::Widget {
    layout: @GUI::VerticalBoxLayout {
        spacing: 2
        margins: [8, 8, 8, 8]
    }
}

And finally, child objects are simply nested within their parent:

@GUI::Widget {
    layout: @GUI::HorizontalBoxLayout {
    }
    @GUI::Button {
        text: "OK"
    }
    @GUI::Button {
        text: "Cancel"
    }
}

This feels a *lot* more pleasant to write than the JSON we had. The fact
that no new code was being written with the JSON mechanism was pretty
telling, so let's approach this with developer convenience in mind. :^)
2020-12-20 11:59:40 +01:00
Andreas Kling
ab289e183e LibGUI: Expose widget focus policy as a Core::Object property
This makes focus policies show up in the inspector which is helpful.
2020-12-07 19:46:34 +01:00
Jakub Berkop
c6bb3d452a
LibGUI: Widget::action_for_key_event() should fail for invalid shortcuts (#4137)
Previously GUI::Actions which were constructed without initializing
m_shortcut could be activated via an invalid GUI::Shortcut.

Steps to reproduce:
It was possible to enable TextEditor's markdown preview by pressing
Ctrl or Alt (Cmd/Ctrl) keys, which should not happen, as this Action
did not specify a shortcut.

This fix should apply to all other cases where actions where declared
without specifying a shortcut.
2020-11-23 18:41:15 +01:00
Tom
75f61fe3d9 AK: Make RefPtr, NonnullRefPtr, WeakPtr thread safe
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.
2020-11-10 19:11:52 +01:00
Andreas Kling
b11b4b29e9 LibGUI: Add Widget::has_focus_within()
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.
2020-10-30 23:40:23 +01:00
Andreas Kling
aef56159a8 LibGUI: Add Widget focus policies
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.
2020-10-30 17:03:28 +01:00
Andreas Kling
e64f43c3a7 LibGUI: Fix null pointer dereference in enter/leave event handling
If an enter/leave event is delivered to a widget after it is removed
from a window, we can't just assume a window is gonna be there.

Fixes #3669.
2020-10-03 19:47:56 +02:00
AnotherTest
6902a09e47 LibGUI: Register the 'ColorInput' and 'Frame' widgets 2020-09-25 23:55:33 +02:00
Andreas Kling
e2f32b8f9d LibCore: Make Core::Object properties more dynamic
Instead of everyone overriding save_to() and set_property() and doing
a pretty asymmetric job of implementing the various properties, let's
add a bit of structure here.

Object properties are now represented by a Core::Property. Properties
are registered with a getter and setter (optional) in constructors.
I've added some convenience macros for creating and registering
properties, but this does still feel a bit bulky. We'll have to
iterate on this and see where it goes.
2020-09-15 21:46:26 +02:00
Andreas Kling
093de0e323 LibGUI: Use Core::Object::set_property() to handle JSON GUI properties
Piggyback on the existing mechanism to set individual properties.
This doesn't cover layouts or child widgets, but the per-widget own
properties can be set this way.

Any property can now be set in JSON GUI, all you need to do is handle
it in the relevant Core::Object::set_property() override. :^)
2020-09-14 16:16:36 +02:00
Andreas Kling
6fc8dedd28 LibGUI: Allow setting widget visibility from JSON GUI spec 2020-09-14 16:16:36 +02:00
Andreas Kling
6590eb8eb7 LibGUI: Complain about malformed "layout" values in JSON GUI 2020-09-14 16:16:36 +02:00
Andreas Kling
ea17b0cbb6 LibGUI: Start building a way to instantiate GUI from JSON
My original idea for GUI building tools was to have the "VisualBuilder"
app generate C++ code which in turn programmatically instantiated UI.
That never really materialized in any useful way beyond static UIs.

This is a fresh, new approach: using JSON to declare the UI and parsing
and constructing this UI at runtime. This will allow for way more
dynamic and flexible approaches to GUI development (I think.)

The basic idea is that you pass a JSON string to Widget::load_from_json
and it takes care of the rest.

This first version supports basic box layouts and instantiation of
arbitrary widgets, as long as those widgets have been registered.

This code has some pretty rough edges right now as it's evolving and
we need to figure out a lot of things about how it should work.
Nevertheless, it feels pretty cool. :^)
2020-09-14 16:16:36 +02:00
Andreas Kling
3c580233d1 LibGUI: Improve widget registration mechanism a bit
Allow registering widgets from namespaces other than GUI. :^)
Also add a few widgets.
2020-09-14 16:16:36 +02:00
Andreas Kling
cf429a788c LibGUI: Add Widget override cursor concept
We got ourselves into a mess by making widgets override the window
cursor whenever they wanted a custom cursor. This patch introduces a
better solution to that issue: per-widget override cursors.

Each widget now has an override cursor that overrides the window
cursor when that widget is hovered.
2020-09-11 14:26:37 +02:00
Andreas Kling
a265d40d6e LibGUI: Allow widgets to clip their child widgets
This patch adds Widget::children_clip_rect() which can be overridden
to tighten clipping of a widget's children. The default implementation
simply returns Widget::rect().
2020-08-26 00:51:35 +02:00
Andreas Kling
af16552624 LibGUI: Add Widget focus proxies
A Widget can now have a focus proxy widget. Questions about focus are
redirected to the proxy if present. This is useful if a widget could
logically get focus, but wants one of its child widgets to actually
handle it.
2020-08-26 00:51:35 +02:00
Andreas Kling
e374eb3035 LibGUI+WindowServer: Remove ResizeEvent::old_size()
Turns out nobody was using this information anyway, so let's not go
through all the trouble of plumbing it from WindowServer to LibGUI.

Fixes #3247.
2020-08-22 13:11:25 +02:00
Linus Groh
47d7faa998 LibGUI: Update active tooltip when source widget changes the label
Application::show_tooltip() now keeps track of the application's active
tooltip source widget so it can be updated while being shown when the
same widget updates its tooltip label.
Application::hide_tooltip() will unset the tooltip source widget,
respectively.

This is pretty useful for the ResourceGraph applet's tooltips!

Also re-use the Application::TooltipWindow's rect position in its
set_tooltip() method to avoid flickering from the window temporarily
being moved to 100, 100 and the position adjusted moments later.
2020-08-15 13:45:08 +02:00
Andreas Kling
75b8f4e4e6 LibGUI: Make focus events more aware of why focus is changing
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.
2020-08-15 00:05:45 +02:00
Linus Groh
e77991e63a LibGUI: Fix Widget::screen_relative_rect() for WindowType::MenuApplet
This was using window()->position(), which is unset for windows with
WindowType::MenuApplet. Now it checks the window type and then uses
rect_in_menubar() for MenuApplet windows and rect() for everything else.

This makes tooltips show up for MenuApplet windows, previously they were
positioned off-screen :^)
2020-08-14 10:28:03 +02:00
Andreas Kling
e0b8b4ac67 LibCore+LibGUI: Switch to using AK::is and AK::downcast 2020-07-26 17:51:00 +02:00
Tom
ec3737510d WindowServer: Add accessory windows
Accessory windows are windows that, when activated, will activate
their parent and bring all other accessory windows of that parent
to the front of the window stack. Accessory windows can only be
active input windows. The accessory window's parent is always the
active window regardless of whether it is also the active input
window.

In order to route input correctly, input is now sent to the active
input window, which can be any accessory window or their parent,
or any regular window.
2020-07-15 17:15:45 +02:00