1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 12:38:12 +00:00

LibGUI: Add GTableModel::Role::ForegroundColor.

This makes it possible to specify the text color for each table cell.
Use this to make the IRCClient show unread window list items in red.
This commit is contained in:
Andreas Kling 2019-03-18 04:54:07 +01:00
parent f4b8e4966f
commit d466f2634d
10 changed files with 120 additions and 63 deletions

View file

@ -151,18 +151,18 @@ GVariant DirectoryTableModel::data(const GModelIndex& index, Role role) const
} }
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
ASSERT(role == Role::Display); if (role == Role::Display) {
switch (index.column()) { switch (index.column()) {
case Column::Icon: return icon_for(entry); case Column::Icon: return icon_for(entry);
case Column::Name: return entry.name; case Column::Name: return entry.name;
case Column::Size: return (int)entry.size; case Column::Size: return (int)entry.size;
case Column::Owner: return name_for_uid(entry.uid); case Column::Owner: return name_for_uid(entry.uid);
case Column::Group: return name_for_gid(entry.gid); case Column::Group: return name_for_gid(entry.gid);
case Column::Permissions: return permission_string(entry.mode); case Column::Permissions: return permission_string(entry.mode);
case Column::Inode: return (int)entry.inode; case Column::Inode: return (int)entry.inode;
}
} }
ASSERT_NOT_REACHED(); return { };
} }
void DirectoryTableModel::update() void DirectoryTableModel::update()

View file

@ -120,7 +120,7 @@ void IRCAppWindow::setup_widgets()
m_window_list->set_alternating_row_colors(false); m_window_list->set_alternating_row_colors(false);
m_window_list->set_model(OwnPtr<IRCWindowListModel>(m_client.client_window_list_model())); m_window_list->set_model(OwnPtr<IRCWindowListModel>(m_client.client_window_list_model()));
m_window_list->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); m_window_list->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill);
m_window_list->set_preferred_size({ 120, 0 }); m_window_list->set_preferred_size({ 100, 0 });
m_client.client_window_list_model()->on_activation = [this] (IRCWindow& window) { m_client.client_window_list_model()->on_activation = [this] (IRCWindow& window) {
m_container->set_active_widget(&window); m_container->set_active_widget(&window);
window.clear_unread_count(); window.clear_unread_count();

View file

@ -39,12 +39,14 @@ GTableModel::ColumnMetadata IRCChannelMemberListModel::column_metadata(int colum
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
GVariant IRCChannelMemberListModel::data(const GModelIndex& index, Role) const GVariant IRCChannelMemberListModel::data(const GModelIndex& index, Role role) const
{ {
switch (index.column()) { if (role == Role::Display) {
case Column::Name: return m_channel.member_at(index.row()); switch (index.column()) {
case Column::Name: return m_channel.member_at(index.row());
}
} }
ASSERT_NOT_REACHED(); return { };
} }
void IRCChannelMemberListModel::update() void IRCChannelMemberListModel::update()

View file

@ -43,21 +43,23 @@ GTableModel::ColumnMetadata IRCLogBufferModel::column_metadata(int column) const
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
GVariant IRCLogBufferModel::data(const GModelIndex& index, Role) const GVariant IRCLogBufferModel::data(const GModelIndex& index, Role role) const
{ {
auto& entry = m_log_buffer->at(index.row()); if (role == Role::Display) {
switch (index.column()) { auto& entry = m_log_buffer->at(index.row());
case Column::Timestamp: { switch (index.column()) {
auto* tm = localtime(&entry.timestamp); case Column::Timestamp: {
return String::format("%02u:%02u:%02u", tm->tm_hour, tm->tm_min, tm->tm_sec); auto* tm = localtime(&entry.timestamp);
return String::format("%02u:%02u:%02u", tm->tm_hour, tm->tm_min, tm->tm_sec);
}
case Column::Name:
if (entry.sender.is_empty())
return String::empty();
return String::format("<%c%s>", entry.prefix ? entry.prefix : ' ', entry.sender.characters());
case Column::Text: return entry.text;
}
} }
case Column::Name: return { };
if (entry.sender.is_empty())
return String::empty();
return String::format("<%c%s>", entry.prefix ? entry.prefix : ' ', entry.sender.characters());
case Column::Text: return entry.text;
}
ASSERT_NOT_REACHED();
} }
void IRCLogBufferModel::update() void IRCLogBufferModel::update()

View file

@ -40,17 +40,29 @@ GTableModel::ColumnMetadata IRCWindowListModel::column_metadata(int column) cons
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
GVariant IRCWindowListModel::data(const GModelIndex& index, Role) const GVariant IRCWindowListModel::data(const GModelIndex& index, Role role) const
{ {
switch (index.column()) { if (role == Role::Display) {
case Column::Name: { switch (index.column()) {
auto& window = m_client.window_at(index.row()); case Column::Name: {
if (!window.unread_count()) auto& window = m_client.window_at(index.row());
if (window.unread_count())
return String::format("%s (%d)", window.name().characters(), window.unread_count());
return window.name(); return window.name();
return String::format("%s (%d)\n", window.name().characters(), window.unread_count()); }
}
} }
if (role == Role::ForegroundColor) {
switch (index.column()) {
case Column::Name: {
auto& window = m_client.window_at(index.row());
if (window.unread_count())
return Color(Color::Red);
return Color(Color::Black);
}
}
} }
ASSERT_NOT_REACHED(); return { };
} }
void IRCWindowListModel::update() void IRCWindowListModel::update()

View file

@ -99,25 +99,28 @@ GVariant ProcessTableModel::data(const GModelIndex& index, Role role) const
return { }; return { };
} }
switch (index.column()) { if (role == Role::Display) {
case Column::Icon: return *m_generic_process_icon; switch (index.column()) {
case Column::PID: return process.current_state.pid; case Column::Icon: return *m_generic_process_icon;
case Column::State: return process.current_state.state; case Column::PID: return process.current_state.pid;
case Column::User: return process.current_state.user; case Column::State: return process.current_state.state;
case Column::Priority: case Column::User: return process.current_state.user;
if (process.current_state.priority == "High") case Column::Priority:
return *m_high_priority_icon; if (process.current_state.priority == "High")
if (process.current_state.priority == "Low") return *m_high_priority_icon;
return *m_low_priority_icon; if (process.current_state.priority == "Low")
if (process.current_state.priority == "Normal") return *m_low_priority_icon;
return *m_normal_priority_icon; if (process.current_state.priority == "Normal")
return process.current_state.priority; return *m_normal_priority_icon;
case Column::Linear: return pretty_byte_size(process.current_state.linear); return process.current_state.priority;
case Column::Physical: return pretty_byte_size(process.current_state.physical); case Column::Linear: return pretty_byte_size(process.current_state.linear);
case Column::CPU: return process.current_state.cpu_percent; case Column::Physical: return pretty_byte_size(process.current_state.physical);
case Column::Name: return process.current_state.name; case Column::CPU: return process.current_state.cpu_percent;
case Column::Name: return process.current_state.name;
}
} }
ASSERT_NOT_REACHED();
return { };
} }
void ProcessTableModel::update() void ProcessTableModel::update()

View file

@ -42,7 +42,7 @@ public:
const Font* font { nullptr }; const Font* font { nullptr };
}; };
enum class Role { Display, Sort, Custom }; enum class Role { Display, Sort, Custom, ForegroundColor, BackgroundColor };
virtual ~GTableModel(); virtual ~GTableModel();

View file

@ -116,15 +116,14 @@ void GTableView::paint_event(GPaintEvent& event)
int y_offset = header_height(); int y_offset = header_height();
for (int row_index = 0; row_index < m_model->row_count(); ++row_index) { for (int row_index = 0; row_index < m_model->row_count(); ++row_index) {
bool is_selected_row = row_index == m_model->selected_index().row();
int y = y_offset + painted_item_index * item_height(); int y = y_offset + painted_item_index * item_height();
Color background_color; Color background_color;
Color key_column_background_color; Color key_column_background_color;
Color text_color; if (is_selected_row) {
if (row_index == m_model->selected_index().row()) {
background_color = is_focused() ? Color::from_rgb(0x84351a) : Color::from_rgb(0x606060); background_color = is_focused() ? Color::from_rgb(0x84351a) : Color::from_rgb(0x606060);
key_column_background_color = is_focused() ? Color::from_rgb(0x84351a) : Color::from_rgb(0x606060); key_column_background_color = is_focused() ? Color::from_rgb(0x84351a) : Color::from_rgb(0x606060);
text_color = Color::White;
} else { } else {
if (alternating_row_colors() && (painted_item_index % 2)) { if (alternating_row_colors() && (painted_item_index % 2)) {
background_color = Color(210, 210, 210); background_color = Color(210, 210, 210);
@ -133,10 +132,9 @@ void GTableView::paint_event(GPaintEvent& event)
background_color = Color::White; background_color = Color::White;
key_column_background_color = Color(235, 235, 235); key_column_background_color = Color(235, 235, 235);
} }
text_color = Color::Black;
} }
painter.fill_rect(row_rect(painted_item_index), background_color); painter.fill_rect(row_rect(painted_item_index), background_color);
int x_offset = 0; int x_offset = 0;
for (int column_index = 0; column_index < m_model->column_count(); ++column_index) { for (int column_index = 0; column_index < m_model->column_count(); ++column_index) {
auto column_metadata = m_model->column_metadata(column_index); auto column_metadata = m_model->column_metadata(column_index);
@ -148,11 +146,18 @@ void GTableView::paint_event(GPaintEvent& event)
auto cell_rect_for_fill = cell_rect.inflated(horizontal_padding() * 2, 0); auto cell_rect_for_fill = cell_rect.inflated(horizontal_padding() * 2, 0);
painter.fill_rect(cell_rect_for_fill, key_column_background_color); painter.fill_rect(cell_rect_for_fill, key_column_background_color);
} }
auto data = m_model->data({ row_index, column_index }); GModelIndex cell_index(row_index, column_index);
if (data.is_bitmap()) auto data = m_model->data(cell_index);
if (data.is_bitmap()) {
painter.blit(cell_rect.location(), data.as_bitmap(), data.as_bitmap().rect()); painter.blit(cell_rect.location(), data.as_bitmap(), data.as_bitmap().rect());
else } else {
Color text_color;
if (is_selected_row)
text_color = Color::White;
else
text_color = m_model->data(cell_index, GTableModel::Role::ForegroundColor).to_color(Color::Black);
painter.draw_text(cell_rect, data.to_string(), font, column_metadata.text_alignment, text_color); painter.draw_text(cell_rect, data.to_string(), font, column_metadata.text_alignment, text_color);
}
x_offset += column_width + horizontal_padding() * 2; x_offset += column_width + horizontal_padding() * 2;
} }
++painted_item_index; ++painted_item_index;

View file

@ -1,5 +1,9 @@
#include <LibGUI/GVariant.h> #include <LibGUI/GVariant.h>
GVariant::GVariant()
{
}
GVariant::~GVariant() GVariant::~GVariant()
{ {
switch (m_type) { switch (m_type) {
@ -48,6 +52,12 @@ GVariant::GVariant(const GraphicsBitmap& value)
AK::retain_if_not_null(m_value.as_bitmap); AK::retain_if_not_null(m_value.as_bitmap);
} }
GVariant::GVariant(Color color)
: m_type(Type::Color)
{
m_value.as_color = color.value();
}
bool GVariant::operator==(const GVariant& other) const bool GVariant::operator==(const GVariant& other) const
{ {
if (m_type != other.m_type) if (m_type != other.m_type)
@ -63,6 +73,8 @@ bool GVariant::operator==(const GVariant& other) const
return as_string() == other.as_string(); return as_string() == other.as_string();
case Type::Bitmap: case Type::Bitmap:
return m_value.as_bitmap == other.m_value.as_bitmap; return m_value.as_bitmap == other.m_value.as_bitmap;
case Type::Color:
return m_value.as_color == other.m_value.as_color;
case Type::Invalid: case Type::Invalid:
break; break;
} }
@ -85,6 +97,8 @@ bool GVariant::operator<(const GVariant& other) const
case Type::Bitmap: case Type::Bitmap:
// FIXME: Maybe compare bitmaps somehow differently? // FIXME: Maybe compare bitmaps somehow differently?
return m_value.as_bitmap < other.m_value.as_bitmap; return m_value.as_bitmap < other.m_value.as_bitmap;
case Type::Color:
return m_value.as_color < other.m_value.as_color;
case Type::Invalid: case Type::Invalid:
break; break;
} }
@ -104,6 +118,8 @@ String GVariant::to_string() const
return as_string(); return as_string();
case Type::Bitmap: case Type::Bitmap:
return "[GraphicsBitmap]"; return "[GraphicsBitmap]";
case Type::Color:
return as_color().to_string();
case Type::Invalid: case Type::Invalid:
break; break;
} }

View file

@ -11,6 +11,7 @@ public:
GVariant(int); GVariant(int);
GVariant(const String&); GVariant(const String&);
GVariant(const GraphicsBitmap&); GVariant(const GraphicsBitmap&);
GVariant(Color);
~GVariant(); ~GVariant();
enum class Type { enum class Type {
@ -20,6 +21,7 @@ public:
Float, Float,
String, String,
Bitmap, Bitmap,
Color,
}; };
bool is_valid() const { return m_type != Type::Invalid; } bool is_valid() const { return m_type != Type::Invalid; }
@ -28,6 +30,7 @@ public:
bool is_float() const { return m_type == Type::Float; } bool is_float() const { return m_type == Type::Float; }
bool is_string() const { return m_type == Type::String; } bool is_string() const { return m_type == Type::String; }
bool is_bitmap() const { return m_type == Type::Bitmap; } bool is_bitmap() const { return m_type == Type::Bitmap; }
bool is_color() const { return m_type == Type::Color; }
Type type() const { return m_type; } Type type() const { return m_type; }
bool as_bool() const bool as_bool() const
@ -60,6 +63,19 @@ public:
return *m_value.as_bitmap; return *m_value.as_bitmap;
} }
Color as_color() const
{
ASSERT(type() == Type::Color);
return Color::from_rgba(m_value.as_color);
}
Color to_color(Color default_value) const
{
if (type() == Type::Color)
return as_color();
return default_value;
}
String to_string() const; String to_string() const;
bool operator==(const GVariant&) const; bool operator==(const GVariant&) const;
@ -72,6 +88,7 @@ private:
bool as_bool; bool as_bool;
int as_int; int as_int;
float as_float; float as_float;
RGBA32 as_color;
} m_value; } m_value;
Type m_type { Type::Invalid }; Type m_type { Type::Invalid };