Kaynağa Gözat

Merge remote-tracking branch 'monkeyfirst/hotkeys-smg-instances'

Conflicts:
	bin/Data/EditorStrings.json
Lasse Öörni 10 yıl önce
ebeveyn
işleme
50013c85d4

+ 2 - 0
Docs/GettingStarted.dox

@@ -790,6 +790,8 @@ Z                  - Cycle through solid, wireframe and point rendering
 M                  - Show/Hide LayerEditor
 M                  - Show/Hide LayerEditor
 F                  - Focus on selected object (LookAt)               
 F                  - Focus on selected object (LookAt)               
 X                  - Delete node or component
 X                  - Delete node or component
+Alt+D              - Smart Duplicate (note: select one of axises on gizmo to show direction for next instance)
+Key "." or Del     - View Closer selected node(s)  
 \endverbatim
 \endverbatim
 
 
 Press right mouse button in the 3D view if you want to defocus the active window without changing the object selection.
 Press right mouse button in the 3D view if you want to defocus the active window without changing the object selection.

+ 6 - 0
Source/Urho3D/Scene/Node.cpp

@@ -289,6 +289,12 @@ void Node::SetScale(float scale)
 
 
 void Node::SetScale(const Vector3& scale)
 void Node::SetScale(const Vector3& scale)
 {
 {
+    if (Urho3D::IsNaN(scale.x_) || Urho3D::IsNaN(scale.y_) || Urho3D::IsNaN(scale.z_))
+    {
+        LOGWARNING("Attempt to set NaN node scale " + scale.ToString() + ", disregarding");
+        return;
+    }
+
     scale_ = scale;
     scale_ = scale;
     MarkDirty();
     MarkDirty();
 
 

+ 8 - 2
bin/Data/EditorStrings.json

@@ -854,7 +854,13 @@
 	"Renderer":{
 	"Renderer":{
 		"en":"Renderer",
 		"en":"Renderer",
 		"ru":"Рендерер"
 		"ru":"Рендерер"
+	},
+	"Please, use only nodes with one StaticModel for instansing":{
+		"en":"Please, use only nodes with one StaticModel for instansing",
+		"ru":"Пожалуйста, используйте только ноду с одной статической моделью для инстансинга"
+	},
+	"  CameraFlyMode: ":{
+		"en":"  CameraFlyMode: ",
+		"ru":"  Камера в режиме полета: "
 	}
 	}
 }
 }
-
-	

+ 22 - 3
bin/Data/Scripts/Editor/EditorHierarchyWindow.as

@@ -496,7 +496,7 @@ void SelectNode(Node@ node, bool multiselect)
         hierarchyList.ClearSelection();
         hierarchyList.ClearSelection();
         return;
         return;
     }
     }
-
+    
     lastSelectedNode = node;
     lastSelectedNode = node;
     uint index = GetListIndex(node);
     uint index = GetListIndex(node);
     uint numItems = hierarchyList.numItems;
     uint numItems = hierarchyList.numItems;
@@ -626,7 +626,7 @@ void HandleHierarchyListSelectionChange()
         else if (type == ITEM_NODE)
         else if (type == ITEM_NODE)
         {
         {
             Node@ node = GetListNode(index);
             Node@ node = GetListNode(index);
-            if (node !is null)
+            if (node !is null) 
                 selectedNodes.Push(node);
                 selectedNodes.Push(node);
         }
         }
         else if (type == ITEM_UI_ELEMENT)
         else if (type == ITEM_UI_ELEMENT)
@@ -636,7 +636,7 @@ void HandleHierarchyListSelectionChange()
                 selectedUIElements.Push(element);
                 selectedUIElements.Push(element);
         }
         }
     }
     }
-
+    
     // If only one node/UIElement selected, use it for editing
     // If only one node/UIElement selected, use it for editing
     if (selectedNodes.length == 1)
     if (selectedNodes.length == 1)
         editNode = selectedNodes[0];
         editNode = selectedNodes[0];
@@ -1530,6 +1530,20 @@ bool Paste()
     return false;
     return false;
 }
 }
 
 
+bool BlenderModeDelete() 
+{
+    // In this place maybe placed avoidance flags that not allow delete in some cases
+    
+    Array<UIElement@> actions;
+    actions.Push(CreateContextMenuItem("Delete?", "HandleBlenderModeDelete"));
+    if (actions.length > 0) {
+        ActivateContextMenu(actions);
+        return true;
+    }
+
+    return false;
+}
+
 bool Delete()
 bool Delete()
 {
 {
     if (CheckHierarchyWindowFocus())
     if (CheckHierarchyWindowFocus())
@@ -1667,6 +1681,11 @@ void HandleHierarchyContextDelete()
     Delete();
     Delete();
 }
 }
 
 
+void HandleBlenderModeDelete() 
+{
+    Delete();
+}
+
 void HandleHierarchyContextPaste()
 void HandleHierarchyContextPaste()
 {
 {
     Paste();
     Paste();

+ 4 - 2
bin/Data/Scripts/Editor/EditorLayers.as

@@ -47,10 +47,12 @@ void CreateLayerEditor()
 bool ShowLayerEditor()
 bool ShowLayerEditor()
 {
 {
     // avoid to show layer window when we type text in LineEdit
     // avoid to show layer window when we type text in LineEdit
-    if (ui.focusElement !is null && ui.focusElement.type == lineEditType) return false;
+    if (ui.focusElement !is null && ui.focusElement.type == lineEditType && lastSelectedNode.Get() is null) 
+        return false;
     
     
     // to avoid when we close dialog with selected other node
     // to avoid when we close dialog with selected other node
-    patternMaskNode = lastSelectedNode;
+    Node@ node = lastSelectedNode.Get(); 
+    patternMaskNode = node;
     
     
     // just change position if already opened
     // just change position if already opened
     if ( layerWindow.visible == true )
     if ( layerWindow.visible == true )

+ 81 - 3
bin/Data/Scripts/Editor/EditorScene.as

@@ -18,7 +18,6 @@ CreateMode instantiateMode = REPLICATED;
 bool sceneModified = false;
 bool sceneModified = false;
 bool runUpdate = false;
 bool runUpdate = false;
 
 
-Node@ lastSelectedNode;
 Array<Node@> selectedNodes;
 Array<Node@> selectedNodes;
 Array<Component@> selectedComponents;
 Array<Component@> selectedComponents;
 Node@ editNode;
 Node@ editNode;
@@ -38,6 +37,8 @@ uint undoStackPos = 0;
 bool revertOnPause = false;
 bool revertOnPause = false;
 XMLFile@ revertData;
 XMLFile@ revertData;
 
 
+Vector3 lastOffsetForSmartDuplicate;
+
 void ClearSceneSelection()
 void ClearSceneSelection()
 {
 {
     selectedNodes.Clear();
     selectedNodes.Clear();
@@ -774,7 +775,7 @@ bool SceneUnparent()
 
 
 bool NodesParentToLastSelected()
 bool NodesParentToLastSelected()
 {
 {
-    if (lastSelectedNode is null)
+    if (lastSelectedNode.Get() is null)
         return false;
         return false;
         
         
     if (!CheckHierarchyWindowFocus() || !selectedComponents.empty || selectedNodes.empty)
     if (!CheckHierarchyWindowFocus() || !selectedComponents.empty || selectedNodes.empty)
@@ -789,7 +790,7 @@ bool NodesParentToLastSelected()
     Array<Node@> changedNodes;
     Array<Node@> changedNodes;
     
     
     // Find new parent node it selected last
     // Find new parent node it selected last
-    Node@ lastNode = lastSelectedNode;
+    Node@ lastNode = lastSelectedNode.Get(); //GetListNode(hierarchyList.selection);
     
     
     for (uint i = 0; i < selectedNodes.length; ++i)
     for (uint i = 0; i < selectedNodes.length; ++i)
     {
     {
@@ -820,6 +821,83 @@ bool NodesParentToLastSelected()
     return true;
     return true;
 }
 }
 
 
+bool SceneSmartDuplicateNode() 
+{       
+    const float minOffset = 0.1;
+    
+    if (!CheckHierarchyWindowFocus() || !selectedComponents.empty 
+        || selectedNodes.empty || lastSelectedNode.Get() is null)
+        return false;
+    
+    
+    Node@ node = lastSelectedNode.Get();
+    Node@ parent = node.parent;
+    Vector3 offset = Vector3(1,0,0); // default offset
+    
+    if (parent is editorScene) // if parent of selected node is Scene make empty parent for it and place in same position; 
+    {
+        parent = CreateNode(LOCAL);
+        SceneChangeParent(parent, editorScene, false);
+        parent.worldPosition = node.worldPosition;
+        parent.name = node.name + "Group";
+        node.name = parent.name + "Instance" + String(parent.numChildren);
+        SceneChangeParent(node, parent, false);
+        parent = node.parent;
+        SelectNode(node, false);
+    } 
+    
+    Vector3 size;
+    BoundingBox bb;
+    
+    // get bb for offset  
+    Drawable@ drawable = GetFirstDrawable(node);
+    if (drawable !is null) 
+    {
+        bb = drawable.boundingBox;
+        size =  bb.size * drawable.node.worldScale;
+        offset = Vector3(size.x, 0, 0); 
+    } 
+    
+    // make offset on axis that select user by mouse
+    if (gizmoAxisX.selected)
+    {
+        if (size.x < minOffset) size.x = minOffset;
+        offset = node.worldRotation * Vector3(size.x,0,0);
+    }
+    else if (gizmoAxisY.selected)
+    {
+        if (size.y < minOffset) size.y = minOffset;
+        offset = node.worldRotation * Vector3(0,size.y,0);
+    }
+    else if (gizmoAxisZ.selected)
+    {
+        if (size.z < minOffset) size.z = minOffset;
+        offset = node.worldRotation * Vector3(0,0,size.z);
+    }
+    else
+        offset = lastOffsetForSmartDuplicate;    
+    
+    Vector3 lastInstancePosition = node.worldPosition;
+    
+    SelectNode(node, false);
+    SceneDuplicate();
+    Node@ newInstance = parent.children[parent.numChildren-1];
+    SelectNode(newInstance, false);
+    newInstance.worldPosition = lastInstancePosition;
+    newInstance.Translate(offset, TS_WORLD);
+    newInstance.name = parent.name + "Instance" + String(parent.numChildren-1);
+    
+    lastOffsetForSmartDuplicate = offset;
+    UpdateNodeAttributes();
+    return true;
+}
+
+bool ViewCloser()
+{
+    return (viewCloser = true);
+}
+
+
 bool SceneToggleEnable()
 bool SceneToggleEnable()
 {
 {
     if (!CheckHierarchyWindowFocus())
     if (!CheckHierarchyWindowFocus())

+ 24 - 10
bin/Data/Scripts/Editor/EditorUI.as

@@ -336,7 +336,7 @@ void CreateMenuBar()
         if ( hotKeyMode == HOTKEYS_MODE_STANDARD )
         if ( hotKeyMode == HOTKEYS_MODE_STANDARD )
             popup.AddChild(CreateMenuItem("Delete", @Delete, KEY_DELETE, QUAL_ANY));
             popup.AddChild(CreateMenuItem("Delete", @Delete, KEY_DELETE, QUAL_ANY));
         else if ( hotKeyMode == HOTKEYS_MODE_BLENDER )
         else if ( hotKeyMode == HOTKEYS_MODE_BLENDER )
-            popup.AddChild(CreateMenuItem("Delete", @Delete, 'X', QUAL_ANY));
+            popup.AddChild(CreateMenuItem("Delete", @BlenderModeDelete, 'X', QUAL_ANY));
         
         
         popup.AddChild(CreateMenuItem("Select all", @SelectAll, 'A', QUAL_CTRL));
         popup.AddChild(CreateMenuItem("Select all", @SelectAll, 'A', QUAL_CTRL));
         popup.AddChild(CreateMenuItem("Deselect all", @DeselectAll, 'A', QUAL_SHIFT | QUAL_CTRL));
         popup.AddChild(CreateMenuItem("Deselect all", @DeselectAll, 'A', QUAL_SHIFT | QUAL_CTRL));
@@ -386,8 +386,14 @@ void CreateMenuBar()
         //else if ( hotKeyMode == HOT_KEYS_MODE_BLENDER )
         //else if ( hotKeyMode == HOT_KEYS_MODE_BLENDER )
         //    popup.AddChild(CreateMenuItem("Toggle update", @ToggleSceneUpdate, 'P', QUAL_CTRL));
         //    popup.AddChild(CreateMenuItem("Toggle update", @ToggleSceneUpdate, 'P', QUAL_CTRL));
         
         
-        if ( hotKeyMode == HOTKEYS_MODE_BLENDER )
+        if ( hotKeyMode == HOTKEYS_MODE_BLENDER ) 
+        {
              popup.AddChild(CreateMenuItem("Move to layer", @ShowLayerMover, 'M'));
              popup.AddChild(CreateMenuItem("Move to layer", @ShowLayerMover, 'M'));
+             popup.AddChild(CreateMenuItem("Smart Duplicate", @SceneSmartDuplicateNode, 'D', QUAL_ALT));
+             popup.AddChild(CreateMenuItem("View closer", @ViewCloser, KEY_KP_PERIOD));                     
+        }
+        
+        CreateChildDivider(popup);
         
         
         popup.AddChild(CreateMenuItem("Stop test animation", @StopTestAnimation));
         popup.AddChild(CreateMenuItem("Stop test animation", @StopTestAnimation));
         CreateChildDivider(popup);
         CreateChildDivider(popup);
@@ -1255,6 +1261,7 @@ void HandleHotKeysBlender( VariantMap& eventData )
     }
     }
     else if (key == KEY_KP_5 && ui.focusElement is null)
     else if (key == KEY_KP_5 && ui.focusElement is null)
     {
     {
+        activeViewport.camera.zoom = 1;
         activeViewport.ToggleOrthographic();
         activeViewport.ToggleOrthographic();
     }
     }
     else if (key == '4')
     else if (key == '4')
@@ -1334,13 +1341,20 @@ void HandleHotKeysBlender( VariantMap& eventData )
                 }
                 }
                 else if (key == KEY_F) 
                 else if (key == KEY_F) 
                 {
                 {
-                    Vector3 center = Vector3(0,0,0);
-                    
-                    if (selectedNodes.length > 0)
-                        center = SelectedNodesCenterPoint(); 
-                    
-                    cameraNode.LookAt(center);
-                    ReacquireCameraYawPitch(); 
+                    if (camera.orthographic) 
+                    {
+                        viewCloser = true;
+                    }
+                    else
+                    {
+                        Vector3 center = Vector3(0,0,0);
+                        
+                        if (selectedNodes.length > 0)
+                            center = SelectedNodesCenterPoint(); 
+                        
+                        cameraNode.LookAt(center);
+                        ReacquireCameraYawPitch();
+                    } 
                 }
                 }
          }  
          }  
     }
     }
@@ -1496,7 +1510,7 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
 }
 }
 
 
 void UnfadeUI()
 void UnfadeUI()
-{
+{    
     FadeUI(false);
     FadeUI(false);
 }
 }
 
 

+ 110 - 17
bin/Data/Scripts/Editor/EditorView.as

@@ -22,7 +22,10 @@ bool contextMenuActionWaitFrame = false;
 bool cameraFlyMode = true;
 bool cameraFlyMode = true;
 int hotKeyMode = 0; // used for checking that kind of style manipulation user are prefer ( see HotKeysMode )
 int hotKeyMode = 0; // used for checking that kind of style manipulation user are prefer ( see HotKeysMode )
 Vector3 lastSelectedNodesCenterPoint = Vector3(0,0,0); // for Blender mode to avoid own origin rotation when no nodes are selected. preserve last center for this
 Vector3 lastSelectedNodesCenterPoint = Vector3(0,0,0); // for Blender mode to avoid own origin rotation when no nodes are selected. preserve last center for this
-
+WeakHandle lastSelectedNode = null;
+WeakHandle lastSelectedDrawable = null;
+WeakHandle lastSelectedComponent = null;
+bool viewCloser = false;
 
 
 const uint VIEWPORT_BORDER_H     = 0x00000001;
 const uint VIEWPORT_BORDER_H     = 0x00000001;
 const uint VIEWPORT_BORDER_H1    = 0x00000002;
 const uint VIEWPORT_BORDER_H1    = 0x00000002;
@@ -1137,7 +1140,7 @@ void UpdateStats(float timeStep)
     String adding = "";
     String adding = "";
     // Todo: add localization
     // Todo: add localization
     if (hotKeyMode == HOTKEYS_MODE_BLENDER)
     if (hotKeyMode == HOTKEYS_MODE_BLENDER)
-       adding = "  CameraFlyMode: " + (cameraFlyMode ? "True" : "False");
+        adding = localization.Get("  CameraFlyMode: ") + (cameraFlyMode ? "True" : "False");
     
     
     editorModeText.text = String(
     editorModeText.text = String(
         localization.Get("Mode: ") + localization.Get(editModeText[editMode]) +
         localization.Get("Mode: ") + localization.Get(editModeText[editMode]) +
@@ -1278,7 +1281,7 @@ void UpdateView(float timeStep)
             if (mouseWheelCameraPosition && !camera.orthographic )
             if (mouseWheelCameraPosition && !camera.orthographic )
             {   
             {   
                 if (input.keyDown[KEY_LSHIFT])
                 if (input.keyDown[KEY_LSHIFT])
-                    cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * -input.mouseMoveWheel*5* timeStep * speedMultiplier);
+                    cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * -input.mouseMoveWheel*20* timeStep * speedMultiplier);
                 else if (input.keyDown[KEY_LCTRL])
                 else if (input.keyDown[KEY_LCTRL])
                     cameraNode.Translate(Vector3(-cameraBaseSpeed,0, 0) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
                     cameraNode.Translate(Vector3(-cameraBaseSpeed,0, 0) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
                 else
                 else
@@ -1286,21 +1289,30 @@ void UpdateView(float timeStep)
             }
             }
             else
             else
             {   
             {   
-                if (input.keyDown[KEY_LSHIFT])
-                    cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * -input.mouseMoveWheel*5* timeStep * speedMultiplier);
-                else if (input.keyDown[KEY_LCTRL])
+                if (input.keyDown[KEY_LSHIFT]) 
+                {
+                    cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * -input.mouseMoveWheel*20* timeStep * speedMultiplier);
+                }
+                else if (input.keyDown[KEY_LCTRL]) 
+                {
                     cameraNode.Translate(Vector3(-cameraBaseSpeed,0, 0) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
                     cameraNode.Translate(Vector3(-cameraBaseSpeed,0, 0) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
+                }
                 else 
                 else 
                 {
                 {
-                    float zoom = camera.zoom + -input.mouseMoveWheel *.1 * speedMultiplier;
-                    camera.zoom = Clamp(zoom, .1, 30);
+                    if (input.qualifierDown[QUAL_ALT]) 
+                    {
+                        float zoom = camera.zoom + -input.mouseMoveWheel *.1 * speedMultiplier;
+                        camera.zoom = Clamp(zoom, .1, 30);
+                    }
+                    else 
+                    {
+                        cameraNode.Translate(Vector3(0, 0, -cameraBaseSpeed) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
+                    }    
                 }
                 }
             }
             }
-        }
-        
+        }       
     }
     }
 
 
-
     if (input.keyDown[KEY_HOME])
     if (input.keyDown[KEY_HOME])
     {
     {
         if (selectedNodes.length > 0 || selectedComponents.length > 0)
         if (selectedNodes.length > 0 || selectedComponents.length > 0)
@@ -1333,14 +1345,24 @@ void UpdateView(float timeStep)
         if (mouseMove.x != 0 || mouseMove.y != 0)
         if (mouseMove.x != 0 || mouseMove.y != 0)
         {
         {
             bool panTheCamera = false;
             bool panTheCamera = false;
+            
             if(mmbPanMode || (hotKeyMode == HOTKEYS_MODE_BLENDER))
             if(mmbPanMode || (hotKeyMode == HOTKEYS_MODE_BLENDER))
                 if ( hotKeyMode == HOTKEYS_MODE_STANDARD) 
                 if ( hotKeyMode == HOTKEYS_MODE_STANDARD) 
                     panTheCamera = !(changeCamViewButton && input.keyDown[KEY_LSHIFT]);
                     panTheCamera = !(changeCamViewButton && input.keyDown[KEY_LSHIFT]);
-                else if (hotKeyMode == HOTKEYS_MODE_BLENDER && cameraFlyMode == true )
+                else if (hotKeyMode == HOTKEYS_MODE_BLENDER && cameraFlyMode) 
+                {
                     panTheCamera = false;
                     panTheCamera = false;
-            else
-                panTheCamera = (changeCamViewButton && input.keyDown[KEY_LSHIFT]);
-
+                    //else if (camera.orthographic)
+                    //    panTheCamera = true;     
+                }
+            else 
+            {
+                if (!camera.orthographic)
+                    panTheCamera = changeCamViewButton && input.keyDown[KEY_LSHIFT];
+                else
+                    panTheCamera = changeCamViewButton && !input.keyDown[KEY_LSHIFT];
+            }
+                
             if (panTheCamera)
             if (panTheCamera)
                 cameraNode.Translate(Vector3(-mouseMove.x, mouseMove.y, 0) * timeStep * cameraBaseSpeed * 0.5);
                 cameraNode.Translate(Vector3(-mouseMove.x, mouseMove.y, 0) * timeStep * cameraBaseSpeed * 0.5);
             else
             else
@@ -1388,8 +1410,59 @@ void UpdateView(float timeStep)
 
 
     if (orbiting && !input.mouseButtonDown[MOUSEB_MIDDLE])
     if (orbiting && !input.mouseButtonDown[MOUSEB_MIDDLE])
         orbiting = false;
         orbiting = false;
-
+        
+    if ( hotKeyMode == HOTKEYS_MODE_BLENDER )
+    if ( viewCloser && lastSelectedDrawable.Get() !is null) 
+    {
+        SetMouseLock();
+        BoundingBox bb;
+        Vector3 centerPoint;
+        
+        if ( selectedNodes.length <= 1 )
+        {
+            Drawable@ drawable = lastSelectedDrawable.Get();
+            if (drawable !is null) 
+            {  
+                bb = drawable.boundingBox;
+                centerPoint = drawable.node.worldPosition;
+            }
+        }
+        else 
+        {
+            for (int i = 0; i < selectedNodes.length; i++) 
+            {
+                bb.Merge(selectedNodes[i].position);
+            }
+                  
+            centerPoint = SelectedNodesCenterPoint();
+        }
+        
+        float distance = bb.size.length;
+        if (camera.orthographic) // if we use viewCloser for 2D get current distance to avoid near clip
+            distance = cameraNode.worldPosition.length;
+        
+        Quaternion q = Quaternion(activeViewport.cameraPitch, activeViewport.cameraYaw, 0);
+        cameraNode.rotation = q;
+        cameraNode.worldPosition = centerPoint -  cameraNode.worldDirection * distance;
+        // ReacquireCameraYawPitch();
+        viewCloser =  false;
+    }
+    else 
+        viewCloser =  false;
+    
     // Move/rotate/scale object
     // Move/rotate/scale object
+    if ( hotKeyMode == HOTKEYS_MODE_BLENDER) // force to select component node for manipulation if selected only component and not his node
+    {   
+        if ((editMode != EDIT_SELECT && editNodes.empty) && lastSelectedComponent.Get() !is null )
+        {   
+            if (lastSelectedComponent.Get() !is null) 
+            {
+                Component@ component  = lastSelectedComponent.Get();
+                SelectNode(component.node, false);
+            }
+        }   
+    }
+    
     if (!editNodes.empty && editMode != EDIT_SELECT && input.keyDown[KEY_LCTRL])
     if (!editNodes.empty && editMode != EDIT_SELECT && input.keyDown[KEY_LCTRL])
     {
     {
         Vector3 adjust(0, 0, 0);
         Vector3 adjust(0, 0, 0);
@@ -1683,9 +1756,29 @@ void ViewRaycast(bool mouseClick)
 
 
         RayQueryResult result = editorScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, camera.farClip,
         RayQueryResult result = editorScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, camera.farClip,
             pickModeDrawableFlags[pickMode], 0x7fffffff);
             pickModeDrawableFlags[pickMode], 0x7fffffff);
+        
         if (result.drawable !is null)
         if (result.drawable !is null)
-        {
+        {            
             Drawable@ drawable = result.drawable;
             Drawable@ drawable = result.drawable;
+            
+            // for actual last selected node or component in both modes
+            if ( hotKeyMode == HOTKEYS_MODE_STANDARD ) {
+                if (input.mouseButtonDown[MOUSEB_LEFT]) 
+                {
+                    lastSelectedNode = drawable.node;
+                    lastSelectedDrawable = drawable;
+                    lastSelectedComponent = drawable;
+                }
+            }
+            else if ( hotKeyMode == HOTKEYS_MODE_BLENDER ) {
+                if (input.mouseButtonDown[MOUSEB_RIGHT]) 
+                {
+                    lastSelectedNode = drawable.node;
+                    lastSelectedDrawable = drawable;
+                    lastSelectedComponent = drawable;
+                }
+            }
+             
             // If selecting a terrain patch, select the parent terrain instead
             // If selecting a terrain patch, select the parent terrain instead
             if (drawable.typeName != "TerrainPatch")
             if (drawable.typeName != "TerrainPatch")
             {
             {