Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Function.h>
10#include <LibGUI/AbstractScrollableWidget.h>
11#include <LibGUI/Model.h>
12#include <LibGUI/ModelSelection.h>
13#include <LibGfx/TextElision.h>
14
15namespace GUI {
16
17class AbstractView
18 : public AbstractScrollableWidget
19 , public ModelClient {
20
21 C_OBJECT_ABSTRACT(AbstractView);
22
23public:
24 enum class CursorMovement {
25 Up,
26 Down,
27 Left,
28 Right,
29 Home,
30 End,
31 PageUp,
32 PageDown,
33 };
34
35 enum class SelectionUpdate {
36 None,
37 Set,
38 Shift,
39 Ctrl,
40 ClearIfNotSelected
41 };
42
43 enum class SelectionBehavior {
44 SelectItems,
45 SelectRows,
46 };
47
48 enum class SelectionMode {
49 SingleSelection,
50 MultiSelection,
51 NoSelection,
52 };
53
54 virtual void move_cursor(CursorMovement, SelectionUpdate) { }
55
56 void set_model(RefPtr<Model>);
57 Model* model() { return m_model.ptr(); }
58 Model const* model() const { return m_model.ptr(); }
59
60 ModelSelection& selection() { return m_selection; }
61 ModelSelection const& selection() const { return m_selection; }
62 virtual void select_all() { }
63
64 void activate(ModelIndex const&);
65 void activate_selected();
66
67 bool is_editable() const { return m_editable; }
68 void set_editable(bool editable) { m_editable = editable; }
69
70 bool is_searchable() const;
71 void set_searchable(bool);
72
73 enum EditTrigger {
74 None = 0,
75 DoubleClicked = 1 << 0,
76 EditKeyPressed = 1 << 1,
77 AnyKeyPressed = 1 << 2,
78 };
79
80 unsigned edit_triggers() const { return m_edit_triggers; }
81 void set_edit_triggers(unsigned);
82
83 SelectionBehavior selection_behavior() const { return m_selection_behavior; }
84 void set_selection_behavior(SelectionBehavior behavior) { m_selection_behavior = behavior; }
85
86 SelectionMode selection_mode() const { return m_selection_mode; }
87 void set_selection_mode(SelectionMode);
88
89 virtual void model_did_update(unsigned flags) override;
90 virtual void did_update_selection();
91
92 virtual Gfx::IntRect content_rect(ModelIndex const&) const { return {}; }
93 virtual Gfx::IntRect editing_rect(ModelIndex const& index) const { return content_rect(index); }
94 virtual Gfx::IntRect paint_invalidation_rect(ModelIndex const& index) const { return content_rect(index); }
95
96 virtual ModelIndex index_at_event_position(Gfx::IntPoint) const { return {}; }
97 void begin_editing(ModelIndex const&);
98 void stop_editing();
99
100 void set_activates_on_selection(bool b) { m_activates_on_selection = b; }
101 bool activates_on_selection() const { return m_activates_on_selection; }
102
103 Function<void()> on_selection_change;
104 Function<void(ModelIndex const&)> on_activation;
105 Function<void(ModelIndex const&, ContextMenuEvent const&)> on_context_menu_request;
106 Function<void(ModelIndex const&, DropEvent const&)> on_drop;
107
108 Function<OwnPtr<ModelEditingDelegate>(ModelIndex const&)> aid_create_editing_delegate;
109
110 void notify_selection_changed(Badge<ModelSelection>);
111
112 NonnullRefPtr<Gfx::Font const> font_for_index(ModelIndex const&) const;
113
114 void set_key_column_and_sort_order(int column, SortOrder);
115
116 int key_column() const { return m_key_column; }
117 void set_key_column(int column) { set_key_column_and_sort_order(column, sort_order()); }
118 SortOrder sort_order() const { return m_sort_order; }
119 void set_sort_order(SortOrder order) { set_key_column_and_sort_order(key_column(), order); }
120
121 virtual void scroll_into_view(ModelIndex const&, [[maybe_unused]] bool scroll_horizontally = true, [[maybe_unused]] bool scroll_vertically = true) { }
122
123 ModelIndex const& cursor_index() const { return m_cursor_index; }
124 ModelIndex const& selection_start_index() const { return m_selection_start_index; }
125 void set_cursor(ModelIndex, SelectionUpdate, bool scroll_cursor_into_view = true);
126
127 bool is_tab_key_navigation_enabled() const { return m_tab_key_navigation_enabled; }
128 void set_tab_key_navigation_enabled(bool enabled) { m_tab_key_navigation_enabled = enabled; }
129
130 void set_draw_item_text_with_shadow(bool b) { m_draw_item_text_with_shadow = b; }
131 bool does_draw_item_text_with_shadow() const { return m_draw_item_text_with_shadow; }
132
133protected:
134 AbstractView();
135 virtual ~AbstractView() override;
136
137 virtual void keydown_event(KeyEvent&) override;
138 virtual void mousedown_event(MouseEvent&) override;
139 virtual void mousemove_event(MouseEvent&) override;
140 virtual void mouseup_event(MouseEvent&) override;
141 virtual void doubleclick_event(MouseEvent&) override;
142 virtual void context_menu_event(ContextMenuEvent&) override;
143 virtual void drag_enter_event(DragEvent&) override;
144 virtual void drag_move_event(DragEvent&) override;
145 virtual void drag_leave_event(Event&) override;
146 virtual void drop_event(DropEvent&) override;
147 virtual void leave_event(Core::Event&) override;
148 virtual void hide_event(HideEvent&) override;
149 virtual void focusin_event(FocusEvent&) override;
150
151 virtual void automatic_scrolling_timer_did_fire() override;
152
153 virtual void clear_selection();
154 virtual void set_selection(ModelIndex const&);
155 virtual void set_selection_start_index(ModelIndex const&);
156 virtual void add_selection(ModelIndex const&);
157 virtual void remove_selection(ModelIndex const&);
158 virtual void toggle_selection(ModelIndex const&);
159 virtual void select_range(ModelIndex const&);
160 virtual void did_change_hovered_index([[maybe_unused]] ModelIndex const& old_index, [[maybe_unused]] ModelIndex const& new_index) { }
161 virtual void did_change_cursor_index([[maybe_unused]] ModelIndex const& old_index, [[maybe_unused]] ModelIndex const& new_index) { }
162 virtual void editing_widget_did_change([[maybe_unused]] ModelIndex const& index) { }
163
164 void draw_item_text(Gfx::Painter&, ModelIndex const&, bool, Gfx::IntRect const&, StringView, Gfx::Font const&, Gfx::TextAlignment, Gfx::TextElision, size_t search_highlighting_offset = 0);
165
166 void set_suppress_update_on_selection_change(bool value) { m_suppress_update_on_selection_change = value; }
167
168 virtual void did_scroll() override;
169 void set_hovered_index(ModelIndex const&);
170 void update_edit_widget_position();
171
172 void stop_highlighted_search_timer();
173 void start_highlighted_search_timer();
174 ModelIndex find_next_search_match(StringView const);
175 void highlight_search(ModelIndex const index);
176
177 ModelIndex drop_candidate_index() const { return m_drop_candidate_index; }
178
179 bool m_editable { false };
180 bool m_searchable { true };
181 RefPtr<Widget> m_edit_widget;
182 Gfx::IntRect m_edit_widget_content_rect;
183 OwnPtr<ModelEditingDelegate> m_editing_delegate;
184
185 Gfx::IntPoint m_left_mousedown_position;
186 bool m_might_drag { false };
187
188 int m_key_column { -1 };
189 SortOrder m_sort_order;
190
191 ModelIndex m_edit_index;
192 ModelIndex m_hovered_index;
193 ModelIndex m_highlighted_search_index;
194
195private:
196 ModelIndex m_selection_start_index;
197 ModelIndex m_cursor_index;
198 ModelIndex m_drop_candidate_index;
199
200 RefPtr<Model> m_model;
201 ModelSelection m_selection;
202 DeprecatedString m_highlighted_search;
203 RefPtr<Core::Timer> m_highlighted_search_timer;
204 SelectionBehavior m_selection_behavior { SelectionBehavior::SelectItems };
205 SelectionMode m_selection_mode { SelectionMode::SingleSelection };
206 unsigned m_edit_triggers { EditTrigger::DoubleClicked | EditTrigger::EditKeyPressed };
207 bool m_activates_on_selection { false };
208 bool m_tab_key_navigation_enabled { false };
209 bool m_is_dragging { false };
210 bool m_draw_item_text_with_shadow { false };
211 bool m_suppress_update_on_selection_change { false };
212
213 Gfx::IntPoint m_automatic_scroll_delta {};
214};
215
216}