From fceeeb8f657b6a5559258d155adcb3461b194a30 Mon Sep 17 00:00:00 2001 From: Bruno Van de Velde Date: Mon, 22 Jul 2024 19:24:37 +0200 Subject: [PATCH] Widgets in hierarchy tree view in Gui Builder can now be dragged to a different location (to alter z-order or change parent) --- gui-builder/include/GuiBuilder.hpp | 4 +- gui-builder/src/GuiBuilder.cpp | 72 +++++++++++++++++++++++++++++- 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/gui-builder/include/GuiBuilder.hpp b/gui-builder/include/GuiBuilder.hpp index 24701f249..18a807634 100644 --- a/gui-builder/include/GuiBuilder.hpp +++ b/gui-builder/include/GuiBuilder.hpp @@ -83,7 +83,8 @@ class GuiBuilder SendtoFront, SendtoBack, CreateNew, - PropertyEdit + PropertyEdit, + HierarchyChange, }; GuiBuilder(const tgui::String& programName); @@ -194,6 +195,7 @@ class GuiBuilder PropertyValueMapPair m_propertyValuePairs; std::vector m_copiedWidgets; + std::vector m_draggedHierarchyTreeItem; std::map m_themes; tgui::String m_defaultTheme; diff --git a/gui-builder/src/GuiBuilder.cpp b/gui-builder/src/GuiBuilder.cpp index c5562277c..0c42f96b6 100644 --- a/gui-builder/src/GuiBuilder.cpp +++ b/gui-builder/src/GuiBuilder.cpp @@ -334,12 +334,73 @@ void GuiBuilder::mainLoop() m_window->close(); } + else if (event.type == tgui::Event::Type::MouseButtonPressed) + { + if (m_gui->getWidgetBelowMouseCursor({event.mouseButton.x, event.mouseButton.y}, true) == m_widgetHierarchyTree) + { + m_gui->handleEvent(event); + passEventToGui = false; + + m_draggedHierarchyTreeItem = m_widgetHierarchyTree->getHoveredItem(); + + // The form itself cannot be dragged, only widgets inside it + if (m_draggedHierarchyTreeItem.size() == 1) + m_draggedHierarchyTreeItem.clear(); + } + else + m_draggedHierarchyTreeItem.clear(); + } else if (event.type == tgui::Event::Type::MouseButtonReleased) { if (m_selectedForm && !m_foregroundPanel) { - if (event.mouseButton.button == tgui::Event::MouseButton::Left) + if (!m_draggedHierarchyTreeItem.empty() && (m_gui->getWidgetBelowMouseCursor({event.mouseButton.x, event.mouseButton.y}, true) == m_widgetHierarchyTree)) + { + m_gui->handleEvent(event); + passEventToGui = false; + + auto hoveredItem = m_widgetHierarchyTree->getHoveredItem(); + if (!hoveredItem.empty()) + { + tgui::Widget::Ptr widgetToMove = m_selectedForm->getWidgetByName(m_draggedHierarchyTreeItem.back())->ptr; + tgui::Widget::Ptr widgetAtDropLocation = hoveredItem.size() >= 2 ? m_selectedForm->getWidgetByName(hoveredItem.back())->ptr : m_selectedForm->getRootWidgetsGroup(); + + if (widgetToMove != widgetAtDropLocation) + { + saveUndoState(GuiBuilder::UndoType::HierarchyChange); + + widgetToMove->getParent()->remove(widgetToMove); + if (widgetAtDropLocation->isContainer()) + { + auto parent = widgetAtDropLocation->cast(); + parent->add(widgetToMove); + + // We want the widget to appear directly below the parent in the tree view, + // otherwise the move might not be clear if the container has many widget. + parent->moveWidgetToBack(widgetToMove); + } + else // Make the widget a sibling of the one where it was dropped on + { + auto parent = widgetAtDropLocation->getParent(); + parent->add(widgetToMove); + + assert(parent->getWidgetIndex(widgetAtDropLocation) >= 0); + parent->setWidgetIndex(widgetToMove, static_cast(parent->getWidgetIndex(widgetAtDropLocation)) + 1); + } + + m_selectedWidgetComboBox->setSelectedItemById(widgetPtrToStrId(widgetToMove)); + widgetHierarchyChanged(); + m_selectedForm->updateSelectionSquarePositions(); // Absolute widget position moved if it's parent changed + m_selectedForm->setChanged(true); + } + } + + m_draggedHierarchyTreeItem.clear(); + } + else if (event.mouseButton.button == tgui::Event::MouseButton::Left) + { m_selectedForm->mouseReleased(); + } else if (event.mouseButton.button == tgui::Event::MouseButton::Right) { if (m_popupMenu) @@ -2791,6 +2852,7 @@ void GuiBuilder::fillWidgetHierarchyTreeRecursively(std::vector& h void GuiBuilder::widgetHierarchyChanged() { + const auto oldScrollbarValue = m_widgetHierarchyTree->getVerticalScrollbarValue(); m_widgetHierarchyTree->removeAllItems(); if (m_selectedForm == nullptr) @@ -2800,6 +2862,7 @@ void GuiBuilder::widgetHierarchyChanged() fillWidgetHierarchyTreeRecursively(widgetHiearchy, m_selectedForm->getRootWidgetsGroup()); updateSelectedWidgetHierarchy(); + m_widgetHierarchyTree->setVerticalScrollbarValue(oldScrollbarValue); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -2905,6 +2968,9 @@ void GuiBuilder::saveUndoState(GuiBuilder::UndoType type) case GuiBuilder::UndoType::PropertyEdit: descString = "Property Edit"; break; + case GuiBuilder::UndoType::HierarchyChange: + descString = "Hierarchy Change"; + break; } // Starts deleting beginning history of saved states if > max ammount set to prevent overflow or excess memory usage @@ -2933,6 +2999,8 @@ void GuiBuilder::loadUndoState() if (selectedWidget) selectedWidgetName = selectedWidget->name; + const auto oldHierarchyScrollbarValue = m_widgetHierarchyTree->getVerticalScrollbarValue(); + const tgui::String filename = m_selectedForm->getFilename(); m_selectedForm = nullptr; m_forms.clear(); @@ -2956,6 +3024,8 @@ void GuiBuilder::loadUndoState() m_selectedForm->setSize(formSize); m_selectedForm->setChanged(true); + m_widgetHierarchyTree->setVerticalScrollbarValue(oldHierarchyScrollbarValue); + if (!selectedWidgetName.empty()) m_selectedForm->selectWidgetByName(selectedWidgetName); }