summaryrefslogtreecommitdiff
path: root/Libraries/LibGUI/GAbstractTableView.h
blob: 77ce48a70dbb013bc863f434e89ba9d94151cd22 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include <LibGUI/GAbstractView.h>

namespace GUI {

class Painter;

// FIXME: Rename this to something without "table cell" in the name.
class TableCellPaintingDelegate {
public:
    virtual ~TableCellPaintingDelegate() {}

    virtual void paint(Painter&, const Gfx::Rect&, const Palette&, const Model&, const ModelIndex&) = 0;
};

class AbstractTableView : public AbstractView {
public:
    int item_height() const { return 16; }

    bool alternating_row_colors() const { return m_alternating_row_colors; }
    void set_alternating_row_colors(bool b) { m_alternating_row_colors = b; }

    int header_height() const { return m_headers_visible ? 16 : 0; }

    bool headers_visible() const { return m_headers_visible; }
    void set_headers_visible(bool headers_visible) { m_headers_visible = headers_visible; }

    bool is_column_hidden(int) const;
    void set_column_hidden(int, bool);

    void set_size_columns_to_fit_content(bool b) { m_size_columns_to_fit_content = b; }
    bool size_columns_to_fit_content() const { return m_size_columns_to_fit_content; }

    void set_cell_painting_delegate(int column, OwnPtr<TableCellPaintingDelegate>&&);

    int horizontal_padding() const { return m_horizontal_padding; }

    Gfx::Point adjusted_position(const Gfx::Point&) const;

    virtual Gfx::Rect content_rect(const ModelIndex&) const override;
    Gfx::Rect content_rect(int row, int column) const;
    Gfx::Rect row_rect(int item_index) const;

    void scroll_into_view(const ModelIndex&, Orientation);

    virtual ModelIndex index_at_event_position(const Gfx::Point&, bool& is_toggle) const;
    virtual ModelIndex index_at_event_position(const Gfx::Point&) const override;

protected:
    virtual ~AbstractTableView() override;
    explicit AbstractTableView(Widget* parent);

    virtual void did_update_model() override;
    virtual void mouseup_event(MouseEvent&) override;
    virtual void mousedown_event(MouseEvent&) override;
    virtual void mousemove_event(MouseEvent&) override;
    virtual void doubleclick_event(MouseEvent&) override;
    virtual void keydown_event(KeyEvent&) override;
    virtual void leave_event(Core::Event&) override;
    virtual void context_menu_event(ContextMenuEvent&) override;

    virtual void toggle_index(const ModelIndex&) {}

    void paint_headers(Painter&);
    Gfx::Rect header_rect(int column) const;

    static const Gfx::Font& header_font();
    void update_headers();
    void set_hovered_header_index(int);

    struct ColumnData {
        int width { 0 };
        bool has_initialized_width { false };
        bool visibility { true };
        RefPtr<Action> visibility_action;
        OwnPtr<TableCellPaintingDelegate> cell_painting_delegate;
    };
    ColumnData& column_data(int column) const;

    mutable Vector<ColumnData> m_column_data;

    Menu& ensure_header_context_menu();
    RefPtr<Menu> m_header_context_menu;

    Gfx::Rect column_resize_grabbable_rect(int) const;
    int column_width(int) const;
    void update_content_size();
    virtual void update_column_sizes();
    virtual int item_count() const;

private:
    bool m_headers_visible { true };
    bool m_size_columns_to_fit_content { false };
    bool m_in_column_resize { false };
    bool m_alternating_row_colors { true };
    int m_horizontal_padding { 5 };
    Gfx::Point m_column_resize_origin;
    int m_column_resize_original_width { 0 };
    int m_resizing_column { -1 };
    int m_pressed_column_header_index { -1 };
    bool m_pressed_column_header_is_pressed { false };
    int m_hovered_column_header_index { -1 };
};

}