Sürükle bırak operasyonu için ImGUI nin bize sağlamış olduğu drag drop isimli bir araç var. Kendi kodumda bir ağaç yapısındaki ögelerin birbirine sürüklenip bırakılarak parent-child ilişkisini kurmasını istiyordum.

Kısacası şöyle.

 void SceneManager::drawHierarchyTreeRecursive(Entity* entity) {
 // ... 
    // --- BURASI: DRAG SOURCE (Sürüklemeyi Başlat) ---
    if (ImGui::BeginDragDropSource()) {
        // Sürüklenen nesnenin pointer'ını paketle (Payload)
        ImGui::SetDragDropPayload("ENTITY_HIERARCHY_NODE", &entity, sizeof(Entity*));

        // Sürüklerken farenin yanında ne görünsün?
        ImGui::Text("Moving: %s", entity->name.c_str());
        ImGui::EndDragDropSource();
    }
    
    // Drag drop aynı alana yapıldığı için başlama ve bitirme kodlarını da aynı yere yazıyoruz. 
    
    // --- BURASI: DRAG TARGET (Üzerine Bırakmayı Kabul Et) ---
    if (ImGui::BeginDragDropTarget()) {
        if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_HIERARCHY_NODE")) {
            // Paketi aç (Sürüklenen Entity'yi al)
            Entity* draggedEntity = *(Entity**)payload->Data;

            // Kendi kendine veya zaten parent'ı olan birine bırakılmadığından emin ol
            if (draggedEntity != entity) {
                draggedEntity->transform->setParent(entity->transform.get()); 
            }
        }
        ImGui::EndDragDropTarget();
    }
// ...   
}
C++

Başka bir öğenin üzerine bırakmak yerine boş alana bırakmak istersek şöyle bir kod ekleyebiliriz

    ImGui::Dummy(ImGui::GetContentRegionAvail()); // Boş bir alan yarat
    if (ImGui::BeginDragDropTarget()) {
        if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_HIERARCHY_NODE")) {
            Entity* draggedEntity = *(Entity**)payload->Data;
            draggedEntity->transform->setParent(nullptr); // Bağımsız yap
        }
        ImGui::EndDragDropTarget();
    }
C++

Kodun tamamı şöyle.

std::vector<std::unique_ptr<Entity>> _entities{};
	
	
/// Call recursively to populate each level of children
void SceneManager::drawHierarchyTreeRecursive(Entity* entity) {
    ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth;
    if (isSelected(entity)) flags |= ImGuiTreeNodeFlags_Selected;
    if (entity->transform->getChildren().empty()) flags |= ImGuiTreeNodeFlags_Leaf;

    bool opened = false;

    if (isLastSelected(entity)) {
        ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(230, 125, 15, 255)); // orange foreground
        opened = ImGui::TreeNodeEx(entity->name.c_str(), flags);
        ImGui::PopStyleColor(1);
    }
    else {
        opened = ImGui::TreeNodeEx(entity->name.c_str(), flags);
    }


    // Seçme işlemi
    if (ImGui::IsItemClicked()){
        if (!ImGui::GetIO().KeyCtrl)
            deselectAll();
        
        select(entity);
    }


    // --- BURASI: DRAG SOURCE (Sürüklemeyi Başlat) ---
    if (ImGui::BeginDragDropSource()) {
        // Sürüklenen nesnenin pointer'ını paketle (Payload)
        ImGui::SetDragDropPayload("ENTITY_HIERARCHY_NODE", &entity, sizeof(Entity*));

        // Sürüklerken farenin yanında ne görünsün?
        ImGui::Text("Moving: %s", entity->name.c_str());
        ImGui::EndDragDropSource();
    }

    // --- BURASI: DRAG TARGET (Üzerine Bırakmayı Kabul Et) ---
    if (ImGui::BeginDragDropTarget()) {
        if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_HIERARCHY_NODE")) {
            // Paketi aç (Sürüklenen Entity'yi al)
            Entity* draggedEntity = *(Entity**)payload->Data;

            // Kendi kendine veya zaten parent'ı olan birine bırakılmadığından emin ol
            if (draggedEntity != entity) {
                draggedEntity->transform->setParent(entity->transform.get()); 
            }
        }
        ImGui::EndDragDropTarget();
    }

    // Recursive çağrı
    if (opened) {
        for (Transform* transform : entity->transform->getChildren())
            drawHierarchyTreeRecursive(transform->owner);
    
        ImGui::TreePop();
    }
}

void SceneManager::onInspect()
{
    // HIERARCHY PANEL

    ImGuiTreeNodeFlags rootFlag =
        ImGuiTreeNodeFlags_DefaultOpen |
        ImGuiTreeNodeFlags_Bullet |
        ImGuiTreeNodeFlags_Leaf;

    ImGui::Begin("Scene");

    if (ImGui::IsItemClicked())
        LOG_TRACE("Scene window tab was clicked");


    if (ImGui::TreeNodeEx("root", rootFlag)){
        if (ImGui::IsItemClicked())
            LOG_TRACE("Scene root was clicked");
        
        ImGui::PushStyleColor(ImGuiCol_Header, IM_COL32(55, 55, 55, 255)); // gray background
        
        for (const auto& i : _entities) 
            if(i->transform->isRoot())
                drawHierarchyTreeRecursive(i.get()); // Call recursively to populate each level of children

        ImGui::PopStyleColor(1);

        ImGui::TreePop();  // This is required at the end of the if block
    }

    // drawHierarchy Tree döngüsünün dışına, Begin/End arasına:
    ImGui::Dummy(ImGui::GetContentRegionAvail()); // Boş bir alan yarat
    if (ImGui::BeginDragDropTarget()) {
        if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("ENTITY_HIERARCHY_NODE")) {
            Entity* draggedEntity = *(Entity**)payload->Data;
            draggedEntity->transform->setParent(nullptr); // Bağımsız yap
        }
        ImGui::EndDragDropTarget();
    }


    // bos alana tiklamayi yakala:
    if (ImGui::IsWindowFocused() &&
        ImGui::IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) &&
        ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
        !ImGui::IsAnyItemHovered()
        )
    {
        deselectAll();        
    }


    ImGui::End();

// ...
}
C++

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *