mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 03:07:44 +00:00
LibGUI+LibDraw: Add "Palette" concept for scoped color theming
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.
This commit is contained in:
parent
cb4e51a7a5
commit
a79bac428b
62 changed files with 448 additions and 410 deletions
|
@ -18,14 +18,15 @@ WSButton::~WSButton()
|
|||
|
||||
void WSButton::paint(Painter& painter)
|
||||
{
|
||||
auto& palette = WSWindowManager::the().palette();
|
||||
PainterStateSaver saver(painter);
|
||||
painter.translate(relative_rect().location());
|
||||
StylePainter::paint_button(painter, rect(), ButtonStyle::Normal, m_pressed, m_hovered);
|
||||
StylePainter::paint_button(painter, rect(), palette, ButtonStyle::Normal, m_pressed, m_hovered);
|
||||
auto x_location = rect().center();
|
||||
x_location.move_by(-(m_bitmap->width() / 2), -(m_bitmap->height() / 2));
|
||||
if (m_pressed)
|
||||
x_location.move_by(1, 1);
|
||||
painter.draw_bitmap(x_location, *m_bitmap, SystemColor::ButtonText);
|
||||
painter.draw_bitmap(x_location, *m_bitmap, palette.button_text());
|
||||
}
|
||||
|
||||
void WSButton::on_mouse_event(const WSMouseEvent& event)
|
||||
|
|
|
@ -113,7 +113,7 @@ void WSCompositor::compose()
|
|||
if (wm.any_opaque_window_contains_rect(dirty_rect))
|
||||
continue;
|
||||
// FIXME: If the wallpaper is opaque, no need to fill with color!
|
||||
m_back_painter->fill_rect(dirty_rect, SystemColor::DesktopBackground);
|
||||
m_back_painter->fill_rect(dirty_rect, wm.palette().desktop_background());
|
||||
if (m_wallpaper) {
|
||||
if (m_wallpaper_mode == WallpaperMode::Simple) {
|
||||
m_back_painter->blit(dirty_rect.location(), *m_wallpaper, dirty_rect);
|
||||
|
|
|
@ -126,6 +126,7 @@ WSWindow& WSMenu::ensure_menu_window()
|
|||
|
||||
void WSMenu::draw()
|
||||
{
|
||||
auto& palette = WSWindowManager::the().palette();
|
||||
m_theme_index_at_last_paint = WSWindowManager::the().theme_index();
|
||||
|
||||
ASSERT(menu_window());
|
||||
|
@ -133,8 +134,8 @@ void WSMenu::draw()
|
|||
Painter painter(*menu_window()->backing_store());
|
||||
|
||||
Rect rect { {}, menu_window()->size() };
|
||||
painter.fill_rect(rect.shrunken(6, 6), SystemColor::MenuBase);
|
||||
StylePainter::paint_window_frame(painter, rect);
|
||||
painter.fill_rect(rect.shrunken(6, 6), palette.menu_base());
|
||||
StylePainter::paint_window_frame(painter, rect, palette);
|
||||
int width = this->width();
|
||||
|
||||
if (!s_checked_bitmap)
|
||||
|
@ -148,15 +149,15 @@ void WSMenu::draw()
|
|||
}
|
||||
|
||||
Rect stripe_rect { frame_thickness(), frame_thickness(), s_stripe_width, height() - frame_thickness() * 2 };
|
||||
painter.fill_rect(stripe_rect, SystemColor::MenuStripe);
|
||||
painter.draw_line(stripe_rect.top_right(), stripe_rect.bottom_right(), Color(SystemColor::MenuStripe).darkened());
|
||||
painter.fill_rect(stripe_rect, palette.menu_stripe());
|
||||
painter.draw_line(stripe_rect.top_right(), stripe_rect.bottom_right(), palette.menu_stripe().darkened());
|
||||
|
||||
for (auto& item : m_items) {
|
||||
if (item.type() == WSMenuItem::Text) {
|
||||
Color text_color = SystemColor::WindowText;
|
||||
Color text_color = palette.window_text();
|
||||
if (&item == m_hovered_item && item.is_enabled()) {
|
||||
painter.fill_rect(item.rect(), SystemColor::MenuSelection);
|
||||
painter.draw_rect(item.rect(), Color(SystemColor::MenuSelection).darkened());
|
||||
painter.fill_rect(item.rect(), palette.menu_selection());
|
||||
painter.draw_rect(item.rect(), palette.menu_selection().darkened());
|
||||
text_color = Color::White;
|
||||
} else if (!item.is_enabled()) {
|
||||
text_color = Color::MidGray;
|
||||
|
@ -166,10 +167,10 @@ void WSMenu::draw()
|
|||
Rect checkmark_rect { item.rect().x() + 7, 0, s_checked_bitmap_width, s_checked_bitmap_height };
|
||||
checkmark_rect.center_vertically_within(text_rect);
|
||||
Rect checkbox_rect = checkmark_rect.inflated(4, 4);
|
||||
painter.fill_rect(checkbox_rect, SystemColor::Base);
|
||||
StylePainter::paint_frame(painter, checkbox_rect, FrameShape::Container, FrameShadow::Sunken, 2);
|
||||
painter.fill_rect(checkbox_rect, palette.base());
|
||||
StylePainter::paint_frame(painter, checkbox_rect, palette, FrameShape::Container, FrameShadow::Sunken, 2);
|
||||
if (item.is_checked()) {
|
||||
painter.draw_bitmap(checkmark_rect.location(), *s_checked_bitmap, SystemColor::ButtonText);
|
||||
painter.draw_bitmap(checkmark_rect.location(), *s_checked_bitmap, palette.button_text());
|
||||
}
|
||||
} else if (item.icon()) {
|
||||
Rect icon_rect { item.rect().x() + 3, 0, s_item_icon_width, s_item_icon_width };
|
||||
|
@ -189,13 +190,13 @@ void WSMenu::draw()
|
|||
s_submenu_arrow_bitmap_height
|
||||
};
|
||||
submenu_arrow_rect.center_vertically_within(item.rect());
|
||||
painter.draw_bitmap(submenu_arrow_rect.location(), submenu_arrow_bitmap, SystemColor::WindowText);
|
||||
painter.draw_bitmap(submenu_arrow_rect.location(), submenu_arrow_bitmap, palette.window_text());
|
||||
}
|
||||
} else if (item.type() == WSMenuItem::Separator) {
|
||||
Point p1(item.rect().translated(stripe_rect.width() + 4, 0).x(), item.rect().center().y() - 1);
|
||||
Point p2(width - 7, item.rect().center().y() - 1);
|
||||
painter.draw_line(p1, p2, SystemColor::ThreedShadow1);
|
||||
painter.draw_line(p1.translated(0, 1), p2.translated(0, 1), SystemColor::ThreedHighlight);
|
||||
painter.draw_line(p1, p2, palette.threed_shadow1());
|
||||
painter.draw_line(p1.translated(0, 1), p2.translated(0, 1), palette.threed_highlight());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ bool WSMenuManager::is_open(const WSMenu& menu) const
|
|||
void WSMenuManager::draw()
|
||||
{
|
||||
auto& wm = WSWindowManager::the();
|
||||
auto& palette = wm.palette();
|
||||
auto menubar_rect = this->menubar_rect();
|
||||
|
||||
if (m_needs_window_resize) {
|
||||
|
@ -83,14 +84,14 @@ void WSMenuManager::draw()
|
|||
|
||||
Painter painter(*window().backing_store());
|
||||
|
||||
painter.fill_rect(menubar_rect, SystemColor::Window);
|
||||
painter.draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, SystemColor::ThreedShadow1);
|
||||
painter.fill_rect(menubar_rect, palette.window());
|
||||
painter.draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, palette.threed_shadow1());
|
||||
int index = 0;
|
||||
wm.for_each_active_menubar_menu([&](WSMenu& menu) {
|
||||
Color text_color = SystemColor::WindowText;
|
||||
Color text_color = palette.window_text();
|
||||
if (is_open(menu)) {
|
||||
painter.fill_rect(menu.rect_in_menubar(), SystemColor::MenuSelection);
|
||||
painter.draw_rect(menu.rect_in_menubar(), Color(SystemColor::MenuSelection).darkened());
|
||||
painter.fill_rect(menu.rect_in_menubar(), palette.menu_selection());
|
||||
painter.draw_rect(menu.rect_in_menubar(), palette.menu_selection().darkened());
|
||||
text_color = Color::White;
|
||||
}
|
||||
painter.draw_text(
|
||||
|
@ -103,7 +104,7 @@ void WSMenuManager::draw()
|
|||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
painter.draw_text(m_username_rect, m_username, Font::default_bold_font(), TextAlignment::CenterRight, SystemColor::WindowText);
|
||||
painter.draw_text(m_username_rect, m_username, Font::default_bold_font(), TextAlignment::CenterRight, palette.window_text());
|
||||
|
||||
time_t now = time(nullptr);
|
||||
auto* tm = localtime(&now);
|
||||
|
@ -115,7 +116,7 @@ void WSMenuManager::draw()
|
|||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
|
||||
painter.draw_text(m_time_rect, time_text, wm.font(), TextAlignment::CenterRight, SystemColor::WindowText);
|
||||
painter.draw_text(m_time_rect, time_text, wm.font(), TextAlignment::CenterRight, palette.window_text());
|
||||
|
||||
for (auto& applet : m_applets) {
|
||||
if (!applet)
|
||||
|
|
|
@ -153,6 +153,7 @@ void WSWindowFrame::paint(Painter& painter)
|
|||
if (m_window.type() != WSWindowType::Normal)
|
||||
return;
|
||||
|
||||
auto& palette = WSWindowManager::the().palette();
|
||||
auto& window = m_window;
|
||||
|
||||
auto titlebar_rect = title_bar_rect();
|
||||
|
@ -170,29 +171,29 @@ void WSWindowFrame::paint(Painter& painter)
|
|||
auto& wm = WSWindowManager::the();
|
||||
|
||||
if (&window == wm.m_highlight_window) {
|
||||
border_color = SystemColor::HighlightWindowBorder1;
|
||||
border_color2 = SystemColor::HighlightWindowBorder2;
|
||||
title_color = SystemColor::HighlightWindowTitle;
|
||||
border_color = palette.highlight_window_border1();
|
||||
border_color2 = palette.highlight_window_border2();
|
||||
title_color = palette.highlight_window_title();
|
||||
} else if (&window == wm.m_move_window) {
|
||||
border_color = SystemColor::MovingWindowBorder1;
|
||||
border_color2 = SystemColor::MovingWindowBorder2;
|
||||
title_color = SystemColor::MovingWindowTitle;
|
||||
border_color = palette.moving_window_border1();
|
||||
border_color2 = palette.moving_window_border2();
|
||||
title_color = palette.moving_window_title();
|
||||
} else if (&window == wm.m_active_window) {
|
||||
border_color = SystemColor::ActiveWindowBorder1;
|
||||
border_color2 = SystemColor::ActiveWindowBorder2;
|
||||
title_color = SystemColor::ActiveWindowTitle;
|
||||
border_color = palette.active_window_border1();
|
||||
border_color2 = palette.active_window_border2();
|
||||
title_color = palette.active_window_title();
|
||||
} else {
|
||||
border_color = SystemColor::InactiveWindowBorder1;
|
||||
border_color2 = SystemColor::InactiveWindowBorder2;
|
||||
title_color = SystemColor::InactiveWindowTitle;
|
||||
border_color = palette.inactive_window_border1();
|
||||
border_color2 = palette.inactive_window_border2();
|
||||
title_color = palette.inactive_window_title();
|
||||
}
|
||||
|
||||
StylePainter::paint_window_frame(painter, outer_rect);
|
||||
StylePainter::paint_window_frame(painter, outer_rect, palette);
|
||||
|
||||
if (!window.show_titlebar())
|
||||
return;
|
||||
|
||||
painter.draw_line(titlebar_rect.bottom_left().translated(0, 1), titlebar_rect.bottom_right().translated(0, 1), SystemColor::Button);
|
||||
painter.draw_line(titlebar_rect.bottom_left().translated(0, 1), titlebar_rect.bottom_right().translated(0, 1), palette.button());
|
||||
|
||||
auto leftmost_button_rect = m_buttons.is_empty() ? Rect() : m_buttons.last().relative_rect();
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ WSWindowManager& WSWindowManager::the()
|
|||
return *s_the;
|
||||
}
|
||||
|
||||
WSWindowManager::WSWindowManager()
|
||||
WSWindowManager::WSWindowManager(const Palette& palette)
|
||||
: m_palette(palette)
|
||||
{
|
||||
s_the = this;
|
||||
|
||||
|
@ -132,6 +133,7 @@ WSWindowManager::WSWindowManager()
|
|||
auto new_theme = load_system_theme(theme.path);
|
||||
ASSERT(new_theme);
|
||||
set_system_theme(*new_theme);
|
||||
m_palette = Palette::create_with_shared_buffer(*new_theme);
|
||||
HashTable<WSClientConnection*> notified_clients;
|
||||
for_each_window([&](WSWindow& window) {
|
||||
if (window.client()) {
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <LibDraw/Color.h>
|
||||
#include <LibDraw/DisjointRectSet.h>
|
||||
#include <LibDraw/Painter.h>
|
||||
#include <LibDraw/Palette.h>
|
||||
#include <LibDraw/Rect.h>
|
||||
#include <WindowServer/WSCursor.h>
|
||||
#include <WindowServer/WSEvent.h>
|
||||
|
@ -50,10 +51,15 @@ class WSWindowManager : public CObject {
|
|||
public:
|
||||
static WSWindowManager& the();
|
||||
|
||||
WSWindowManager();
|
||||
explicit WSWindowManager(const Palette&);
|
||||
virtual ~WSWindowManager() override;
|
||||
|
||||
RefPtr<CConfigFile> wm_config() const { return m_wm_config; }
|
||||
const Palette& palette() const { return *m_palette; }
|
||||
|
||||
RefPtr<CConfigFile> wm_config() const
|
||||
{
|
||||
return m_wm_config;
|
||||
}
|
||||
void reload_config(bool);
|
||||
|
||||
void add_window(WSWindow&);
|
||||
|
@ -276,6 +282,8 @@ private:
|
|||
WeakPtr<WSButton> m_cursor_tracking_button;
|
||||
WeakPtr<WSButton> m_hovered_button;
|
||||
|
||||
NonnullRefPtr<Palette> m_palette;
|
||||
|
||||
RefPtr<CConfigFile> m_wm_config;
|
||||
|
||||
struct AppMetadata {
|
||||
|
|
|
@ -70,9 +70,10 @@ void WSWindowSwitcher::on_key_event(const WSKeyEvent& event)
|
|||
|
||||
void WSWindowSwitcher::draw()
|
||||
{
|
||||
auto& palette = WSWindowManager::the().palette();
|
||||
Painter painter(*m_switcher_window->backing_store());
|
||||
painter.fill_rect({ {}, m_rect.size() }, SystemColor::Window);
|
||||
painter.draw_rect({ {}, m_rect.size() }, SystemColor::ThreedShadow2);
|
||||
painter.fill_rect({ {}, m_rect.size() }, palette.window());
|
||||
painter.draw_rect({ {}, m_rect.size() }, palette.threed_shadow2());
|
||||
for (int index = 0; index < m_windows.size(); ++index) {
|
||||
auto& window = *m_windows.at(index);
|
||||
Rect item_rect {
|
||||
|
@ -84,21 +85,21 @@ void WSWindowSwitcher::draw()
|
|||
Color text_color;
|
||||
Color rect_text_color;
|
||||
if (index == m_selected_index) {
|
||||
painter.fill_rect(item_rect, SystemColor::Selection);
|
||||
text_color = SystemColor::SelectionText;
|
||||
rect_text_color = SystemColor::ThreedShadow1;
|
||||
painter.fill_rect(item_rect, palette.selection());
|
||||
text_color = palette.selection_text();
|
||||
rect_text_color = palette.threed_shadow1();
|
||||
} else {
|
||||
text_color = SystemColor::WindowText;
|
||||
rect_text_color = SystemColor::ThreedShadow2;
|
||||
text_color = palette.window_text();
|
||||
rect_text_color = palette.threed_shadow2();
|
||||
}
|
||||
item_rect.shrink(item_padding(), 0);
|
||||
Rect thumbnail_rect = { item_rect.location().translated(0, 5), { thumbnail_width(), thumbnail_height() } };
|
||||
if (window.backing_store()) {
|
||||
painter.draw_scaled_bitmap(thumbnail_rect, *window.backing_store(), window.backing_store()->rect());
|
||||
StylePainter::paint_frame(painter, thumbnail_rect.inflated(4, 4), FrameShape::Container, FrameShadow::Sunken, 2);
|
||||
StylePainter::paint_frame(painter, thumbnail_rect.inflated(4, 4), palette, FrameShape::Container, FrameShadow::Sunken, 2);
|
||||
}
|
||||
Rect icon_rect = { thumbnail_rect.bottom_right().translated(-window.icon().width(), -window.icon().height()), { window.icon().width(), window.icon().height() } };
|
||||
painter.fill_rect(icon_rect, SystemColor::Window);
|
||||
painter.fill_rect(icon_rect, palette.window());
|
||||
painter.blit(icon_rect.location(), window.icon(), window.icon().rect());
|
||||
painter.draw_text(item_rect.translated(thumbnail_width() + 12, 0), window.title(), WSWindowManager::the().window_title_font(), TextAlignment::CenterLeft, text_color);
|
||||
painter.draw_text(item_rect, window.rect().to_string(), TextAlignment::CenterRight, rect_text_color);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <LibCore/CConfigFile.h>
|
||||
#include <LibDraw/Palette.h>
|
||||
#include <LibDraw/SystemTheme.h>
|
||||
#include <WindowServer/WSCompositor.h>
|
||||
#include <WindowServer/WSEventLoop.h>
|
||||
|
@ -25,13 +26,14 @@ int main(int, char**)
|
|||
auto theme = load_system_theme(String::format("/res/themes/%s.ini", theme_name.characters()));
|
||||
ASSERT(theme);
|
||||
set_system_theme(*theme);
|
||||
auto palette = Palette::create_with_shared_buffer(*theme);
|
||||
|
||||
WSEventLoop loop;
|
||||
|
||||
WSScreen screen(wm_config->read_num_entry("Screen", "Width", 1024),
|
||||
wm_config->read_num_entry("Screen", "Height", 768));
|
||||
WSCompositor::the();
|
||||
auto wm = WSWindowManager::construct();
|
||||
auto wm = WSWindowManager::construct(*palette);
|
||||
|
||||
dbgprintf("Entering WindowServer main loop.\n");
|
||||
loop.exec();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue