///////////////////////////////////////////////////////////////////////////////
// Called at the end of a drag-and-drop event.  Called when the user
// releases the mouse button.  Moves all the selected items to be under a 
// new parent (the item that was dropped onto in the tree).  You cannot drop
// onto an item that is already selected (your command will be ignored if
// you do).  All the reparenting is handled through the undo stack so that
// it can be undone and redone.  This function does not update the tree
// hierarchy; that is handled in a callback.
// 
void HierarchyOutliner::OnEndDrag( wxTreeEvent& args )
{
    const wxTreeItemId& dropItem = args.GetItem();

    // You can only drop on a valid item that's not already selected.
    if ( dropItem.IsOk() && !m_TreeCtrl->IsSelected( dropItem ) )
    {
        m_TreeCtrl->Freeze();

        // Reparent every selected item into the item that was dropped on
        Editor::HierarchyNode* newParent = GetTreeItemData( dropItem )->GetHierarchyNode();
        HELIUM_ASSERT( newParent );

        BatchUndoCommandPtr batch = new BatchUndoCommand ();

        const OS_ObjectDumbPtr& selection = m_CurrentScene->GetSelection().GetItems();
        OS_ObjectDumbPtr::Iterator selItr = selection.Begin();
        const OS_ObjectDumbPtr::Iterator selEnd = selection.End();
        for ( ; selItr != selEnd; ++selItr )
        {
            Editor::HierarchyNode* hNode = Reflect::SafeCast< Editor::HierarchyNode >( *selItr );
            if ( hNode )
            {
                batch->Push( new ParentCommand( hNode, newParent ) );
            }
        }

        m_CurrentScene->Push( batch );

        m_TreeCtrl->Thaw();
    }
    // else: drop target was not valid
}
Beispiel #2
0
void LayersPanel::DeleteSelectedLayers()
{
    // If anything selected in the grid
    if ( m_Scene && m_Grid->IsAnythingSelected() )
    {
        LayerSelectedItems( false );

        // Begin undo batch
        BatchUndoCommandPtr batch = new BatchUndoCommand ();

        // Get an ordered list of the selected rows, and traverse the list in reverse order.
        // This makes sure that removing an item doesn't change the row number of another
        // item that will be removed later in the loop.  If we don't do this, we run the
        // risk of invalidating the selection array as we iterate over it.
        const std::set< uint32_t >& selection = m_Grid->GetSelectedRows();
        std::set< uint32_t >::const_reverse_iterator rowItr = selection.rbegin();
        std::set< uint32_t >::const_reverse_iterator rowEnd = selection.rend();
        for ( ; rowItr != rowEnd; ++rowItr )
        {
            M_LayerDumbPtr::iterator layerItr = m_Layers.find( m_Grid->GetRowName( *rowItr ) );
            HELIUM_ASSERT( layerItr != m_Layers.end() );
            // NOTE: m_Layers is changing as we iterate over the selection (items are being
            // removed via callbacks), so don't hold on to any iterators that point into the list.
            // Recalculate m_Layers.end() each time through the loop.
            if ( layerItr != m_Layers.end() )
            {
                Layer* layer = layerItr->second;

                // If the layer that we are about to delete is in the scene's selection list,
                // we had better just clear out the selection list (otherwise the attribute
                // editor will still be showing a layer that is no longer in the scene).  This
                // has to be done before actually deleting the layer.
                if ( m_Scene->GetSelection().Contains( layer ) )
                {
                    batch->Push( m_Scene->GetSelection().Clear() );
                }

                // If the layer has any members, we should remove them before removing the layer,
                // otherwise if those members are deleted, they will be pointing to an invalid
                // layer that will eventually be Disconnected.
                S_SceneNodeSmartPtr descendents = layer->GetDescendants();
                for ( S_SceneNodeSmartPtr::iterator itr = descendents.begin(), end = descendents.end(); itr != end; ++itr )
                {
                    batch->Push( new DependencyCommand( DependencyCommand::Disconnect, layer, *itr ) );
                }

                // Push the command to delete the layer
                batch->Push( new SceneNodeExistenceCommand( ExistenceActions::Remove, m_Scene, layer ) );
            }
        }

        // End undo batch
        m_Scene->Push( batch );

        m_Scene->Execute( false );
    }
}
Beispiel #3
0
///////////////////////////////////////////////////////////////////////////////
// Called when the "New Layer From Selection" button is clicked on the toolbar.
//
void LayersPanel::OnNewLayerFromSelection( wxCommandEvent& dummyEvt )
{
    if ( m_Scene )
    {
        if(IsSelectionValid() == false)
        {
            return;
        }

        BatchUndoCommandPtr batch = new BatchUndoCommand ();
        LayerPtr layer = new Layer();
        layer->SetOwner( m_Scene );
        layer->Initialize();

        // Generate a name for this layer
        GenerateLayerName(layer);

        batch->Push( new SceneNodeExistenceCommand( ExistenceActions::Add, m_Scene, layer ) );

        // Step 2: add all the selected items to the layer
        const OS_ObjectDumbPtr& selection = m_Scene->GetSelection().GetItems();
        OS_ObjectDumbPtr::Iterator itr = selection.Begin();
        OS_ObjectDumbPtr::Iterator end = selection.End();
        for ( ; itr != end; ++itr )
        {
            //If the element is a supported type
            if( *itr )
            {
                SceneNode* node = Reflect::SafeCast< SceneNode >( *itr );
                if ( node )
                {
                    batch->Push( new DependencyCommand( DependencyCommand::Connect, layer, node ) );
                }
            }
        }

        m_Scene->Push( batch );
        m_Scene->Execute( false );
    }
}
Beispiel #4
0
///////////////////////////////////////////////////////////////////////////////
// Adds undoable commands to m_Scene's undo queue which will do one of two thing:
//
// Either...
// 1. Adds the currently selected scene items to the currently highlighted
// layers.  Set addToLayer to true for this option.
// or...
// 2. Removes the currently selected scene items from the currently highlighted
// layers.  Set addToLayer to false for this option.
//
// If there are no selected items, or no selected layers, nothing happens.  It
// is also safe to remove items from a layer even if they are not part of the
// layer (nothing happens), or add items to a layer that already belong to
// that layer (again, nothing happens).
//
void LayersPanel::LayerSelectedItems( bool addToLayer )
{
    HELIUM_ASSERT( m_Scene );

    // Decide whether we are adding the selected scene items to the highlighted
    // layers, or removing the items from the layers.
    const DependencyCommand::DependencyAction action = addToLayer ? DependencyCommand::Connect : DependencyCommand::Disconnect;

    // If there are selected nodes in the scene, and selected rows in this control...
    const OS_ObjectDumbPtr& selectedNodes = m_Scene->GetSelection().GetItems();
    std::set< uint32_t > selectedRows = m_Grid->GetSelectedRows();
    if ( selectedNodes.Size() > 0 && selectedRows.size() > 0 )
    {
        //Log::Debug( "LayerSelectedItems\n" );
        BatchUndoCommandPtr batch = new BatchUndoCommand ();

        OS_ObjectDumbPtr::Iterator nodeItr = selectedNodes.Begin();
        OS_ObjectDumbPtr::Iterator nodeEnd = selectedNodes.End();
        std::set< uint32_t >::const_iterator rowItr;
        const std::set< uint32_t >::const_iterator rowEnd = selectedRows.end();
        const M_LayerDumbPtr::const_iterator layerEnd = m_Layers.end();

        // For each node in the scene's selection list...
        for ( ; nodeItr != nodeEnd; ++nodeItr )
        {
            // ensure that we are not trying to add one layer to another layer
            {
                Layer* layerTest = Reflect::SafeCast< Layer >( *nodeItr );
                if( layerTest )
                {
                    continue;
                }
            }

            //Check the current selection
            if( *nodeItr == NULL )
            {
                //Invalid or incompatible
                continue;
            }

            SceneNode* node = Reflect::SafeCast< SceneNode >( *nodeItr );
            if ( node )
            {
                // For each row that is highlighted...
                for ( rowItr = selectedRows.begin(); rowItr != rowEnd; ++rowItr )
                {
                    // Find the layer that goes with the highlighted row
                    M_LayerDumbPtr::iterator layerItr = m_Layers.find( m_Grid->GetRowName( *rowItr ) );
                    if ( layerItr != layerEnd )
                    {
                        // Check to see if the node is already in the current layer...
                        Layer* layer = layerItr->second;
                        S_SceneNodeSmartPtr::const_iterator foundDescendant = layer->GetDescendants().find( node );

                        // If the node is already in this layer, and we are suppose to be adding the node to the layer,
                        // just skip the command (doCommand = false).  If the node is not in this layer, and we are
                        // suppose to be removing the node from the layer, skip the command as well.  Otherwise, go
                        // ahead and carry out the command (doCommand = true).
                        const bool doCommand = addToLayer ? ( foundDescendant == layer->GetDescendants().end() ) : ( foundDescendant != layer->GetDescendants().end() );
                        if ( doCommand )
                        {
                            // Finally make an undoable command to add/remove the node to/from the layer
                            batch->Push( new DependencyCommand( action, layer, node ) );
                            //Log::Debug( "\t\t%s node %s %s layer %s [row=%d]\n", addToLayer ? "Added" : "Removed", node->GetName().c_str(), addToLayer ? "to" : "from", layer->GetName().c_str(), *rowItr );
                        }
                        else
                        {
                            //Log::Debug( "\t\tNode %s was already a member of layer %s [row=%d]\n", node->GetName().c_str(), layer->GetName().c_str(), *rowItr );
                        }
                    }
                    else
                    {
                        // Something is wrong.  The rows that are selected in the grid do not correspond to
                        // items in our list of layers (m_Layers).  Somehow those lists got out of sync.
                        Log::Error( TXT( "Unable to add selection to layer [row=%d] because it doesn't exist\n" ), *rowItr );
                        HELIUM_BREAK();
                    }
                }
            }
        }

        //Log::Debug( "\n" );
        if( !batch->IsEmpty() )
        {
            m_Scene->Push( batch );
            m_Scene->Execute( false );
        }
    }
}
Beispiel #5
0
UndoCommandPtr Curve::CenterTransform()
{
    BatchUndoCommandPtr batch = new BatchUndoCommand();

    batch->Push( Base::CenterTransform() );

    if ( GetNumberControlPoints() == 0 )
    {
        return batch;
    }


    //
    // We are going to move all control points, so just snap shot
    //

    batch->Push( SnapShot() );


    //
    // Compute the centered position
    //

    Vector3 position = Vector3::Zero;

    {
        uint32_t controlPointCount = 0;
        OS_HierarchyNodeDumbPtr::Iterator childItr = GetChildren().Begin();
        OS_HierarchyNodeDumbPtr::Iterator childEnd = GetChildren().End();
        for ( ; childItr != childEnd; ++childItr )
        {
            CurveControlPoint* point = Reflect::SafeCast< CurveControlPoint >( *childItr );
            if ( point )
            {
                ++controlPointCount;
                position += point->GetPosition();
            }
        }
        position /= (float32_t)controlPointCount;
    }

    m_GlobalTransform.TransformVertex( position );


    //
    // Offset the control points
    //

    Matrix4 m = m_GlobalTransform;

    m.t = position;

    m = m_GlobalTransform * m.Inverted();

    {
        OS_HierarchyNodeDumbPtr::Iterator childItr = GetChildren().Begin();
        OS_HierarchyNodeDumbPtr::Iterator childEnd = GetChildren().End();
        for ( ; childItr != childEnd; ++childItr )
        {
            CurveControlPoint* point = Reflect::SafeCast< CurveControlPoint >( *childItr );
            if ( point )
            {
                Vector3 p = point->GetPosition();

                m.TransformVertex( p );

                batch->Push( new PropertyUndoCommand< Vector3 >( new Helium::MemberProperty< CurveControlPoint, Vector3 >( point, &CurveControlPoint::GetPosition, &CurveControlPoint::SetPosition ), p ) );
            }
        }
    }


    //
    // Recompute global transform
    //

    // our new global transform is just translated to the new position
    m_GlobalTransform.t = position;

    // this will recompute the local components
    SetGlobalTransform( m_GlobalTransform );

    // update the transform object
    Evaluate( GraphDirections::Downstream );

    // update each child's local transform to stay in the same global position
    for ( OS_HierarchyNodeDumbPtr::Iterator itr = m_Children.Begin(), end = m_Children.End(); itr != end; ++itr )
    {
        HierarchyNode* n = *itr;

        Transform* t = Reflect::SafeCast<Transform>( n );

        if ( !t )
        {
            continue;
        }

        batch->Push( t->ComputeObjectComponents() );
    }

    Dirty();

    return batch;
}
Beispiel #6
0
void CreateTool::AddToScene()
{
	if (!m_Instance.ReferencesObject())
	{
		return;
	}

	if (!m_Scene->IsEditable())
	{
		return;
	}

	{
		HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Remove Transient Instance" );

		m_Scene->RemoveObject( m_Instance.Ptr() );
	}

	BatchUndoCommandPtr batch = new BatchUndoCommand ();

	if (!m_Created)
	{
		batch->Push( m_Scene->GetSelection().Clear() );
		m_Created = true;
	}

	m_Instance->SetTransient( false );

	{
		HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Push Undo Command Adding Instance Into Batch" );

		batch->Push( new SceneNodeExistenceCommand( ExistenceActions::Add, m_Scene, m_Instance ) );
	}

	{
		HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Initialize Instance" );

		if ( !m_Instance->IsInitialized() )
		{
			m_Instance->SetOwner( m_Scene );
			m_Instance->Initialize();
		}

		HELIUM_ASSERT( m_Instance->GetOwner() == m_Scene );
	}

	{
		HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Append To Selection" );

		m_Selection.Append( m_Instance );
	}

	{
		HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Push Undo Batch Into Scene" );

		m_Scene->Push( batch );
	}

	{
		HELIUM_EDITOR_SCENE_SCOPE_TIMER( "Place New Instance At Origin" );

		m_Instance = NULL;
		Place( Matrix4::Identity );
	}
}