aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/ui/controls/Control.h4
-rw-r--r--include/cru/ui/controls/TreeView.h41
-rw-r--r--src/ui/controls/TreeView.cpp87
-rw-r--r--src/ui/render/TreeRenderObject.cpp12
4 files changed, 141 insertions, 3 deletions
diff --git a/include/cru/ui/controls/Control.h b/include/cru/ui/controls/Control.h
index 242db3f4..1d976970 100644
--- a/include/cru/ui/controls/Control.h
+++ b/include/cru/ui/controls/Control.h
@@ -9,9 +9,11 @@ namespace cru::ui::controls {
* \remarks If you want to write a new control. You should override following
* methods:
* - GetControlType()
+ * - GetRenderObject()
* - ForEachChild(const std::function<void(Control*)>& predicate)
* - RemoveChild(Control* child)
- * - GetRenderObject()
+ * The last two methods are totally for convenient control tree management. The
+ * former one is even not used.
*/
class CRU_UI_API Control : public Object {
protected:
diff --git a/include/cru/ui/controls/TreeView.h b/include/cru/ui/controls/TreeView.h
index b36ca553..6c3c360b 100644
--- a/include/cru/ui/controls/TreeView.h
+++ b/include/cru/ui/controls/TreeView.h
@@ -1,5 +1,6 @@
#pragma once
#include "Control.h"
+#include "cru/ui/render/TreeRenderObject.h"
namespace cru::ui::controls {
class TreeView;
@@ -7,31 +8,67 @@ class TreeView;
class CRU_UI_API TreeViewItem : public Object {
friend TreeView;
+ private:
+ TreeViewItem(TreeView* tree_view, TreeViewItem* parent,
+ render::TreeRenderObjectItem* render_object_item);
+ ~TreeViewItem() override;
+
public:
- TreeViewItem(TreeView* tree_view, TreeViewItem* parent);
CRU_DELETE_COPY(TreeViewItem)
CRU_DELETE_MOVE(TreeViewItem)
- ~TreeViewItem() override;
TreeView* GetTreeView() { return tree_view_; }
TreeViewItem* GetParent() { return parent_; }
+ render::TreeRenderObjectItem* GetRenderObjectItem() const {
+ return render_object_item_;
+ }
+
const std::vector<TreeViewItem*>& GetChildren() const { return children_; }
Index GetChildCount() const { return children_.size(); }
TreeViewItem* GetChildAt(Index index) {
Expects(index >= 0 && index < children_.size());
return children_[index];
}
+ Index IndexOf(TreeViewItem* item) const;
TreeViewItem* AddItem(Index position);
void RemoveItem(Index position);
+ void RemoveFromParent();
+
+ Control* GetControl() const { return control_; }
+ void SetControl(Control* control);
+
+ void TraverseDescendants(std::function<void(TreeViewItem*)> callback);
private:
TreeView* tree_view_;
+ render::TreeRenderObjectItem* render_object_item_;
TreeViewItem* parent_;
std::vector<TreeViewItem*> children_;
Control* control_;
};
+class CRU_UI_API TreeView : public Control {
+ public:
+ constexpr static StringView kControlType = u"TreeView";
+
+ TreeView();
+ CRU_DELETE_COPY(TreeView)
+ CRU_DELETE_MOVE(TreeView)
+ ~TreeView() override;
+
+ String GetControlType() const override { return kControlType.ToString(); }
+ render::TreeRenderObject* GetRenderObject() { return &render_object_; }
+
+ void ForEachChild(const std::function<void(Control*)>& predicate) override;
+ void RemoveChild(Control* control) override;
+
+ TreeViewItem* GetRootItem() { return &root_item_; }
+
+ private:
+ render::TreeRenderObject render_object_;
+ TreeViewItem root_item_;
+};
} // namespace cru::ui::controls
diff --git a/src/ui/controls/TreeView.cpp b/src/ui/controls/TreeView.cpp
index e69de29b..659aef00 100644
--- a/src/ui/controls/TreeView.cpp
+++ b/src/ui/controls/TreeView.cpp
@@ -0,0 +1,87 @@
+#include "cru/ui/controls/TreeView.h"
+
+namespace cru::ui::controls {
+TreeViewItem::TreeViewItem(TreeView* tree_view, TreeViewItem* parent,
+ render::TreeRenderObjectItem* render_object_item)
+ : tree_view_(tree_view),
+ parent_(parent),
+ render_object_item_(render_object_item) {}
+
+TreeViewItem::~TreeViewItem() {
+ if (control_) {
+ control_->SetParent(nullptr);
+ }
+
+ for (auto item : children_) {
+ delete item;
+ }
+}
+
+Index TreeViewItem::IndexOf(TreeViewItem* item) const {
+ auto result = std::find(children_.begin(), children_.end(), item);
+ if (result == children_.end()) {
+ return -1;
+ }
+ return result - children_.begin();
+}
+
+void TreeViewItem::RemoveFromParent() {
+ if (parent_ == nullptr) return;
+ parent_->RemoveItem(parent_->IndexOf(this));
+}
+
+TreeViewItem* TreeViewItem::AddItem(Index position) {
+ auto render_object_item = render_object_item_->AddItem(position);
+ auto item = new TreeViewItem(tree_view_, this, render_object_item);
+ children_.insert(children_.begin() + position, item);
+ return item;
+}
+
+void TreeViewItem::RemoveItem(Index position) {
+ Expects(position >= 0 && position < children_.size());
+ delete children_[position];
+ children_.erase(children_.begin() + position);
+ render_object_item_->RemoveItem(position);
+}
+
+void TreeViewItem::SetControl(Control* control) {
+ if (control_) {
+ control_->SetParent(nullptr);
+ render_object_item_->SetRenderObject(nullptr);
+ }
+ control_ = control;
+ if (control) {
+ control->SetParent(tree_view_);
+ render_object_item_->SetRenderObject(control->GetRenderObject());
+ }
+}
+
+void TreeViewItem::TraverseDescendants(
+ std::function<void(TreeViewItem*)> callback) {
+ callback(this);
+ for (auto item : children_) {
+ TraverseDescendants(callback);
+ }
+}
+
+TreeView::TreeView()
+ : root_item_(this, nullptr, render_object_.GetRootItem()) {}
+
+TreeView::~TreeView() {}
+
+void TreeView::ForEachChild(const std::function<void(Control*)>& predicate) {
+ root_item_.TraverseDescendants([&predicate](TreeViewItem* item) {
+ if (auto control = item->GetControl()) {
+ predicate(control);
+ }
+ });
+}
+
+void TreeView::RemoveChild(Control* control) {
+ root_item_.TraverseDescendants([&control](TreeViewItem* item) {
+ if (item->GetControl() == control) {
+ item->SetControl(nullptr);
+ }
+ });
+}
+} // namespace cru::ui::controls
diff --git a/src/ui/render/TreeRenderObject.cpp b/src/ui/render/TreeRenderObject.cpp
index 9bf74535..8bf662e4 100644
--- a/src/ui/render/TreeRenderObject.cpp
+++ b/src/ui/render/TreeRenderObject.cpp
@@ -9,6 +9,11 @@ TreeRenderObjectItem::TreeRenderObjectItem(TreeRenderObject* tree_render_object,
: tree_render_object_(tree_render_object), parent_(parent) {}
TreeRenderObjectItem::~TreeRenderObjectItem() {
+ if (render_object_) {
+ render_object_->SetParent(nullptr);
+ render_object_ = nullptr;
+ }
+
for (auto child : children_) {
delete child;
}
@@ -16,7 +21,14 @@ TreeRenderObjectItem::~TreeRenderObjectItem() {
void TreeRenderObjectItem::SetRenderObject(RenderObject* render_object) {
if (render_object == render_object_) return;
+ if (render_object_) {
+ render_object_->SetParent(nullptr);
+ }
render_object_ = render_object;
+ if (render_object) {
+ assert(render_object->GetParent() == nullptr);
+ render_object->SetParent(tree_render_object_);
+ }
tree_render_object_->InvalidateLayout();
}