Serenity Operating System
at portability 147 lines 6.5 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/StringBuilder.h> 28#include <Kernel/KeyCode.h> 29#include <LibGfx/Palette.h> 30#include <LibGUI/Action.h> 31#include <LibGUI/Menu.h> 32#include <LibGUI/Model.h> 33#include <LibGUI/Painter.h> 34#include <LibGUI/ScrollBar.h> 35#include <LibGUI/TableView.h> 36#include <LibGUI/TextBox.h> 37#include <LibGUI/Window.h> 38 39namespace GUI { 40 41TableView::TableView() 42{ 43 set_background_role(ColorRole::Base); 44 set_foreground_role(ColorRole::BaseText); 45} 46 47TableView::~TableView() 48{ 49} 50 51void TableView::paint_event(PaintEvent& event) 52{ 53 Color widget_background_color = palette().color(background_role()); 54 Frame::paint_event(event); 55 56 Painter painter(*this); 57 painter.add_clip_rect(frame_inner_rect()); 58 painter.add_clip_rect(event.rect()); 59 painter.fill_rect(event.rect(), widget_background_color); 60 painter.translate(frame_thickness(), frame_thickness()); 61 painter.translate(-horizontal_scrollbar().value(), -vertical_scrollbar().value()); 62 63 if (!model()) 64 return; 65 66 int exposed_width = max(content_size().width(), width()); 67 int y_offset = header_height(); 68 69 bool dummy; 70 int first_visible_row = index_at_event_position(frame_inner_rect().top_left(), dummy).row(); 71 int last_visible_row = index_at_event_position(frame_inner_rect().bottom_right(), dummy).row(); 72 73 if (first_visible_row == -1) 74 first_visible_row = 0; 75 if (last_visible_row == -1) 76 last_visible_row = model()->row_count() - 1; 77 78 int painted_item_index = first_visible_row; 79 80 for (int row_index = first_visible_row; row_index <= last_visible_row; ++row_index) { 81 bool is_selected_row = selection().contains_row(row_index); 82 int y = y_offset + painted_item_index * item_height(); 83 84 Color background_color; 85 Color key_column_background_color; 86 if (is_selected_row) { 87 background_color = is_focused() ? palette().selection() : palette().inactive_selection(); 88 key_column_background_color = is_focused() ? palette().selection() : palette().inactive_selection(); 89 } else { 90 if (alternating_row_colors() && (painted_item_index % 2)) { 91 background_color = widget_background_color.darkened(0.8f); 92 key_column_background_color = widget_background_color.darkened(0.7f); 93 } else { 94 background_color = widget_background_color; 95 key_column_background_color = widget_background_color.darkened(0.9f); 96 } 97 } 98 painter.fill_rect(row_rect(painted_item_index), background_color); 99 100 int x_offset = 0; 101 for (int column_index = 0; column_index < model()->column_count(); ++column_index) { 102 if (is_column_hidden(column_index)) 103 continue; 104 auto column_metadata = model()->column_metadata(column_index); 105 int column_width = this->column_width(column_index); 106 const Gfx::Font& font = column_metadata.font ? *column_metadata.font : this->font(); 107 bool is_key_column = model()->key_column() == column_index; 108 Gfx::Rect cell_rect(horizontal_padding() + x_offset, y, column_width, item_height()); 109 if (is_key_column) { 110 auto cell_rect_for_fill = cell_rect.inflated(horizontal_padding() * 2, 0); 111 painter.fill_rect(cell_rect_for_fill, key_column_background_color); 112 } 113 auto cell_index = model()->index(row_index, column_index); 114 115 if (auto* delegate = column_data(column_index).cell_painting_delegate.ptr()) { 116 delegate->paint(painter, cell_rect, palette(), *model(), cell_index); 117 } else { 118 auto data = model()->data(cell_index); 119 if (data.is_bitmap()) { 120 painter.blit(cell_rect.location(), data.as_bitmap(), data.as_bitmap().rect()); 121 } else if (data.is_icon()) { 122 if (auto bitmap = data.as_icon().bitmap_for_size(16)) 123 painter.blit(cell_rect.location(), *bitmap, bitmap->rect()); 124 } else { 125 Color text_color; 126 if (is_selected_row) 127 text_color = is_focused() ? palette().selection_text() : palette().inactive_selection_text(); 128 else 129 text_color = model()->data(cell_index, Model::Role::ForegroundColor).to_color(palette().color(foreground_role())); 130 painter.draw_text(cell_rect, data.to_string(), font, column_metadata.text_alignment, text_color, Gfx::TextElision::Right); 131 } 132 } 133 x_offset += column_width + horizontal_padding() * 2; 134 } 135 ++painted_item_index; 136 }; 137 138 Gfx::Rect unpainted_rect(0, header_height() + painted_item_index * item_height(), exposed_width, height()); 139 painter.fill_rect(unpainted_rect, widget_background_color); 140 141 // Untranslate the painter vertically and do the column headers. 142 painter.translate(0, vertical_scrollbar().value()); 143 if (headers_visible()) 144 paint_headers(painter); 145} 146 147}