I started adding things to a Draw namespace, but it somehow felt really
wrong seeing Draw::Rect and Draw::Bitmap, etc. So instead, let's rename
the library to LibGfx. :^)
I've been wanting to do this for a long time. It's time we start being
consistent about how this stuff works.
The new convention is:
- "LibFoo" is a userspace library that provides the "Foo" namespace.
That's it :^) This was pretty tedious to convert and I didn't even
start on LibGUI yet. But it's coming up next.
This commit adds vertical wrap to menus. The first item is focused if
Key_Down is pressed on the last item and the last item is focused if
Key_up is pressed on the first item.
A mouse move event needs to do a bit more work than what a mouse wheel event
does. Mouse wheel just needs to update the hovered item, and update for a new
hovered item. This also stops us from calling redraw() twice on a wheel event.
While I really enjoyed having an infinite cycle when I implemented menu
keys (and seeing it wizz around and around :D), menu key movement should
be consistent between menus - and an inifinite cycle does not make much
sense for a scrollable menu.
Menus now have a scroll offset (index based, not pixel based) which is
controlled either with the mouse wheel or with the up/down arrow keys.
This finally allows us to browse all of the fonts that @xTibor has made
avilable through his serenity-fontdev project:
https://github.com/xTibor/serenity-fontdev
I'm not completely sure about the up/down arrows. They feel like maybe
they occupy a bit too much vertical space.
Also FIXME: this mechanism probably won't look completely right for
menus that have separators in them.
Fixes#1043.
Use an imaginary triangle between the top and bottom of the submenu of a
hovered item to determine whether the mouse is moving towards the
submenu. If it is, we do not update the hovered item. This allows the
submenu to stay open, making for much easier menu navigation.
Closes#1094
As suggested by Joshua, this commit adds the 2-clause BSD license as a
comment block to the top of every source file.
For the first pass, I've just added myself for simplicity. I encourage
everyone to add themselves as copyright holders of any file they've
added or modified in some significant way. If I've added myself in
error somewhere, feel free to replace it with the appropriate copyright
holder instead.
Going forward, all new source files should include a license header.
Tracking the hovered menu item independently from the index of the
currently hovered item is error prone and bad code. Simplify WSMenu by
only tracking the index of the currently hovered item.
Fixes#1092
We were forgetting to update the current menu when switching to a new
item.
We also rename the function from implying that only a redraw is
happening, as is actually not the case. It is now more correctly named:
update_for_new_hovered_item()
We're gonna need to handle overflow better than this, but at least this
way we can see the top of the menu, even if we can't scroll down to see
the rest of it.
For #1043.
Add event handling for key presses for navigating a menu. The currently
hovered menu item is tracked through an index which is either
incremented or decremented on up or down arrow key presses, changing the
hovered item.
Whenever there is a mouse move event, we ensure that the current index
matches the currently hovered item so that the mouse and keyboard do not
get out of sync.
If the right key is pressed, and we are on a submenu menu item, we
'enter' that submenu. While we are currently in a submenu, we forward
all keypress events to that submenu for handling. This allows us to
traverse the heirachy of a menu. While in a submenu, if the left key is
pressed, we leave that submenu and start handling the keypresses
ourselves again.
There is currently a small issue where the mouse hover and key hover can
get out of sync. The mouse can be traversing a submenu, but the parent
menu has no idea that the mouse has 'entered' a submenu, so will handle
the key presses itself, instead of forwarding them to the submenu. One
potential fix for this is for a menu to tell its menu parent that the
submenu is being traversed.
Menus are now owned by menu manager instead of being split between the
window manager and menu manager. If the window server wants to change
a menu, or call menu related functionality, this will need to be done
through the menu manager.
Further refactoring is likely needed, but this seems like a good start
for seperating menu logic from window logic.
Palette is now a value wrapper around a NonnullRefPtr<PaletteImpl>.
A new function, set_color(ColorRole, Color) implements a simple
copy-on-write mechanism so that we're sharing the PaletteImpl in the
common case, but allowing you to create custom palettes if you like,
by getting a GWidget's palette, modifying it, and then assigning the
modified palette to the widget via GWidget::set_palette().
Use this to make PaintBrush show its palette colors once again.
Fixes#943.
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.
Color themes are loaded from .ini files in /res/themes/
The theme can be switched from the "Themes" section in the system menu.
The basic mechanism is that WindowServer broadcasts a SharedBuffer with
all of the color values of the current theme. Clients receive this with
the response to their initial WindowServer::Greet handshake.
When the theme is changed, WindowServer tells everyone by sending out
an UpdateSystemTheme message with a new SharedBuffer to use.
This does feel somewhat bloated somehow, but I'm sure we can iterate on
it over time and improve things.
To get one of the theme colors, use the Color(SystemColor) constructor:
painter.fill_rect(rect, SystemColor::HoverHighlight);
Some things don't work 100% right without a reboot. Specifically, when
constructing a GWidget, it will set its own background and foreground
colors based on the current SystemColor::Window and SystemColor::Text.
The widget is then stuck with these values, and they don't update on
system theme change, only on app restart.
All in all though, this is pretty cool. Merry Christmas! :^)
This patch introduces code generation for the WindowServer IPC with
its clients. The client/server endpoints are defined by the two .ipc
files in Servers/WindowServer/: WindowServer.ipc and WindowClient.ipc
It now becomes significantly easier to add features and capabilities
to WindowServer since you don't have to know nearly as much about all
the intricate paths that IPC messages take between LibGUI and WSWindow.
The new system also uses significantly less IPC bandwidth since we're
now doing packed serialization instead of passing fixed-sized structs
of ~600 bytes for each message.
Some repaint coalescing optimizations are lost in this conversion and
we'll need to look at how to implement those in the new world.
The old CoreIPC::Client::Connection and CoreIPC::Server::Connection
classes are removed by this patch and replaced by use of ConnectionNG,
which will be renamed eventually.
Goodbye, old WindowServer IPC. You served us well :^)
Separators can't have identifiers associated with them, so it's not
possible to react meaningfully to their activation. Don't send messages
about it to avoid confusing the clients.
Let the global menu bar be either "open" or "closed". Clicking on one
of the menus in the menu bar toggles the state.
This ends up simpler and more intuitive than what we had before.
This patch moves a whole lot of the menu logic from WSWindowManager to
its proper home in WSMenuManager.
We also get rid of the "close_current_menu()" concept which was easily
confused in the presence of submenus. All operations should now be
aware of the menu stack instead. (The concept of a single, current menu
made a lot more sense when there were no nested menus.)
If the .af file for an app contains the App/Category key, we'll now put
it in a submenu of the system menu, together with all the other apps in
that same category. This is pretty neat! :^)
Okay, I've spent a whole day on this now, and it finally kinda works!
With this patch, CObject and all of its derived classes are reference
counted instead of tree-owned.
The previous, Qt-like model was nice and familiar, but ultimately also
outdated and difficult to reason about.
CObject-derived types should now be stored in RefPtr/NonnullRefPtr and
each class can be constructed using the forwarding construct() helper:
auto widget = GWidget::construct(parent_widget);
Note that construct() simply forwards all arguments to an existing
constructor. It is inserted into each class by the C_OBJECT macro,
see CObject.h to understand how that works.
CObject::delete_later() disappears in this patch, as there is no longer
a single logical owner of a CObject.
It's now possible to add a GMenu as a submenu of another GMenu.
Simply use the GMenu::add_submenu(NonnullOwnPtr<GMenu>) API :^)
The WindowServer now keeps track of a stack of open menus rather than
just one "current menu". This code needs a bit more work, but the basic
functionality is now here!
Take some inspiration from the first release of Visual Studio .NET and
add a left-hand stripe to contain the icons. And various other tweaks.
This isn't quite perfect, but it's pretty neat! :^)
Any GAction that has an icon assigned will now show up with that icon
when added to a menu as well.
I made the menu items 2px taller to accomodate the icons. I think this
turned out quite nice as well :^)
Paint a little checkbox frame for checkable items to make it obvious
that they are indeed checkable. This looks quite nice :^)
We also now shift all menu items to the right if we have any checkable
items in the menu.
Now that the window used by a WSMenu is its child CObject, the menu also
receives CChildEvent's about the window, including CEvent::ChildAdded when
the window gets created. At this point, menu_window() still returns nullptr,
so stop unconditionally assuming that it doesn't. We should not care whether
or not we have a window for unrelated events anyway.
Instead of LibGUI and WindowServer building their own copies of the drawing
and graphics code, let's it in a separate LibDraw library.
This avoids building the code twice, and will encourage better separation
of concerns. :^)
They show up as checkable GButtons in GToolBar, and with (or without) check
marks in menus.
There are a bunch of places to make use of this. This patch only takes
advantage of it in the FileManager for the view type actions.