From f6b48ecd4772a57dd10542a76881b32860cb40d3 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 29 Mar 2019 18:10:36 +0100 Subject: [PATCH] GTreeView: More implementation work. --- Base/res/icons/treeview-collapse.png | Bin 0 -> 143 bytes Base/res/icons/treeview-expand.png | Bin 0 -> 151 bytes LibGUI/GTreeView.cpp | 35 +++++++++++++++++++++------ LibGUI/GTreeView.h | 5 +++- 4 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 Base/res/icons/treeview-collapse.png create mode 100644 Base/res/icons/treeview-expand.png diff --git a/Base/res/icons/treeview-collapse.png b/Base/res/icons/treeview-collapse.png new file mode 100644 index 0000000000000000000000000000000000000000..d56f76a6024a3bf6db3ed544412e22c9b91d8dd9 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0y~yVBiE{4mJh`h6fYb1VEeukH}&M20djEW~^9hU&g?| zz+U3%>&pI^SysS|>x{))Rt5$JJx>?M5Q)plB?SdP&O2}j1U-51;KTgRMh=H5N@6Nz pX4#S#MGb>eWCOb-Iyu!D{ygRoP?>-20RsaAgQu&X%Q~loCIGOZCG7wJ literal 0 HcmV?d00001 diff --git a/Base/res/icons/treeview-expand.png b/Base/res/icons/treeview-expand.png new file mode 100644 index 0000000000000000000000000000000000000000..66f5d1e3b6e701a0d35aee051b5d0186951194b1 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0y~yVBiE{4mJh`h6fYb1VEeukH}&M20djEW~^9hU&g?| zz+U3%>&pI^SysS|LFX-tGy?;JnWu|mh{WaOl7fOC=N&i%f}T8h@L@h@w?&(p8k-UW vH=l4qj$4Uqj|Z28=Qh6CN^U%iNryNYxHob0&vMEGSgTe~DWM4fOo}9B literal 0 HcmV?d00001 diff --git a/LibGUI/GTreeView.cpp b/LibGUI/GTreeView.cpp index 59e8a53ea0..8a3146d0b3 100644 --- a/LibGUI/GTreeView.cpp +++ b/LibGUI/GTreeView.cpp @@ -2,6 +2,8 @@ #include #include +//#define DEBUG_ITEM_RECTS + struct Node { String text; Node* parent { nullptr }; @@ -111,6 +113,9 @@ GTreeView::GTreeView(GWidget* parent) set_frame_thickness(2); set_model(TestModel::create()); + + m_expand_bitmap = GraphicsBitmap::load_from_file("/res/icons/treeview-expand.png"); + m_collapse_bitmap = GraphicsBitmap::load_from_file("/res/icons/treeview-collapse.png"); } GTreeView::~GTreeView() @@ -122,7 +127,7 @@ GModelIndex GTreeView::index_at_content_position(const Point& position) const if (!model()) return { }; GModelIndex result; - traverse_in_paint_order([&] (const GModelIndex& index, const Rect& rect) { + traverse_in_paint_order([&] (const GModelIndex& index, const Rect& rect, int, bool) { if (rect.contains(position)) { result = index; return IterationDecision::Abort; @@ -162,7 +167,7 @@ void GTreeView::traverse_in_paint_order(Callback callback) const int y_offset = 0; auto visible_content_rect = this->visible_content_rect(); - Function traverse_index = [&] (const GModelIndex& index) { + Function traverse_index = [&] (const GModelIndex& index, bool is_last_in_parent) { if (index.is_valid()) { auto& metadata = ensure_metadata_for_index(index); int x_offset = indent_level * indent_width_in_pixels(); @@ -172,7 +177,7 @@ void GTreeView::traverse_in_paint_order(Callback callback) const icon_size() + icon_spacing() + font().width(node_text), item_height() }; if (rect.intersects(visible_content_rect)) { - if (callback(index, rect) == IterationDecision::Abort) + if (callback(index, rect, indent_level, is_last_in_parent) == IterationDecision::Abort) return IterationDecision::Abort; } y_offset += item_height(); @@ -182,14 +187,15 @@ void GTreeView::traverse_in_paint_order(Callback callback) const } ++indent_level; - for (int i = 0; i < model.row_count(index); ++i) { - if (traverse_index(model.index(i, 0, index)) == IterationDecision::Abort) + int row_count = model.row_count(index); + for (int i = 0; i < row_count; ++i) { + if (traverse_index(model.index(i, 0, index), i == row_count - 1) == IterationDecision::Abort) return IterationDecision::Abort; } --indent_level; return IterationDecision::Continue; }; - traverse_index(model.index(0, 0, GModelIndex())); + traverse_index(model.index(0, 0, GModelIndex()), true); } void GTreeView::paint_event(GPaintEvent& event) @@ -205,8 +211,10 @@ void GTreeView::paint_event(GPaintEvent& event) return; auto& model = *this->model(); - traverse_in_paint_order([&] (const GModelIndex& index, const Rect& rect) { + traverse_in_paint_order([&] (const GModelIndex& index, const Rect& rect, int indent_level, bool is_last_in_parent) { +#ifdef DEBUG_ITEM_RECTS painter.fill_rect(rect, Color::LightGray); +#endif Rect icon_rect = { rect.x(), rect.y(), icon_size(), icon_size() }; auto icon = model.data(index, GModel::Role::Icon); if (icon.is_icon()) { @@ -219,6 +227,19 @@ void GTreeView::paint_event(GPaintEvent& event) }; auto node_text = model.data(index, GModel::Role::Display).to_string(); painter.draw_text(text_rect, node_text, TextAlignment::CenterLeft, Color::Black); + for (int i = 0; i <= indent_level; ++i) { + Point a { indent_width_in_pixels() * i - icon_size() / 2, rect.y() }; + Point b { a.x(), a.y() + item_height() - 1 }; + if (i == indent_level && is_last_in_parent) + b.set_y(rect.center().y()); + painter.draw_line(a, b, Color::MidGray); + + if (i == indent_level) { + Point c { a.x(), rect.center().y() }; + Point d { c.x() + icon_size() / 2, c.y() }; + painter.draw_line(c, d, Color::MidGray); + } + } return IterationDecision::Continue; }); } diff --git a/LibGUI/GTreeView.h b/LibGUI/GTreeView.h index 5cd4bb7de5..a3603fcc7f 100644 --- a/LibGUI/GTreeView.h +++ b/LibGUI/GTreeView.h @@ -18,7 +18,7 @@ protected: private: int item_height() const { return 16; } int max_item_width() const { return frame_inner_rect().width(); } - int indent_width_in_pixels() const { return 12; } + int indent_width_in_pixels() const { return 16; } int icon_size() const { return 16; } int icon_spacing() const { return 4; } @@ -30,4 +30,7 @@ private: MetadataForIndex& ensure_metadata_for_index(const GModelIndex&) const; mutable HashMap> m_view_metadata; + + RetainPtr m_expand_bitmap; + RetainPtr m_collapse_bitmap; };