Procházet zdrojové kódy

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.
Andreas Kling před 6 roky
rodič
revize
d466f2634d

+ 11 - 11
Applications/FileManager/DirectoryTableModel.cpp

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

+ 1 - 1
Applications/IRCClient/IRCAppWindow.cpp

@@ -120,7 +120,7 @@ void IRCAppWindow::setup_widgets()
     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_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_container->set_active_widget(&window);
         window.clear_unread_count();

+ 6 - 4
Applications/IRCClient/IRCChannelMemberListModel.cpp

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

+ 15 - 13
Applications/IRCClient/IRCLogBufferModel.cpp

@@ -43,21 +43,23 @@ GTableModel::ColumnMetadata IRCLogBufferModel::column_metadata(int column) const
     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());
-    switch (index.column()) {
-    case Column::Timestamp: {
-        auto* tm = localtime(&entry.timestamp);
-        return String::format("%02u:%02u:%02u", tm->tm_hour, tm->tm_min, tm->tm_sec);
+    if (role == Role::Display) {
+        auto& entry = m_log_buffer->at(index.row());
+        switch (index.column()) {
+        case Column::Timestamp: {
+            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:
-        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();
+    return { };
 }
 
 void IRCLogBufferModel::update()

+ 19 - 7
Applications/IRCClient/IRCWindowListModel.cpp

@@ -40,17 +40,29 @@ GTableModel::ColumnMetadata IRCWindowListModel::column_metadata(int column) cons
     ASSERT_NOT_REACHED();
 }
 
-GVariant IRCWindowListModel::data(const GModelIndex& index, Role) const
+GVariant IRCWindowListModel::data(const GModelIndex& index, Role role) const
 {
-    switch (index.column()) {
-    case Column::Name: {
-        auto& window = m_client.window_at(index.row());
-        if (!window.unread_count())
+    if (role == Role::Display) {
+        switch (index.column()) {
+        case Column::Name: {
+            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 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()

+ 21 - 18
Applications/ProcessManager/ProcessTableModel.cpp

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

+ 1 - 1
LibGUI/GTableModel.h

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

+ 13 - 8
LibGUI/GTableView.cpp

@@ -116,15 +116,14 @@ void GTableView::paint_event(GPaintEvent& event)
     int y_offset = header_height();
 
     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();
 
         Color background_color;
         Color key_column_background_color;
-        Color text_color;
-        if (row_index == m_model->selected_index().row()) {
+        if (is_selected_row) {
             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 {
             if (alternating_row_colors() && (painted_item_index % 2)) {
                 background_color = Color(210, 210, 210);
@@ -133,10 +132,9 @@ void GTableView::paint_event(GPaintEvent& event)
                 background_color = Color::White;
                 key_column_background_color = Color(235, 235, 235);
             }
-            text_color = Color::Black;
         }
-
         painter.fill_rect(row_rect(painted_item_index), background_color);
+
         int x_offset = 0;
         for (int column_index = 0; column_index < m_model->column_count(); ++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);
                 painter.fill_rect(cell_rect_for_fill, key_column_background_color);
             }
-            auto data = m_model->data({ row_index, column_index });
-            if (data.is_bitmap())
+            GModelIndex cell_index(row_index, column_index);
+            auto data = m_model->data(cell_index);
+            if (data.is_bitmap()) {
                 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);
+            }
             x_offset += column_width + horizontal_padding() * 2;
         }
         ++painted_item_index;

+ 16 - 0
LibGUI/GVariant.cpp

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

+ 17 - 0
LibGUI/GVariant.h

@@ -11,6 +11,7 @@ public:
     GVariant(int);
     GVariant(const String&);
     GVariant(const GraphicsBitmap&);
+    GVariant(Color);
     ~GVariant();
 
     enum class Type {
@@ -20,6 +21,7 @@ public:
         Float,
         String,
         Bitmap,
+        Color,
     };
 
     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_string() const { return m_type == Type::String; }
     bool is_bitmap() const { return m_type == Type::Bitmap; }
+    bool is_color() const { return m_type == Type::Color; }
     Type type() const { return m_type; }
 
     bool as_bool() const
@@ -60,6 +63,19 @@ public:
         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;
 
     bool operator==(const GVariant&) const;
@@ -72,6 +88,7 @@ private:
         bool as_bool;
         int as_int;
         float as_float;
+        RGBA32 as_color;
     } m_value; 
 
     Type m_type { Type::Invalid };