1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 22:27:35 +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:
Andreas Kling 2019-12-24 20:57:54 +01:00
parent cb4e51a7a5
commit a79bac428b
62 changed files with 448 additions and 410 deletions

View file

@ -1,3 +1,4 @@
#include <LibDraw/Palette.h>
#include <LibGUI/GAbstractButton.h>
#include <LibGUI/GPainter.h>
@ -154,7 +155,7 @@ void GAbstractButton::paint_text(GPainter& painter, const Rect& rect, const Font
if (text().is_empty())
return;
painter.draw_text(clipped_rect, text(), font, text_alignment, SystemColor::ButtonText, TextElision::Right);
painter.draw_text(clipped_rect, text(), font, text_alignment, palette().button_text(), TextElision::Right);
if (is_focused())
painter.draw_rect(clipped_rect.inflated(6, 4), Color(140, 140, 140));
}

View file

@ -1,4 +1,5 @@
#include <AK/StringBuilder.h>
#include <LibDraw/Palette.h>
#include <LibGUI/GAbstractColumnView.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GMenu.h>
@ -99,9 +100,9 @@ void GAbstractColumnView::paint_headers(GPainter& painter)
if (!headers_visible())
return;
int exposed_width = max(content_size().width(), width());
painter.fill_rect({ 0, 0, exposed_width, header_height() }, SystemColor::Window);
painter.draw_line({ 0, 0 }, { exposed_width - 1, 0 }, SystemColor::ThreedHighlight);
painter.draw_line({ 0, header_height() - 1 }, { exposed_width - 1, header_height() - 1 }, SystemColor::ThreedShadow1);
painter.fill_rect({ 0, 0, exposed_width, header_height() }, palette().button());
painter.draw_line({ 0, 0 }, { exposed_width - 1, 0 }, palette().threed_highlight());
painter.draw_line({ 0, header_height() - 1 }, { exposed_width - 1, header_height() - 1 }, palette().threed_shadow1());
int x_offset = 0;
int column_count = model()->column_count();
for (int column_index = 0; column_index < column_count; ++column_index) {
@ -112,7 +113,7 @@ void GAbstractColumnView::paint_headers(GPainter& painter)
Rect cell_rect(x_offset, 0, column_width + horizontal_padding() * 2, header_height());
bool pressed = column_index == m_pressed_column_header_index && m_pressed_column_header_is_pressed;
bool hovered = column_index == m_hovered_column_header_index && model()->column_metadata(column_index).sortable == GModel::ColumnMetadata::Sortable::True;
StylePainter::paint_button(painter, cell_rect, ButtonStyle::Normal, pressed, hovered);
StylePainter::paint_button(painter, cell_rect, palette(), ButtonStyle::Normal, pressed, hovered);
String text;
if (is_key_column) {
StringBuilder builder;
@ -129,7 +130,7 @@ void GAbstractColumnView::paint_headers(GPainter& painter)
auto text_rect = cell_rect.translated(horizontal_padding(), 0);
if (pressed)
text_rect.move_by(1, 1);
painter.draw_text(text_rect, text, header_font(), TextAlignment::CenterLeft, SystemColor::ButtonText);
painter.draw_text(text_rect, text, header_font(), TextAlignment::CenterLeft, palette().button_text());
x_offset += column_width + horizontal_padding() * 2;
}
}

View file

@ -9,7 +9,7 @@ class GTableCellPaintingDelegate {
public:
virtual ~GTableCellPaintingDelegate() {}
virtual void paint(GPainter&, const Rect&, const GModel&, const GModelIndex&) = 0;
virtual void paint(GPainter&, const Rect&, const Palette&, const GModel&, const GModelIndex&) = 0;
};
class GAbstractColumnView : public GAbstractView {

View file

@ -1,3 +1,4 @@
#include <LibDraw/Palette.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GApplication.h>
#include <LibGUI/GDesktop.h>
@ -142,3 +143,19 @@ void GApplication::did_delete_last_window(Badge<GWindow>)
if (m_quit_when_last_window_deleted)
m_event_loop->quit(0);
}
void GApplication::set_system_palette(SharedBuffer& buffer)
{
if (!m_system_palette)
m_system_palette = Palette::create_with_shared_buffer(buffer);
else
m_system_palette->replace_internal_buffer({}, buffer);
if (!m_palette)
m_palette = m_system_palette;
}
void GApplication::set_palette(const Palette& palette)
{
m_palette = palette;
}

View file

@ -10,7 +10,10 @@ class GAction;
class GKeyEvent;
class GMenuBar;
class GWindow;
class GWindowServerConnection;
class Palette;
class Point;
class SharedBuffer;
class GApplication {
public:
@ -39,9 +42,16 @@ public:
const String& invoked_as() const { return m_invoked_as; }
const Vector<String>& args() const { return m_args; }
const Palette& palette() const { return *m_palette; }
void set_palette(const Palette&);
void set_system_palette(SharedBuffer&);
private:
OwnPtr<CEventLoop> m_event_loop;
OwnPtr<GMenuBar> m_menubar;
RefPtr<Palette> m_palette;
RefPtr<Palette> m_system_palette;
HashMap<GShortcut, GAction*> m_global_shortcut_actions;
class TooltipWindow;
TooltipWindow* m_tooltip_window { nullptr };

View file

@ -27,7 +27,7 @@ void GButton::paint_event(GPaintEvent& event)
GPainter painter(*this);
painter.add_clip_rect(event.rect());
StylePainter::paint_button(painter, rect(), m_button_style, is_being_pressed(), is_hovered(), is_checked(), is_enabled());
StylePainter::paint_button(painter, rect(), palette(), m_button_style, is_being_pressed(), is_hovered(), is_checked(), is_enabled());
if (text().is_empty() && !m_icon)
return;

View file

@ -1,8 +1,9 @@
#include <Kernel/KeyCode.h>
#include <LibDraw/CharacterBitmap.h>
#include <LibDraw/Palette.h>
#include <LibDraw/StylePainter.h>
#include <LibGUI/GCheckBox.h>
#include <LibGUI/GPainter.h>
#include <LibDraw/CharacterBitmap.h>
#include <LibDraw/StylePainter.h>
static const char* s_checked_bitmap_data = {
" "
@ -48,14 +49,14 @@ void GCheckBox::paint_event(GPaintEvent& event)
text_rect.set_height(font().glyph_height());
if (fill_with_background_color())
painter.fill_rect(rect(), background_color());
painter.fill_rect(rect(), palette().window());
Rect box_rect {
0, height() / 2 - s_box_height / 2 - 1,
s_box_width, s_box_height
};
painter.fill_rect(box_rect, SystemColor::Base);
StylePainter::paint_frame(painter, box_rect, FrameShape::Container, FrameShadow::Sunken, 2);
painter.fill_rect(box_rect, palette().base());
StylePainter::paint_frame(painter, box_rect, palette(), FrameShape::Container, FrameShadow::Sunken, 2);
if (is_being_pressed())
painter.draw_rect(box_rect.shrunken(4, 4), Color::MidGray);
@ -63,7 +64,7 @@ void GCheckBox::paint_event(GPaintEvent& event)
if (is_checked()) {
if (!s_checked_bitmap)
s_checked_bitmap = &CharacterBitmap::create_from_ascii(s_checked_bitmap_data, s_checked_bitmap_width, s_checked_bitmap_height).leak_ref();
painter.draw_bitmap(box_rect.shrunken(4, 4).location(), *s_checked_bitmap, SystemColor::ButtonText);
painter.draw_bitmap(box_rect.shrunken(4, 4).location(), *s_checked_bitmap, palette().button_text());
}
paint_text(painter, text_rect, font(), TextAlignment::TopLeft);

View file

@ -58,7 +58,6 @@ GFilePicker::GFilePicker(Mode mode, const StringView& file_name, const StringVie
horizontal_container->set_layout(make<GBoxLayout>(Orientation::Horizontal));
horizontal_container->layout()->set_margins({ 4, 4, 4, 4 });
horizontal_container->set_fill_with_background_color(true);
horizontal_container->set_background_color(SystemColor::Window);
auto vertical_container = GWidget::construct(horizontal_container.ptr());
vertical_container->set_layout(make<GBoxLayout>(Orientation::Vertical));

View file

@ -18,5 +18,5 @@ void GFrame::paint_event(GPaintEvent& event)
GPainter painter(*this);
painter.add_clip_rect(event.rect());
StylePainter::paint_frame(painter, rect(), m_shape, m_shadow, m_thickness, spans_entire_window_horizontally());
StylePainter::paint_frame(painter, rect(), palette(), m_shape, m_shadow, m_thickness, spans_entire_window_horizontally());
}

View file

@ -1,6 +1,7 @@
#include <LibDraw/Palette.h>
#include <LibDraw/StylePainter.h>
#include <LibGUI/GGroupBox.h>
#include <LibGUI/GPainter.h>
#include <LibDraw/StylePainter.h>
GGroupBox::GGroupBox(GWidget* parent)
: GGroupBox({}, parent)
@ -11,8 +12,6 @@ GGroupBox::GGroupBox(const StringView& title, GWidget* parent)
: GWidget(parent)
, m_title(title)
{
set_fill_with_background_color(true);
set_background_color(SystemColor::Window);
}
GGroupBox::~GGroupBox()
@ -28,11 +27,11 @@ void GGroupBox::paint_event(GPaintEvent& event)
0, font().glyph_height() / 2,
width(), height() - font().glyph_height() / 2
};
StylePainter::paint_frame(painter, frame_rect, FrameShape::Box, FrameShadow::Sunken, 2);
StylePainter::paint_frame(painter, frame_rect, palette(), FrameShape::Box, FrameShadow::Sunken, 2);
Rect text_rect { 4, 0, font().width(m_title) + 6, font().glyph_height() };
painter.fill_rect(text_rect, background_color());
painter.draw_text(text_rect, m_title, TextAlignment::Center, foreground_color());
painter.fill_rect(text_rect, palette().button());
painter.draw_text(text_rect, m_title, TextAlignment::Center, palette().button_text());
}
void GGroupBox::set_title(const StringView& title)

View file

@ -1,5 +1,6 @@
#include <AK/StringBuilder.h>
#include <Kernel/KeyCode.h>
#include <LibDraw/Palette.h>
#include <LibGUI/GDragOperation.h>
#include <LibGUI/GItemView.h>
#include <LibGUI/GModel.h>
@ -186,12 +187,13 @@ void GItemView::doubleclick_event(GMouseEvent& event)
void GItemView::paint_event(GPaintEvent& event)
{
Color widget_background_color = palette().color(background_role());
GFrame::paint_event(event);
GPainter painter(*this);
painter.add_clip_rect(widget_inner_rect());
painter.add_clip_rect(event.rect());
painter.fill_rect(event.rect(), SystemColor::Base);
painter.fill_rect(event.rect(), widget_background_color);
painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
auto column_metadata = model()->column_metadata(m_model_column);
@ -201,9 +203,9 @@ void GItemView::paint_event(GPaintEvent& event)
bool is_selected_item = selection().contains(model()->index(item_index, m_model_column));
Color background_color;
if (is_selected_item) {
background_color = is_focused() ? Color(SystemColor::Selection) : Color::from_rgb(0x606060);
background_color = is_focused() ? palette().selection() : Color::from_rgb(0x606060);
} else {
background_color = SystemColor::Base;
background_color = widget_background_color;
}
Rect item_rect = this->item_rect(item_index);
@ -228,9 +230,9 @@ void GItemView::paint_event(GPaintEvent& event)
Color text_color;
if (is_selected_item)
text_color = SystemColor::SelectionText;
text_color = palette().selection_text();
else
text_color = model()->data(model_index, GModel::Role::ForegroundColor).to_color(SystemColor::WindowText);
text_color = model()->data(model_index, GModel::Role::ForegroundColor).to_color(palette().color(foreground_role()));
painter.fill_rect(text_rect, background_color);
painter.draw_text(text_rect, item_text.to_string(), font, TextAlignment::Center, text_color, TextElision::Right);
};

View file

@ -1,6 +1,7 @@
#include "GLabel.h"
#include <LibGUI/GPainter.h>
#include <LibDraw/GraphicsBitmap.h>
#include <LibDraw/Palette.h>
#include <LibGUI/GLabel.h>
#include <LibGUI/GPainter.h>
GLabel::GLabel(GWidget* parent)
: GFrame(parent)
@ -58,7 +59,7 @@ void GLabel::paint_event(GPaintEvent& event)
text_rect.set_width(text_rect.width() - indent * 2);
if (is_enabled()) {
painter.draw_text(text_rect, text(), m_text_alignment, foreground_color(), TextElision::Right);
painter.draw_text(text_rect, text(), m_text_alignment, palette().window_text(), TextElision::Right);
} else {
painter.draw_text(text_rect.translated(1, 1), text(), font(), text_alignment(), Color::White, TextElision::Right);
painter.draw_text(text_rect, text(), font(), text_alignment(), Color::from_rgb(0x808080), TextElision::Right);

View file

@ -1,4 +1,5 @@
#include <Kernel/KeyCode.h>
#include <LibDraw/Palette.h>
#include <LibGUI/GListView.h>
#include <LibGUI/GPainter.h>
#include <LibGUI/GScrollBar.h>
@ -6,6 +7,7 @@
GListView::GListView(GWidget* parent)
: GAbstractView(parent)
{
set_background_role(ColorRole::Base);
set_frame_shape(FrameShape::Container);
set_frame_shadow(FrameShadow::Sunken);
set_frame_thickness(2);
@ -104,12 +106,12 @@ void GListView::paint_event(GPaintEvent& event)
Color background_color;
if (is_selected_row) {
background_color = is_focused() ? Color(SystemColor::SelectionText) : Color::from_rgb(0x606060);
background_color = is_focused() ? palette().selection_text() : Color::from_rgb(0x606060);
} else {
if (alternating_row_colors() && (painted_item_index % 2))
background_color = Color(210, 210, 210);
else
background_color = SystemColor::Base;
background_color = palette().color(background_role());
}
auto column_metadata = model()->column_metadata(m_model_column);
@ -129,7 +131,7 @@ void GListView::paint_event(GPaintEvent& event)
if (is_selected_row)
text_color = Color::White;
else
text_color = model()->data(index, GModel::Role::ForegroundColor).to_color(SystemColor::WindowText);
text_color = model()->data(index, GModel::Role::ForegroundColor).to_color(palette().color(foreground_role()));
auto text_rect = row_rect;
text_rect.move_by(horizontal_padding(), 0);
text_rect.set_width(text_rect.width() - horizontal_padding() * 2);
@ -140,7 +142,7 @@ void GListView::paint_event(GPaintEvent& event)
};
Rect unpainted_rect(0, painted_item_index * item_height(), exposed_width, height());
painter.fill_rect(unpainted_rect, SystemColor::Base);
painter.fill_rect(unpainted_rect, palette().color(background_role()));
}
int GListView::item_count() const

View file

@ -58,5 +58,5 @@ void GProgressBar::paint_event(GPaintEvent& event)
progress_text = builder.to_string();
}
StylePainter::paint_progress_bar(painter, rect, m_min, m_max, m_value, progress_text);
StylePainter::paint_progress_bar(painter, rect, palette(), m_min, m_max, m_value, progress_text);
}

View file

@ -1,11 +1,13 @@
#include <LibDraw/GraphicsBitmap.h>
#include <LibDraw/Palette.h>
#include <LibGUI/GPainter.h>
#include <LibGUI/GResizeCorner.h>
#include <LibGUI/GWindow.h>
#include <LibDraw/GraphicsBitmap.h>
GResizeCorner::GResizeCorner(GWidget* parent)
: GWidget(parent)
{
set_background_role(ColorRole::Button);
set_size_policy(SizePolicy::Fixed, SizePolicy::Fixed);
set_preferred_size(16, 16);
m_bitmap = GraphicsBitmap::load_from_file("/res/icons/resize-corner.png");
@ -20,7 +22,7 @@ void GResizeCorner::paint_event(GPaintEvent& event)
{
GPainter painter(*this);
painter.add_clip_rect(event.rect());
painter.fill_rect(rect(), SystemColor::Button);
painter.fill_rect(rect(), palette().color(background_role()));
painter.blit({ 0, 0 }, *m_bitmap, m_bitmap->rect());
GWidget::paint_event(event);
}

View file

@ -1,5 +1,6 @@
#include <LibDraw/CharacterBitmap.h>
#include <LibDraw/GraphicsBitmap.h>
#include <LibDraw/Palette.h>
#include <LibDraw/StylePainter.h>
#include <LibGUI/GPainter.h>
#include <LibGUI/GScrollBar.h>
@ -203,18 +204,18 @@ void GScrollBar::paint_event(GPaintEvent& event)
GPainter painter(*this);
painter.add_clip_rect(event.rect());
painter.fill_rect(rect(), Color(SystemColor::Button).lightened());
painter.fill_rect(rect(), palette().button().lightened());
StylePainter::paint_button(painter, decrement_button_rect(), ButtonStyle::Normal, false, m_hovered_component == Component::DecrementButton);
StylePainter::paint_button(painter, increment_button_rect(), ButtonStyle::Normal, false, m_hovered_component == Component::IncrementButton);
StylePainter::paint_button(painter, decrement_button_rect(), palette(), ButtonStyle::Normal, false, m_hovered_component == Component::DecrementButton);
StylePainter::paint_button(painter, increment_button_rect(), palette(), ButtonStyle::Normal, false, m_hovered_component == Component::IncrementButton);
if (length(orientation()) > default_button_size()) {
painter.draw_bitmap(decrement_button_rect().location().translated(3, 3), orientation() == Orientation::Vertical ? *s_up_arrow_bitmap : *s_left_arrow_bitmap, has_scrubber() ? SystemColor::ButtonText : SystemColor::DisabledText);
painter.draw_bitmap(increment_button_rect().location().translated(3, 3), orientation() == Orientation::Vertical ? *s_down_arrow_bitmap : *s_right_arrow_bitmap, has_scrubber() ? SystemColor::ButtonText : SystemColor::DisabledText);
painter.draw_bitmap(decrement_button_rect().location().translated(3, 3), orientation() == Orientation::Vertical ? *s_up_arrow_bitmap : *s_left_arrow_bitmap, has_scrubber() ? palette().button_text() : palette().threed_shadow1());
painter.draw_bitmap(increment_button_rect().location().translated(3, 3), orientation() == Orientation::Vertical ? *s_down_arrow_bitmap : *s_right_arrow_bitmap, has_scrubber() ? palette().button_text() : palette().threed_shadow1());
}
if (has_scrubber())
StylePainter::paint_button(painter, scrubber_rect(), ButtonStyle::Normal, false, m_hovered_component == Component::Scrubber || m_scrubber_in_use);
StylePainter::paint_button(painter, scrubber_rect(), palette(), ButtonStyle::Normal, false, m_hovered_component == Component::Scrubber || m_scrubber_in_use);
}
void GScrollBar::on_automatic_scrolling_timer_fired()

View file

@ -62,8 +62,8 @@ void GSlider::paint_event(GPaintEvent& event)
track_rect.center_horizontally_within(inner_rect());
}
StylePainter::paint_frame(painter, track_rect, FrameShape::Panel, FrameShadow::Sunken, 1);
StylePainter::paint_button(painter, knob_rect(), ButtonStyle::Normal, false, m_knob_hovered);
StylePainter::paint_frame(painter, track_rect, palette(), FrameShape::Panel, FrameShadow::Sunken, 1);
StylePainter::paint_button(painter, knob_rect(), palette(), ButtonStyle::Normal, false, m_knob_hovered);
}
Rect GSlider::knob_rect() const

View file

@ -1,3 +1,4 @@
#include <LibDraw/Palette.h>
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GSplitter.h>
#include <LibGUI/GWindow.h>
@ -6,9 +7,9 @@ GSplitter::GSplitter(Orientation orientation, GWidget* parent)
: GFrame(parent)
, m_orientation(orientation)
{
set_background_role(ColorRole::Button);
set_layout(make<GBoxLayout>(orientation));
set_fill_with_background_color(true);
set_background_color(SystemColor::Window);
layout()->set_spacing(3);
}
@ -18,14 +19,14 @@ GSplitter::~GSplitter()
void GSplitter::enter_event(CEvent&)
{
set_background_color(StylePainter::hover_highlight_color());
set_background_role(ColorRole::HoverHighlight);
window()->set_override_cursor(m_orientation == Orientation::Horizontal ? GStandardCursor::ResizeHorizontal : GStandardCursor::ResizeVertical);
update();
}
void GSplitter::leave_event(CEvent&)
{
set_background_color(SystemColor::Window);
set_background_role(ColorRole::Button);
if (!m_resizing)
window()->set_override_cursor(GStandardCursor::None);
update();

View file

@ -66,5 +66,5 @@ void GStatusBar::paint_event(GPaintEvent& event)
{
GPainter painter(*this);
painter.add_clip_rect(event.rect());
StylePainter::paint_surface(painter, rect(), !spans_entire_window_horizontally());
StylePainter::paint_surface(painter, rect(), palette(), !spans_entire_window_horizontally());
}

View file

@ -1,3 +1,4 @@
#include <LibDraw/Palette.h>
#include <LibDraw/StylePainter.h>
#include <LibGUI/GBoxLayout.h>
#include <LibGUI/GPainter.h>
@ -6,8 +7,6 @@
GTabWidget::GTabWidget(GWidget* parent)
: GWidget(parent)
{
set_fill_with_background_color(true);
set_background_color(SystemColor::Window);
}
GTabWidget::~GTabWidget()
@ -112,19 +111,19 @@ void GTabWidget::paint_event(GPaintEvent& event)
auto container_rect = this->container_rect();
auto padding_rect = container_rect;
for (int i = 0; i < container_padding(); ++i) {
painter.draw_rect(padding_rect, background_color());
painter.draw_rect(padding_rect, palette().button());
padding_rect.shrink(2, 2);
}
StylePainter::paint_frame(painter, container_rect, FrameShape::Container, FrameShadow::Raised, 2);
StylePainter::paint_frame(painter, container_rect, palette(), FrameShape::Container, FrameShadow::Raised, 2);
for (int i = 0; i < m_tabs.size(); ++i) {
if (m_tabs[i].widget == m_active_widget)
continue;
bool hovered = i == m_hovered_tab_index;
auto button_rect = this->button_rect(i);
StylePainter::paint_tab_button(painter, button_rect, false, hovered, m_tabs[i].widget->is_enabled());
painter.draw_text(button_rect.translated(0, 1), m_tabs[i].title, TextAlignment::Center, SystemColor::ButtonText);
StylePainter::paint_tab_button(painter, button_rect, palette(), false, hovered, m_tabs[i].widget->is_enabled());
painter.draw_text(button_rect.translated(0, 1), m_tabs[i].title, TextAlignment::Center, palette().button_text());
}
for (int i = 0; i < m_tabs.size(); ++i) {
@ -132,9 +131,9 @@ void GTabWidget::paint_event(GPaintEvent& event)
continue;
bool hovered = i == m_hovered_tab_index;
auto button_rect = this->button_rect(i);
StylePainter::paint_tab_button(painter, button_rect, true, hovered, m_tabs[i].widget->is_enabled());
painter.draw_text(button_rect.translated(0, 1), m_tabs[i].title, TextAlignment::Center, SystemColor::ButtonText);
painter.draw_line(button_rect.bottom_left().translated(1, 1), button_rect.bottom_right().translated(-1, 1), SystemColor::Button);
StylePainter::paint_tab_button(painter, button_rect, palette(), true, hovered, m_tabs[i].widget->is_enabled());
painter.draw_text(button_rect.translated(0, 1), m_tabs[i].title, TextAlignment::Center, palette().button_text());
painter.draw_line(button_rect.bottom_left().translated(1, 1), button_rect.bottom_right().translated(-1, 1), palette().button());
break;
}
}

View file

@ -1,5 +1,6 @@
#include <AK/StringBuilder.h>
#include <Kernel/KeyCode.h>
#include <LibDraw/Palette.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GMenu.h>
#include <LibGUI/GModel.h>
@ -12,6 +13,7 @@
GTableView::GTableView(GWidget* parent)
: GAbstractColumnView(parent)
{
set_background_role(ColorRole::Base);
}
GTableView::~GTableView()
@ -20,12 +22,13 @@ GTableView::~GTableView()
void GTableView::paint_event(GPaintEvent& event)
{
Color widget_background_color = palette().color(background_role());
GFrame::paint_event(event);
GPainter painter(*this);
painter.add_clip_rect(frame_inner_rect());
painter.add_clip_rect(event.rect());
painter.fill_rect(event.rect(), SystemColor::Base);
painter.fill_rect(event.rect(), widget_background_color);
painter.translate(frame_thickness(), frame_thickness());
painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
@ -53,15 +56,15 @@ void GTableView::paint_event(GPaintEvent& event)
Color background_color;
Color key_column_background_color;
if (is_selected_row) {
background_color = is_focused() ? Color(SystemColor::Selection) : Color::from_rgb(0x606060);
key_column_background_color = is_focused() ? Color(SystemColor::Selection) : Color::from_rgb(0x606060);
background_color = is_focused() ? palette().selection() : Color::from_rgb(0x606060);
key_column_background_color = is_focused() ? palette().selection() : Color::from_rgb(0x606060);
} else {
if (alternating_row_colors() && (painted_item_index % 2)) {
background_color = Color(SystemColor::Base).darkened(0.8f);
key_column_background_color = Color(SystemColor::Base).darkened(0.7f);
background_color = widget_background_color.darkened(0.8f);
key_column_background_color = widget_background_color.darkened(0.7f);
} else {
background_color = SystemColor::Base;
key_column_background_color = Color(SystemColor::Base).darkened(0.9f);
background_color = widget_background_color;
key_column_background_color = widget_background_color.darkened(0.9f);
}
}
painter.fill_rect(row_rect(painted_item_index), background_color);
@ -82,7 +85,7 @@ void GTableView::paint_event(GPaintEvent& event)
auto cell_index = model()->index(row_index, column_index);
if (auto* delegate = column_data(column_index).cell_painting_delegate.ptr()) {
delegate->paint(painter, cell_rect, *model(), cell_index);
delegate->paint(painter, cell_rect, palette(), *model(), cell_index);
} else {
auto data = model()->data(cell_index);
if (data.is_bitmap()) {
@ -93,9 +96,9 @@ void GTableView::paint_event(GPaintEvent& event)
} else {
Color text_color;
if (is_selected_row)
text_color = SystemColor::SelectionText;
text_color = palette().selection_text();
else
text_color = model()->data(cell_index, GModel::Role::ForegroundColor).to_color(SystemColor::WindowText);
text_color = model()->data(cell_index, GModel::Role::ForegroundColor).to_color(palette().color(foreground_role()));
painter.draw_text(cell_rect, data.to_string(), font, column_metadata.text_alignment, text_color, TextElision::Right);
}
}
@ -105,7 +108,7 @@ void GTableView::paint_event(GPaintEvent& event)
};
Rect unpainted_rect(0, header_height() + painted_item_index * item_height(), exposed_width, height());
painter.fill_rect(unpainted_rect, SystemColor::Base);
painter.fill_rect(unpainted_rect, widget_background_color);
// Untranslate the painter vertically and do the column headers.
painter.translate(0, vertical_scrollbar().value());

View file

@ -1,6 +1,7 @@
#include <AK/QuickSort.h>
#include <AK/StringBuilder.h>
#include <Kernel/KeyCode.h>
#include <LibDraw/Palette.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GClipboard.h>
#include <LibGUI/GFontDatabase.h>
@ -295,6 +296,7 @@ Rect GTextEditor::visible_text_rect_in_inner_coordinates() const
void GTextEditor::paint_event(GPaintEvent& event)
{
Color widget_background_color = palette().color(background_role());
// NOTE: This ensures that spans are updated before we look at them.
flush_pending_change_notification_if_needed();
@ -303,15 +305,15 @@ void GTextEditor::paint_event(GPaintEvent& event)
GPainter painter(*this);
painter.add_clip_rect(widget_inner_rect());
painter.add_clip_rect(event.rect());
painter.fill_rect(event.rect(), SystemColor::Base);
painter.fill_rect(event.rect(), widget_background_color);
painter.translate(frame_thickness(), frame_thickness());
auto ruler_rect = ruler_rect_in_inner_coordinates();
if (m_ruler_visible) {
painter.fill_rect(ruler_rect, Color(SystemColor::Base).darkened(0.85f));
painter.draw_line(ruler_rect.top_right(), ruler_rect.bottom_right(), Color(SystemColor::Base).darkened(0.5f));
painter.fill_rect(ruler_rect, widget_background_color.darkened(0.85f));
painter.draw_line(ruler_rect.top_right(), ruler_rect.bottom_right(), widget_background_color.darkened(0.5f));
}
painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value());
@ -333,7 +335,7 @@ void GTextEditor::paint_event(GPaintEvent& event)
String::number(i + 1),
is_current_line ? Font::default_bold_font() : font(),
TextAlignment::TopRight,
is_current_line ? Color(SystemColor::Base).darkened(0.6f) : Color(SystemColor::Base).darkened(0.7f));
is_current_line ? widget_background_color.darkened(0.6f) : widget_background_color.darkened(0.7f));
}
}
@ -369,13 +371,13 @@ void GTextEditor::paint_event(GPaintEvent& event)
size_t visual_line_index = 0;
for_each_visual_line(line_index, [&](const Rect& visual_line_rect, const StringView& visual_line_text, size_t start_of_visual_line) {
if (is_multi_line() && line_index == m_cursor.line())
painter.fill_rect(visual_line_rect, Color(SystemColor::Base).darkened(0.9f));
painter.fill_rect(visual_line_rect, widget_background_color.darkened(0.9f));
#ifdef DEBUG_GTEXTEDITOR
painter.draw_rect(visual_line_rect, Color::Cyan);
#endif
if (!document().has_spans()) {
// Fast-path for plain text
painter.draw_text(visual_line_rect, visual_line_text, m_text_alignment, SystemColor::WindowText);
painter.draw_text(visual_line_rect, visual_line_text, m_text_alignment, palette().color(foreground_role()));
} else {
int advance = font().glyph_width(' ') + font().glyph_spacing();
Rect character_rect = { visual_line_rect.location(), { font().glyph_width(' '), line_height() } };
@ -424,7 +426,7 @@ void GTextEditor::paint_event(GPaintEvent& event)
visual_line_rect.height()
};
painter.fill_rect(selection_rect, SystemColor::Selection);
painter.fill_rect(selection_rect, palette().selection());
size_t start_of_selection_within_visual_line = (size_t)max(0, (int)selection_start_column_within_line - (int)start_of_visual_line);
size_t end_of_selection_within_visual_line = selection_end_column_within_line - start_of_visual_line;
@ -434,7 +436,7 @@ void GTextEditor::paint_event(GPaintEvent& event)
end_of_selection_within_visual_line - start_of_selection_within_visual_line
};
painter.draw_text(selection_rect, visual_selected_text, TextAlignment::CenterLeft, SystemColor::SelectionText);
painter.draw_text(selection_rect, visual_selected_text, TextAlignment::CenterLeft, palette().selection_text());
}
}
++visual_line_index;

View file

@ -1,3 +1,4 @@
#include <LibDraw/Palette.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GActionGroup.h>
#include <LibGUI/GBoxLayout.h>
@ -71,8 +72,8 @@ public:
GPainter painter(*this);
painter.add_clip_rect(event.rect());
painter.translate(rect().center().x() - 1, 0);
painter.draw_line({ 0, 0 }, { 0, rect().bottom() }, SystemColor::ThreedShadow1);
painter.draw_line({ 1, 0 }, { 1, rect().bottom() }, SystemColor::ThreedHighlight);
painter.draw_line({ 0, 0 }, { 0, rect().bottom() }, palette().threed_shadow1());
painter.draw_line({ 1, 0 }, { 1, rect().bottom() }, palette().threed_highlight());
}
};
@ -90,7 +91,7 @@ void GToolBar::paint_event(GPaintEvent& event)
painter.add_clip_rect(event.rect());
if (m_has_frame)
StylePainter::paint_surface(painter, rect(), x() != 0, y() != 0);
StylePainter::paint_surface(painter, rect(), palette(), x() != 0, y() != 0);
else
painter.fill_rect(event.rect(), background_color());
painter.fill_rect(event.rect(), palette().button());
}

View file

@ -1,3 +1,4 @@
#include <LibDraw/Palette.h>
#include <LibGUI/GPainter.h>
#include <LibGUI/GScrollBar.h>
#include <LibGUI/GTreeView.h>
@ -23,6 +24,7 @@ GTreeView::MetadataForIndex& GTreeView::ensure_metadata_for_index(const GModelIn
GTreeView::GTreeView(GWidget* parent)
: GAbstractColumnView(parent)
{
set_background_role(ColorRole::Base);
set_size_columns_to_fit_content(true);
set_headers_visible(false);
m_expand_bitmap = GraphicsBitmap::load_from_file("/res/icons/treeview-expand.png");
@ -146,7 +148,7 @@ void GTreeView::paint_event(GPaintEvent& event)
GPainter painter(*this);
painter.add_clip_rect(frame_inner_rect());
painter.add_clip_rect(event.rect());
painter.fill_rect(event.rect(), SystemColor::Base);
painter.fill_rect(event.rect(), palette().color(background_role()));
if (!model())
return;
@ -178,21 +180,21 @@ void GTreeView::paint_event(GPaintEvent& event)
bool is_selected_row = selection().contains(index);
Color text_color = SystemColor::WindowText;
Color text_color = palette().color(foreground_role());
if (is_selected_row)
text_color = Color::White;
Color background_color;
Color key_column_background_color;
if (is_selected_row) {
background_color = is_focused() ? Color(SystemColor::Selection) : Color::from_rgb(0x606060);
key_column_background_color = is_focused() ? Color(SystemColor::Selection) : Color::from_rgb(0x606060);
background_color = is_focused() ? palette().selection() : Color::from_rgb(0x606060);
key_column_background_color = is_focused() ? palette().selection() : Color::from_rgb(0x606060);
} else {
if (alternating_row_colors() && (painted_row_index % 2)) {
background_color = Color(220, 220, 220);
key_column_background_color = Color(200, 200, 200);
} else {
background_color = SystemColor::Base;
background_color = palette().color(background_role());
key_column_background_color = Color(220, 220, 220);
}
}
@ -215,7 +217,7 @@ void GTreeView::paint_event(GPaintEvent& event)
auto cell_index = model.sibling(index.row(), column_index, index.parent());
if (auto* delegate = column_data(column_index).cell_painting_delegate.ptr()) {
delegate->paint(painter, cell_rect, model, cell_index);
delegate->paint(painter, cell_rect, palette(), model, cell_index);
} else {
auto data = model.data(cell_index);
@ -226,7 +228,7 @@ void GTreeView::paint_event(GPaintEvent& event)
painter.blit(cell_rect.location(), *bitmap, bitmap->rect());
} else {
if (!is_selected_row)
text_color = model.data(cell_index, GModel::Role::ForegroundColor).to_color(SystemColor::WindowText);
text_color = model.data(cell_index, GModel::Role::ForegroundColor).to_color(palette().color(foreground_role()));
painter.draw_text(cell_rect, data.to_string(), font, column_metadata.text_alignment, text_color, TextElision::Right);
}
}

View file

@ -1,26 +1,26 @@
#include <AK/Assertions.h>
#include <AK/JsonObject.h>
#include <LibDraw/GraphicsBitmap.h>
#include <LibDraw/Palette.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GApplication.h>
#include <LibGUI/GButton.h>
#include <LibGUI/GCheckBox.h>
#include <LibGUI/GEvent.h>
#include <LibGUI/GGroupBox.h>
#include <LibGUI/GLabel.h>
#include <LibGUI/GLayout.h>
#include <LibGUI/GMenu.h>
#include <LibGUI/GPainter.h>
#include <LibGUI/GWidget.h>
#include <LibGUI/GWindow.h>
#include <LibGUI/GWindowServerConnection.h>
#include <unistd.h>
#include <LibGUI/GButton.h>
#include <LibGUI/GCheckBox.h>
#include <LibGUI/GGroupBox.h>
#include <LibGUI/GLabel.h>
#include <LibGUI/GRadioButton.h>
#include <LibGUI/GScrollBar.h>
#include <LibGUI/GSlider.h>
#include <LibGUI/GSpinBox.h>
#include <LibGUI/GTextBox.h>
#include <LibGUI/GWidget.h>
#include <LibGUI/GWindow.h>
#include <LibGUI/GWindowServerConnection.h>
#include <unistd.h>
REGISTER_GWIDGET(GButton)
REGISTER_GWIDGET(GCheckBox)
@ -67,9 +67,8 @@ const GWidgetClassRegistration* GWidgetClassRegistration::find(const String& cla
GWidget::GWidget(GWidget* parent)
: CObject(parent, true)
, m_font(Font::default_font())
, m_palette(GApplication::the().palette())
{
m_background_color = SystemColor::Window;
m_foreground_color = SystemColor::WindowText;
}
GWidget::~GWidget()
@ -173,7 +172,7 @@ void GWidget::handle_paint_event(GPaintEvent& event)
ASSERT(is_visible());
if (fill_with_background_color()) {
GPainter painter(*this);
painter.fill_rect(event.rect(), background_color());
painter.fill_rect(event.rect(), palette().color(background_role()));
} else {
#ifdef DEBUG_WIDGET_UNDERDRAW
// FIXME: This is a bit broken.
@ -693,3 +692,8 @@ Vector<GWidget*> GWidget::child_widgets() const
}
return widgets;
}
void GWidget::set_palette(const Palette& palette)
{
m_palette = palette;
}

View file

@ -9,6 +9,7 @@
#include <LibDraw/Font.h>
#include <LibDraw/Orientation.h>
#include <LibDraw/Rect.h>
#include <LibDraw/SystemTheme.h>
#include <LibGUI/GEvent.h>
#include <LibGUI/GShortcut.h>
@ -16,11 +17,12 @@
extern GWidgetClassRegistration registration_##class_name; \
GWidgetClassRegistration registration_##class_name(#class_name, [](GWidget* parent) { return class_name::construct(parent); });
class GraphicsBitmap;
class GAction;
class GLayout;
class GMenu;
class GWindow;
class GraphicsBitmap;
class Palette;
enum class SizePolicy {
Fixed,
@ -149,6 +151,12 @@ public:
void move_by(int x, int y) { move_by({ x, y }); }
void move_by(const Point& delta) { set_relative_rect({ relative_position().translated(delta), size() }); }
ColorRole background_role() const { return m_background_role; }
void set_background_role(ColorRole role) { m_background_role = role; }
ColorRole foreground_role() const { return m_foreground_role; }
void set_foreground_role(ColorRole role) { m_foreground_role = role; }
Color background_color() const { return m_background_color; }
Color foreground_color() const { return m_foreground_color; }
@ -230,6 +238,9 @@ public:
void do_layout();
const Palette& palette() const { return *m_palette; }
void set_palette(const Palette&);
protected:
explicit GWidget(GWidget* parent = nullptr);
@ -271,6 +282,8 @@ private:
OwnPtr<GLayout> m_layout;
Rect m_relative_rect;
ColorRole m_background_role { ColorRole::Window };
ColorRole m_foreground_role { ColorRole::WindowText };
Color m_background_color;
Color m_foreground_color;
NonnullRefPtr<Font> m_font;
@ -288,6 +301,8 @@ private:
bool m_updates_enabled { true };
HashMap<GShortcut, GAction*> m_local_shortcut_actions;
NonnullRefPtr<Palette> m_palette;
};
template<>

View file

@ -1,3 +1,4 @@
#include <LibDraw/Palette.h>
#include <LibDraw/SystemTheme.h>
#include <LibGUI/GAction.h>
#include <LibGUI/GApplication.h>
@ -25,6 +26,7 @@ static void set_system_theme_from_shared_buffer_id(int id)
auto system_theme = SharedBuffer::create_from_shared_buffer_id(id);
ASSERT(system_theme);
set_system_theme(*system_theme);
GApplication::the().set_system_palette(*system_theme);
}
void GWindowServerConnection::handshake()