4 #include "displaytree.h" 6 #include "../core/log.h" 7 #include "../core/workspace.h" 9 #include <unordered_map> 11 DisplayTreeWidget::DisplayTreeWidget() : QDockWidget(
"Display Tree") {
20 virtual void dropEvent(QDropEvent *event)
override {
23 LOG_DEBUG(currentItem()->text(0).toStdString());
24 QTreeWidgetItem *dragged_item = currentItem();
25 QTreeWidget::dropEvent(event);
26 QTreeWidgetItem *new_parent_item = dragged_item->parent();
27 std::shared_ptr<Object> dragged_object;
28 std::shared_ptr<DisplayGroupBase> new_parent_display;
29 for (
auto &item : parent->items) {
30 if (item.second.get() == dragged_item) {
31 dragged_object = item.first.lock();
33 if (item.second.get() == new_parent_item) {
38 if (!dragged_object) {
39 LOG_ERROR(
"dragged object lost");
43 if (!new_parent_display) {
44 LOG_WARN(
"no drop target");
48 std::shared_ptr<DisplayGroupBase> old_parent_display;
49 ws()->document()->display()->recurse(
50 [&](
const std::shared_ptr<Display> &parent,
51 const std::shared_ptr<Display> &child) {
52 if (child == dragged_object) {
57 if (!old_parent_display) {
58 LOG_ERROR(
"parent display lost");
62 if (old_parent_display == new_parent_display) {
63 LOG_DEBUG(
"same parent");
67 if (
auto dragged_display =
68 std::dynamic_pointer_cast<Display>(dragged_object)) {
71 for (
size_t i = 0; i < old_parent_display->displays().size(); i++) {
72 if (old_parent_display->displays()[i] == dragged_object) {
73 old_parent_display->displays().erase(
74 old_parent_display->displays().begin() + i);
80 new_parent_display->displays().push_back(dragged_display);
85 view =
new TreeWidget2(
this);
86 view->setSelectionMode(QAbstractItemView::ExtendedSelection);
87 view->setEditTriggers(QAbstractItemView::DoubleClicked |
88 QAbstractItemView::EditKeyPressed |
89 QAbstractItemView::AnyKeyPressed);
90 view->setDragEnabled(
true);
91 view->viewport()->setAcceptDrops(
true);
92 view->setDropIndicatorShown(
true);
93 view->setDragDropMode(QAbstractItemView::InternalMove);
94 QWidget *content =
new QWidget();
95 auto *layout =
new QVBoxLayout(content);
96 layout->setContentsMargins(0, 0, 0, 0);
97 auto *bar =
new QHBoxLayout(content);
99 layout->setSpacing(0);
102 button->setIcon(TEXT_ICON(
"+"));
103 bar->addWidget(button);
104 QMenu *menu =
new QMenu(button);
105 std::map<QString, std::map<QString, std::function<void()>>> actions;
106 for (
auto &type : Type::find<Display>()->list()) {
110 if (!type->constructable()) {
113 QString name = QString(type->name().c_str());
115 QString str =
"Display";
116 int index = name.lastIndexOf(str);
118 name = name.remove(index, str.size());
121 if (Type::tryFind(name.toStdString() +
"PublisherDisplay")) {
124 actions[QString(type->category().c_str())][name] = [type]() {
125 ActionScope ws(std::string(
"Create ") + type->name());
126 auto new_display = type->instantiate<
Display>();
127 static size_t counter = 1;
128 new_display->name(std::string() + type->name() +
"" +
129 std::to_string(counter++));
130 ws->document()->display()->displays().push_back(new_display);
131 ws->selection() = new_display;
135 actions[
"ZZZZZZ"] = actions[
""];
137 for (
auto category : actions) {
139 if (category.first !=
"ZZZZZZ") {
140 cmenu = menu->addMenu(category.first);
142 for (
auto p : category.second) {
143 connect(cmenu->addAction(p.first), &QAction::triggered,
this,
144 [p](
bool checked) { p.second(); });
147 button->setMenu(menu);
149 layout->addLayout(bar);
150 layout->addWidget(view);
152 view->setHeaderHidden(
true);
153 connect(view, &QTreeWidget::itemChanged,
this,
154 [
this](QTreeWidgetItem *item,
int column) {
157 for (
auto &p : items) {
158 if (p.second.get() == item) {
160 std::dynamic_pointer_cast<Display>(p.first.lock())) {
162 display->name(item->text(0).toStdString());
169 connect(view, &QTreeWidget::itemSelectionChanged,
this, [
this]() {
170 LOG_DEBUG(
"selection changed");
174 ws->selection().clear();
175 for (
auto *item : view->selectedItems()) {
176 for (
auto &p : items) {
177 if (p.second.get() == item) {
178 if (
auto object = p.first.lock()) {
179 ws->selection().add(
object);
187 ws->modified.connect(
this, [
this]() { sync(); });
188 QTimer::singleShot(0,
this, [
this] { view->setFocus(Qt::OtherFocusReason); });
191 void DisplayTreeWidget::sync() {
194 std::unordered_set<std::shared_ptr<Object>> all_objects;
195 ws->document()->display()->recurse(
196 [&](
const std::shared_ptr<Object> &o) { all_objects.insert(o); });
197 std::unordered_map<std::shared_ptr<Object>, std::shared_ptr<QTreeWidgetItem>>
200 for (
auto &p : items) {
201 std::shared_ptr<Object>
object = p.first.lock();
202 if (
object && all_objects.find(
object) != all_objects.end()) {
203 object_to_item[object] = p.second;
205 p.second->takeChildren();
210 ws->document()->display()->recurse(
211 [&object_to_item](
const std::shared_ptr<Display> &display) {
212 if (object_to_item.find(display) == object_to_item.end()) {
213 auto item = std::make_shared<QTreeWidgetItem>();
214 item->setFlags(item->flags() | Qt::ItemIsEditable);
215 object_to_item[display] = item;
218 ws->document()->display()->recurse(
219 [&object_to_item,
this](
const std::shared_ptr<Display> &parent,
220 const std::shared_ptr<Display> &display) {
222 std::shared_ptr<QTreeWidgetItem> parent_item;
224 parent_item = object_to_item[parent];
226 std::shared_ptr<QTreeWidgetItem> item = object_to_item[display];
227 if (display->name().empty()) {
228 item->setText(0, display->type()->name().c_str());
230 item->setText(0, display->name().c_str());
232 item->setSelected(ws->selection().contains(display));
233 if (item->parent() != parent_item.get()) {
234 if (item->parent()) {
235 item->parent()->removeChild(item.get());
237 this->view->takeTopLevelItem(
238 this->view->indexOfTopLevelItem((item.get())));
241 parent_item->addChild(item.get());
243 this->view->addTopLevelItem(item.get());
246 if (item->treeWidget() ==
nullptr) {
247 this->view->addTopLevelItem(item.get());
250 for (
auto &p : object_to_item) {
251 items.emplace_back(p.first, p.second);
256 DisplayTreeWidget::~DisplayTreeWidget() {
258 LOG_DEBUG(
"~DisplayTreeWidget begin" << parent());
259 view->setCurrentItem(
nullptr);
260 for (
auto &item : items) {
261 item.second->takeChildren();
263 LOG_DEBUG(
"~DisplayTreeWidget clear" << parent());
265 LOG_DEBUG(
"~DisplayTreeWidget end" << parent());