Browse Source

Multiple selection WIP

Josh Engebretson 10 years ago
parent
commit
d41f9c171f

+ 31 - 68
Script/AtomicEditor/ui/frames/HierarchyFrame.ts

@@ -36,9 +36,10 @@ class HierarchyFrame extends Atomic.UIWidget {
         hierarchycontainer = this.getWidget("hierarchycontainer");
         hierarchycontainer = this.getWidget("hierarchycontainer");
 
 
         var hierList = this.hierList = new Atomic.UIListView();
         var hierList = this.hierList = new Atomic.UIListView();
+        hierList.multiSelect = true;
         hierList.rootList.id = "hierList_";
         hierList.rootList.id = "hierList_";
 
 
-        hierList.subscribeToEvent("WidgetEvent", (event: Atomic.UIWidgetEvent) => this.handleHierListWidgetEvent(event));
+        hierList.subscribeToEvent("UIListViewSelectionChanged", (event: Atomic.UIListViewSelectionChangedEvent) => this.handleHierListSelectionChangedEvent(event));
 
 
         hierarchycontainer.addChild(hierList);
         hierarchycontainer.addChild(hierList);
 
 
@@ -117,24 +118,20 @@ class HierarchyFrame extends Atomic.UIWidget {
 
 
     }
     }
 
 
-    handleNodeAdded(ev: Atomic.NodeAddedEvent) {
+    handleSceneEditNodeAdded(ev: Editor.SceneEditNodeAddedEvent) {
 
 
         var node = ev.node;
         var node = ev.node;
 
 
         if (this.filterNode(node))
         if (this.filterNode(node))
             return;
             return;
 
 
-        if (!node.parent || node.scene != this.scene)
-            return;
-
         var parentID = this.nodeIDToItemID[node.parent.id];
         var parentID = this.nodeIDToItemID[node.parent.id];
-
         var childItemID = this.recursiveAddNode(parentID, node);
         var childItemID = this.recursiveAddNode(parentID, node);
 
 
         this.nodeIDToItemID[node.id] = childItemID;
         this.nodeIDToItemID[node.id] = childItemID;
     }
     }
 
 
-    handleNodeRemoved(ev: Atomic.NodeRemovedEvent) {
+    handleSceneEditNodeRemoved(ev: Editor.SceneEditNodeRemovedEvent) {
 
 
         // on close
         // on close
         if (!this.scene)
         if (!this.scene)
@@ -147,9 +144,6 @@ class HierarchyFrame extends Atomic.UIWidget {
 
 
         delete this.nodeIDToItemID[node.id];
         delete this.nodeIDToItemID[node.id];
 
 
-        if (!node.parent || node.scene != this.scene)
-            return;
-
         this.hierList.deleteItemByID(node.id.toString());
         this.hierList.deleteItemByID(node.id.toString());
 
 
     }
     }
@@ -173,8 +167,8 @@ class HierarchyFrame extends Atomic.UIWidget {
         if (this.scene) {
         if (this.scene) {
 
 
             this.subscribeToEvent(this.scene, "SceneNodeSelected", (event: Editor.SceneNodeSelectedEvent) => this.handleSceneNodeSelected(event));
             this.subscribeToEvent(this.scene, "SceneNodeSelected", (event: Editor.SceneNodeSelectedEvent) => this.handleSceneNodeSelected(event));
-            this.subscribeToEvent(this.scene, "NodeAdded", (ev: Atomic.NodeAddedEvent) => this.handleNodeAdded(ev));
-            this.subscribeToEvent(this.scene, "NodeRemoved", (ev: Atomic.NodeRemovedEvent) => this.handleNodeRemoved(ev));
+            this.subscribeToEvent(this.scene, "SceneEditNodeAdded", (ev: Editor.SceneEditNodeAddedEvent) => this.handleSceneEditNodeAdded(ev));
+            this.subscribeToEvent(this.scene, "SceneEditNodeRemoved", (ev: Editor.SceneEditNodeRemovedEvent) => this.handleSceneEditNodeRemoved(ev));
             this.subscribeToEvent(this.scene, "NodeNameChanged", (ev: Atomic.NodeNameChangedEvent) => {
             this.subscribeToEvent(this.scene, "NodeNameChanged", (ev: Atomic.NodeNameChangedEvent) => {
 
 
                 this.hierList.setItemText(ev.node.id.toString(), ev.node.name);
                 this.hierList.setItemText(ev.node.id.toString(), ev.node.name);
@@ -287,89 +281,58 @@ class HierarchyFrame extends Atomic.UIWidget {
 
 
             }
             }
 
 
+            this.scene.sendEvent("SceneEditAddRemoveNodes", {end: false});
+
+            this.scene.sendEvent("SceneEditNodeRemoved", {scene: this.scene, node:dragNode, parent:dragNode.parent});
+
             // move it
             // move it
             dropNode.addChild(dragNode);
             dropNode.addChild(dragNode);
 
 
+            this.scene.sendEvent("SceneEditNodeAdded", {scene: this.scene, node:dragNode, dropNode});
+
+            this.scene.sendEvent("SceneEditAddRemoveNodes", {end: true});
+
         } else if (typeName == "Asset") {
         } else if (typeName == "Asset") {
 
 
             var asset = <ToolCore.Asset>ev.dragObject.object;
             var asset = <ToolCore.Asset>ev.dragObject.object;
-            asset.instantiateNode(dropNode, asset.name);
-
+            var newNode = asset.instantiateNode(dropNode, asset.name);
+            if (newNode) {
+                this.sceneEditor.registerNode(newNode);
+                // getting a click event after this (I think) which
+                // is causing the dropNode to be selected
+                this.sceneEditor.selection.addNode(newNode, true);
+            }
         }
         }
-
     }
     }
 
 
     handleSceneNodeSelected(ev: Editor.SceneNodeSelectedEvent) {
     handleSceneNodeSelected(ev: Editor.SceneNodeSelectedEvent) {
 
 
-        if (ev.selected) {
-            this.hierList.selectItemByID(ev.node.id.toString(), true, true);
-        } else {
-            this.hierList.selectItemByID(ev.node.id.toString(), false, true);
-        }
-
+        this.hierList.selectItemByID(ev.node.id.toString(), ev.selected);
         this.hierList.scrollToSelectedItem();
         this.hierList.scrollToSelectedItem();
 
 
     }
     }
 
 
-    handleHierListWidgetEvent(event: Atomic.UIWidgetEvent): boolean {
+    handleHierListSelectionChangedEvent(event: Atomic.UIListViewSelectionChangedEvent) {
 
 
-        if (event.type == Atomic.UI_EVENT_TYPE_CUSTOM) {
+        if (!this.scene)
+            return;
 
 
-            var hierList = this.hierList;
-            if (event.refid == "select_list_selection_changed") {
+        var node = this.scene.getNode(Number(event.refid));
 
 
-                for (var i = 0; i < hierList.rootList.numItems; i++) {
+        if (node) {
 
 
-                    var selected = hierList.rootList.getItemSelected(i);
-                    var id = hierList.rootList.getItemID(i);
-                    var node = this.scene.getNode(Number(id));
-                    if (node) {
+            if (event.selected)
+                this.sceneEditor.selection.addNode(node);
+            else
+                this.sceneEditor.selection.removeNode(node);
 
 
-                        if (selected)
-                            this.sceneEditor.selection.addNode(node);
-                        else
-                            this.sceneEditor.selection.removeNode(node);
-                    }
-                }
-            }
         }
         }
-
-        return false;
-
     }
     }
 
 
     handleWidgetEvent(data: Atomic.UIWidgetEvent): boolean {
     handleWidgetEvent(data: Atomic.UIWidgetEvent): boolean {
 
 
         if (data.type == Atomic.UI_EVENT_TYPE_KEY_UP) {
         if (data.type == Atomic.UI_EVENT_TYPE_KEY_UP) {
 
 
-            if (data.key == Atomic.KEY_RIGHT) {
-                var selectedId = Number(this.hierList.selectedItemID);
-                var itemNodeId = this.nodeIDToItemID[selectedId];
-
-                if (!this.hierList.getExpanded(itemNodeId) && this.hierList.getExpandable(itemNodeId)) {
-                    this.hierList.setExpanded(itemNodeId, true);
-                    this.hierList.rootList.invalidateList();
-                } else {
-                    this.hierList.rootList.selectNextItem();
-                }
-
-            } else if (data.key == Atomic.KEY_LEFT) {
-                var selectedId = Number(this.hierList.selectedItemID);
-                var itemNodeId = this.nodeIDToItemID[selectedId];
-
-                if (this.hierList.getExpanded(itemNodeId)) {
-                    this.hierList.setExpanded(itemNodeId, false);
-                    this.hierList.rootList.invalidateList();
-                } else {
-                    var node = this.scene.getNode(selectedId);
-                    var parentNode = node.getParent();
-                    if (parentNode) {
-                        this.hierList.selectItemByID(parentNode.id.toString());
-                    }
-                }
-
-            }
-
             // node deletion
             // node deletion
             if (data.key == Atomic.KEY_DELETE || data.key == Atomic.KEY_BACKSPACE) {
             if (data.key == Atomic.KEY_DELETE || data.key == Atomic.KEY_BACKSPACE) {
                 this.sceneEditor.selection.delete();
                 this.sceneEditor.selection.delete();

+ 20 - 55
Script/AtomicEditor/ui/frames/ProjectFrame.ts

@@ -51,6 +51,8 @@ class ProjectFrame extends ScriptWidget {
         this.subscribeToEvent("ResourceRemoved", (ev: ToolCore.ResourceRemovedEvent) => this.handleResourceRemoved(ev));
         this.subscribeToEvent("ResourceRemoved", (ev: ToolCore.ResourceRemovedEvent) => this.handleResourceRemoved(ev));
         this.subscribeToEvent("AssetRenamed", (ev: ToolCore.AssetRenamedEvent) => this.handleAssetRenamed(ev));
         this.subscribeToEvent("AssetRenamed", (ev: ToolCore.AssetRenamedEvent) => this.handleAssetRenamed(ev));
 
 
+        folderList.subscribeToEvent("UIListViewSelectionChanged", (event: Atomic.UIListViewSelectionChangedEvent) => this.handleFolderListSelectionChangedEvent(event));
+
         // this.subscribeToEvent(EditorEvents.ResourceFolderCreated, (ev: EditorEvents.ResourceFolderCreatedEvent) => this.handleResourceFolderCreated(ev));
         // this.subscribeToEvent(EditorEvents.ResourceFolderCreated, (ev: EditorEvents.ResourceFolderCreatedEvent) => this.handleResourceFolderCreated(ev));
 
 
         // this uses FileWatcher which doesn't catch subfolder creation
         // this uses FileWatcher which doesn't catch subfolder creation
@@ -70,8 +72,7 @@ class ProjectFrame extends ScriptWidget {
 
 
             if (widget.id == ev.asset.guid) {
             if (widget.id == ev.asset.guid) {
 
 
-                if (widget['assetButton'])
-                {
+                if (widget['assetButton']) {
                     widget['assetButton'].text = ev.asset.name + ev.asset.extension;
                     widget['assetButton'].text = ev.asset.name + ev.asset.extension;
                     widget['assetButton'].dragObject = new Atomic.UIDragObject(ev.asset, ev.asset.name);
                     widget['assetButton'].dragObject = new Atomic.UIDragObject(ev.asset, ev.asset.name);
                 }
                 }
@@ -136,56 +137,6 @@ class ProjectFrame extends ScriptWidget {
 
 
     handleWidgetEvent(data: Atomic.UIWidgetEvent): boolean {
     handleWidgetEvent(data: Atomic.UIWidgetEvent): boolean {
 
 
-        if (data.type == Atomic.UI_EVENT_TYPE_KEY_UP) {
-
-          if (data.key == Atomic.KEY_RIGHT) {
-              var selectedId = this.folderList.selectedItemID;
-              var itemAssetId = this.assetGUIDToItemID[selectedId];
-
-              if (selectedId != "0") {
-                  if (!this.folderList.getExpanded(itemAssetId) && this.folderList.getExpandable(itemAssetId)) {
-                      this.folderList.setExpanded(itemAssetId, true);
-                      this.folderList.rootList.invalidateList();
-                  } else {
-                      this.folderList.rootList.selectNextItem();
-                  }
-              }
-
-
-          } else if (data.key == Atomic.KEY_LEFT) {
-              var selectedId = this.folderList.selectedItemID;
-              var itemAssetId = this.assetGUIDToItemID[selectedId];
-              if (selectedId != "0") {
-                  if (this.folderList.getExpanded(itemAssetId)) {
-                      this.folderList.setExpanded(itemAssetId, false);
-                      this.folderList.rootList.invalidateList();
-                  } else {
-                      var db = ToolCore.getAssetDatabase();
-
-                      var asset = db.getAssetByGUID(selectedId);
-
-                      var parentAsset = asset.parent;
-                      if (parentAsset) {
-                         this.folderList.selectItemByID(parentAsset.guid.toString());
-                      }
-                  }
-              }
-          }
-
-            if (data.key == Atomic.KEY_DOWN || data.key == Atomic.KEY_UP || data.key == Atomic.KEY_LEFT || data.key == Atomic.KEY_RIGHT) {
-
-                var selectedId = this.folderList.selectedItemID;
-
-                if (selectedId != "0") {
-                    var db = ToolCore.getAssetDatabase();
-
-                    var asset = db.getAssetByGUID(selectedId);
-
-                    if (asset.isFolder)
-                        this.refreshContent(asset);
-                }
-            }
-        }
         if (data.type == Atomic.UI_EVENT_TYPE_RIGHT_POINTER_UP) {
         if (data.type == Atomic.UI_EVENT_TYPE_RIGHT_POINTER_UP) {
 
 
             var id = data.target.id;
             var id = data.target.id;
@@ -295,6 +246,20 @@ class ProjectFrame extends ScriptWidget {
 
 
     }
     }
 
 
+    handleFolderListSelectionChangedEvent(event: Atomic.UIListViewSelectionChangedEvent) {
+
+        var selectedId = this.folderList.selectedItemID;
+
+        if (selectedId != "0") {
+            var db = ToolCore.getAssetDatabase();
+
+            var asset = db.getAssetByGUID(selectedId);
+
+            if (asset.isFolder)
+                this.refreshContent(asset);
+        }
+    }
+
     handleDragEnded(data: Atomic.DragEndedEvent) {
     handleDragEnded(data: Atomic.DragEndedEvent) {
 
 
         var asset: ToolCore.Asset;
         var asset: ToolCore.Asset;
@@ -306,10 +271,10 @@ class ProjectFrame extends ScriptWidget {
             if (data.target.id == "contentcontainerscroll" || container.isAncestorOf(data.target)) {
             if (data.target.id == "contentcontainerscroll" || container.isAncestorOf(data.target)) {
 
 
                 if (data.target["asset"])
                 if (data.target["asset"])
-                  asset = <ToolCore.Asset> data.target["asset"];
+                    asset = <ToolCore.Asset>data.target["asset"];
 
 
                 if (!asset || !asset.isFolder)
                 if (!asset || !asset.isFolder)
-                  asset = this.currentFolder;
+                    asset = this.currentFolder;
             }
             }
 
 
         }
         }
@@ -358,7 +323,7 @@ class ProjectFrame extends ScriptWidget {
 
 
         } else if (dragObject.object && dragObject.object.typeName == "Asset") {
         } else if (dragObject.object && dragObject.object.typeName == "Asset") {
 
 
-            var dragAsset = <ToolCore.Asset> dragObject.object;
+            var dragAsset = <ToolCore.Asset>dragObject.object;
 
 
             // get the folder we dragged on
             // get the folder we dragged on
             var destPath = Atomic.addTrailingSlash(asset.path);
             var destPath = Atomic.addTrailingSlash(asset.path);

+ 29 - 0
Script/TypeScript/AtomicWork.d.ts

@@ -76,6 +76,13 @@ declare module Atomic {
 
 
     }
     }
 
 
+    export interface UIListViewSelectionChangedEvent {
+
+        refid: string;
+        selected: boolean;
+        
+    }
+
     export interface NodeAddedEvent {
     export interface NodeAddedEvent {
 
 
         scene: Atomic.Scene;
         scene: Atomic.Scene;
@@ -255,6 +262,28 @@ declare module Editor {
     selected: boolean;
     selected: boolean;
   }
   }
 
 
+  export interface SceneEditAddRemoveNodesEvent {
+
+      end: boolean;
+
+  }
+
+
+  export interface SceneEditNodeAddedEvent {
+
+      scene: Atomic.Scene;
+      parent: Atomic.Node;
+      node: Atomic.Node;
+
+  }
+
+  export interface SceneEditNodeRemovedEvent {
+
+      scene: Atomic.Scene;
+      parent: Atomic.Node;
+      node: Atomic.Node;
+
+  }
 
 
   export interface GizmoEditModeChangedEvent {
   export interface GizmoEditModeChangedEvent {
     mode:EditMode;
     mode:EditMode;

+ 7 - 0
Source/Atomic/UI/UIEvents.h

@@ -127,4 +127,11 @@ EVENT(E_UIUNHANDLEDSHORTCUT, UIUnhandledShortcut)
     PARAM(P_REFID, RefID); // string tbid
     PARAM(P_REFID, RefID); // string tbid
 }
 }
 
 
+EVENT(E_UILISTVIEWSELECTIONCHANGED, UIListViewSelectionChanged)
+{
+    PARAM(P_REFID, RefID); // string tbid
+    PARAM(P_SELECTED, Selected);        // bool
+}
+
+
 }
 }

+ 319 - 53
Source/Atomic/UI/UIListView.cpp

@@ -23,6 +23,10 @@
 #include <TurboBadger/tb_menu_window.h>
 #include <TurboBadger/tb_menu_window.h>
 #include <TurboBadger/tb_select.h>
 #include <TurboBadger/tb_select.h>
 
 
+#include <Atomic/IO/Log.h>
+
+#include "UI.h"
+#include "UIEvents.h"
 #include "UIListView.h"
 #include "UIListView.h"
 
 
 using namespace tb;
 using namespace tb;
@@ -33,20 +37,71 @@ namespace Atomic
 class ListViewItemSource;
 class ListViewItemSource;
 class ListViewItemWidget;
 class ListViewItemWidget;
 
 
+
+class ListViewItemWidget : public TBLayout
+{
+public:
+    ListViewItemWidget(ListViewItem *item, ListViewItemSource *source, TBSelectItemViewer *sourceviewer, int index);
+    virtual bool OnEvent(const TBWidgetEvent &ev);
+
+    void UpdateText(const String& text)
+    {
+        if (textField_)
+            textField_->SetText(text.CString());
+    }
+
+    void UpdateIcon(const String& icon)
+    {
+        if (icon_)
+            icon_->SetSkinBg(TBIDC(icon.CString()));
+    }
+
+    void UpdateTextSkin(const String& skin)
+    {
+        if (textField_)
+            textField_->SetSkinBg(TBIDC(skin.CString()));
+    }
+
+    void SetExpanded(bool expanded)
+    {
+        if (expandBox_)
+            expandBox_->SetValue(expanded ? 1 : 0);
+
+    }
+
+
+private:
+    TBCheckBox* expandBox_;
+    TBTextField* textField_;
+    TBSkinImage* icon_;
+    ListViewItemSource *source_;
+    TBSelectItemViewer *sourceviewer_;
+    int index_;
+    ListViewItem* item_;
+};
+
+
 class ListViewItem : public TBGenericStringItem
 class ListViewItem : public TBGenericStringItem
 {
 {
     bool expanded_;
     bool expanded_;
+    bool selected_;
 
 
 public:
 public:
     ListViewItem(const char *str, const TBID &id, const char* icon,  ListViewItemSource* source)
     ListViewItem(const char *str, const TBID &id, const char* icon,  ListViewItemSource* source)
         : TBGenericStringItem(str, id), source_(source), parent_(0),
         : TBGenericStringItem(str, id), source_(source), parent_(0),
-          depth_(0), widget_(0), expanded_(false), icon_(icon)
+          depth_(0), widget_(0), expanded_(false), icon_(icon), selected_(false)
     {
     {
 
 
     }
     }
 
 
     ListViewItem* AddChild(const char* text, const char* icon, const TBID &id);
     ListViewItem* AddChild(const char* text, const char* icon, const TBID &id);
 
 
+    bool GetSelected() { return selected_; }
+    void SetSelected(bool value)
+    {
+        selected_ = value;
+    }
+
     bool GetExpanded() { return expanded_; }
     bool GetExpanded() { return expanded_; }
 
 
     void GetChildren(PODVector<ListViewItem*>& children, bool recursive = false)
     void GetChildren(PODVector<ListViewItem*>& children, bool recursive = false)
@@ -64,20 +119,20 @@ public:
 
 
     void SetExpanded(bool expanded)
     void SetExpanded(bool expanded)
     {
     {
+        if (widget_)
+            widget_->SetExpanded(expanded);
+
         expanded_ = expanded;
         expanded_ = expanded;
+
         if (!expanded_)
         if (!expanded_)
         {
         {
-            for (unsigned i = 0; i < children_.Size(); i ++)
-                children_[i]->SetExpanded(expanded);
+            //for (unsigned i = 0; i < children_.Size(); i ++)
+            //    children_[i]->SetExpanded(expanded);
         }
         }
         else
         else
         {
         {
-            ListViewItem* p = parent_;
-            while (p)
-            {
-                p->expanded_ = true;
-                p = p->parent_;
-            }
+            if (parent_)
+                parent_->SetExpanded(expanded_);
         }
         }
     }
     }
 
 
@@ -94,46 +149,12 @@ public:
     String textSkin_;
     String textSkin_;
 };
 };
 
 
-class ListViewItemWidget : public TBLayout
-{
-public:
-    ListViewItemWidget(ListViewItem *item, ListViewItemSource *source, TBSelectItemViewer *sourceviewer, int index);
-    virtual bool OnEvent(const TBWidgetEvent &ev);
-
-    void UpdateText(const String& text)
-    {
-        if (textField_)
-            textField_->SetText(text.CString());
-    }
-
-    void UpdateIcon(const String& icon)
-    {
-        if (icon_)
-            icon_->SetSkinBg(TBIDC(icon.CString()));
-    }
-
-    void UpdateTextSkin(const String& skin)
-    {
-        if (textField_)
-            textField_->SetSkinBg(TBIDC(skin.CString()));
-    }
-
-
-private:
-    TBCheckBox* expandBox_;
-    TBTextField* textField_;
-    TBSkinImage* icon_;
-    ListViewItemSource *source_;
-    TBSelectItemViewer *sourceviewer_;
-    int index_;
-    ListViewItem* item_;
-};
 
 
 class ListViewItemSource : public TBSelectItemSourceList<ListViewItem>
 class ListViewItemSource : public TBSelectItemSourceList<ListViewItem>
 {
 {
 public:
 public:
-    TBSelectList* list_;
-    ListViewItemSource(TBSelectList* list) : list_(list) {}
+    UIListView* uiListView_;
+    ListViewItemSource(UIListView* list) : uiListView_(list) {}
     virtual ~ListViewItemSource() {}
     virtual ~ListViewItemSource() {}
     virtual bool Filter(int index, const char *filter);
     virtual bool Filter(int index, const char *filter);
     virtual TBWidget *CreateItemWidget(int index, TBSelectItemViewer *viewer);
     virtual TBWidget *CreateItemWidget(int index, TBSelectItemViewer *viewer);
@@ -320,7 +341,7 @@ bool ListViewItemWidget::OnEvent(const TBWidgetEvent &ev)
     {
     {
         item_->SetExpanded(!item_->GetExpanded());
         item_->SetExpanded(!item_->GetExpanded());
 
 
-        source_->list_->InvalidateList();
+        source_->uiListView_->UpdateItemVisibility();
 
 
         // want to bubble
         // want to bubble
         return false;
         return false;
@@ -340,7 +361,7 @@ bool ListViewItemSource::Filter(int index, const char *filter)
     if (item->parent_->GetExpanded())
     if (item->parent_->GetExpanded())
         return true;
         return true;
 
 
-    return false;
+    return true;
 
 
 }
 }
 
 
@@ -379,7 +400,7 @@ static int select_list_sort_cb(TBSelectItemSource *_source, const int *a, const
 
 
 UIListView::UIListView(Context* context, bool createWidget) :
 UIListView::UIListView(Context* context, bool createWidget) :
     UIWidget(context, createWidget),
     UIWidget(context, createWidget),
-    source_(0), itemLookupId_(0)
+    source_(0), itemLookupId_(0), multiSelect_(false)
 {
 {
     rootList_ = new UISelectList(context);
     rootList_ = new UISelectList(context);
 
 
@@ -389,7 +410,7 @@ UIListView::UIListView(Context* context, bool createWidget) :
     widget_->SetGravity(WIDGET_GRAVITY_ALL);
     widget_->SetGravity(WIDGET_GRAVITY_ALL);
     rootList_->SetGravity(UI_GRAVITY_ALL);
     rootList_->SetGravity(UI_GRAVITY_ALL);
 
 
-    source_ = new ListViewItemSource(rootList_->GetTBSelectList());
+    source_ = new ListViewItemSource(this);
 
 
     rootList_->GetTBSelectList()->SetSource(source_);
     rootList_->GetTBSelectList()->SetSource(source_);
 
 
@@ -489,6 +510,8 @@ void UIListView::DeleteItemByID(const String& id)
 
 
             source_->DeleteItem(i);
             source_->DeleteItem(i);
 
 
+            rootList_->InvalidateList();
+
             return;
             return;
         }
         }
     }
     }
@@ -543,7 +566,7 @@ void UIListView::DeleteAllItems()
 }
 }
 
 
 
 
-void UIListView::SelectItemByID(const String& id, bool selected, bool focus)
+void UIListView::SelectItemByID(const String& id, bool selected)
 {
 {
     TBID tid = TBIDC(id.CString());
     TBID tid = TBIDC(id.CString());
 
 
@@ -553,10 +576,26 @@ void UIListView::SelectItemByID(const String& id, bool selected, bool focus)
 
 
         if (tid == item->id)
         if (tid == item->id)
         {
         {
-            if (selected && focus)
-                rootList_->SetValue(i);
+            if (selected)
+            {
+                if (item->GetSelected())
+                    return;
+
+                item->SetSelected(selected);
+                item->SetExpanded(true);
+                SetValueFirstSelected();
+                UpdateItemVisibility();
+                ScrollToSelectedItem();
+            }
             else
             else
-                rootList_->SelectItem(i, selected);
+            {
+                if (!item->GetSelected())
+                    return;
+
+                item->SetSelected(false);
+                UpdateItemVisibility();
+
+            }
 
 
             return;
             return;
         }
         }
@@ -564,6 +603,46 @@ void UIListView::SelectItemByID(const String& id, bool selected, bool focus)
     }
     }
 }
 }
 
 
+void UIListView::UpdateItemVisibility()
+{
+    UI* ui = GetSubsystem<UI>();
+    VariantMap eventData;
+
+    for (int i = 0; i < source_->GetNumItems(); i++)
+    {
+        ListViewItem* item = source_->GetItem(i);
+
+        String refid;
+        ui->GetTBIDString(item->id, refid);
+
+        eventData[UIListViewSelectionChanged::P_REFID] = refid;
+        eventData[UIListViewSelectionChanged::P_SELECTED] = item->GetSelected();
+
+        this->SendEvent(E_UILISTVIEWSELECTIONCHANGED, eventData);
+
+        if (!item->widget_)
+            continue;
+
+        item->widget_->SetVisibilility(WIDGET_VISIBILITY_VISIBLE);
+        item->widget_->SetState(WIDGET_STATE_SELECTED, item->GetSelected());
+
+        ListViewItem* parent = item->parent_;
+        while (parent)
+        {
+            if (!parent->GetExpanded())
+                break;
+
+            parent = parent->parent_;
+        }
+
+        if (parent)
+            item->widget_->SetVisibilility(WIDGET_VISIBILITY_GONE);
+    }
+
+    tb::TBScrollContainer* scroll = (tb::TBScrollContainer*) rootList_->GetInternalWidget()->GetFirstChild();
+    scroll->OnProcess();
+}
+
 void UIListView::ScrollToSelectedItem()
 void UIListView::ScrollToSelectedItem()
 {
 {
     if (rootList_.Null())
     if (rootList_.Null())
@@ -572,5 +651,192 @@ void UIListView::ScrollToSelectedItem()
     rootList_->ScrollToSelectedItem();
     rootList_->ScrollToSelectedItem();
 }
 }
 
 
+void UIListView::SelectAllItems(bool select)
+{
+    for (int i = 0; i < source_->GetNumItems(); i++)
+    {
+        ListViewItem* item = source_->GetItem(i);
+        item->SetSelected(select);
+    }
+
+}
+
+void UIListView::SetValueFirstSelected()
+{
+    int index = -1;
+
+    for (int i = 0; i < source_->GetNumItems(); i++)
+    {
+        ListViewItem* item = source_->GetItem(i);
+        if (item->GetSelected())
+        {
+            index = i;
+            break;
+        }
+    }
+
+    rootList_->SetValue(index);
+
+}
+
+void UIListView::SelectSingleItem(ListViewItem* item, bool expand)
+{
+    SelectAllItems(false);
+    if (expand)
+        item->SetExpanded(true);
+    item->SetSelected(true);
+    UpdateItemVisibility();
+
+    SetValueFirstSelected();
+    ScrollToSelectedItem();
+}
+
+void UIListView::Move(tb::SPECIAL_KEY key)
+{
+    // selected index
+    int index = -1;
+
+    for (int i = 0; i < source_->GetNumItems(); i++)
+    {
+        ListViewItem* item = source_->GetItem(i);
+        if (item->GetSelected())
+        {
+            index = i;
+            break;
+        }
+    }
+
+    // nothing selected
+    if (index == -1)
+        return;
+
+    if (key == TB_KEY_LEFT)
+    {
+        ListViewItem* item = source_->GetItem(index);
+        if (item->children_.Size() > 0 && item->GetExpanded())
+        {
+            item->SetExpanded(false);
+            UpdateItemVisibility();
+        }
+        else
+        {
+            key = TB_KEY_UP;
+        }
+    }
+
+    if (key == TB_KEY_RIGHT)
+    {
+        ListViewItem* item = source_->GetItem(index);
+        if (item->children_.Size() > 0 && !item->GetExpanded())
+        {
+            item->SetExpanded(true);
+            UpdateItemVisibility();
+        }
+        else
+        {
+            key = TB_KEY_DOWN;
+        }
+    }
+
+
+    if (key == TB_KEY_UP)
+    {
+        // can't go any further up list
+        if (index == 0)
+            return;
+
+        for (int i = (int) (index - 1 ); i >= 0; i--)
+        {
+            ListViewItem* item = source_->GetItem(i);
+            if (item->widget_ && item->widget_->GetVisibility() == WIDGET_VISIBILITY_VISIBLE)
+            {
+                SelectSingleItem(item, false);
+                return;
+            }
+
+        }
+
+    }
+
+    if (key == TB_KEY_DOWN)
+    {
+        // can't go any further down list
+        if (index == source_->GetNumItems() - 1)
+            return;
+
+        for (int i = index + 1; i < source_->GetNumItems(); i++)
+        {
+            ListViewItem* item = source_->GetItem(i);
+            if (item->widget_ && item->widget_->GetVisibility() == WIDGET_VISIBILITY_VISIBLE)
+            {
+                SelectSingleItem(item, false);
+                return;
+            }
+
+        }
+
+    }
+
+}
+
+bool UIListView::OnEvent(const tb::TBWidgetEvent &ev)
+{
+
+    if (ev.type == EVENT_TYPE_KEY_UP )
+    {
+        if (ev.special_key == TB_KEY_DOWN || ev.special_key == TB_KEY_UP || ev.special_key == TB_KEY_LEFT || ev.special_key == TB_KEY_RIGHT)
+        {
+            Move(ev.special_key);
+            return true;
+        }
+    }
+
+    if (ev.type == EVENT_TYPE_CUSTOM && ev.ref_id == TBIDC("select_list_validation_end"))
+    {
+        UpdateItemVisibility();
+        return true;
+    }
+
+    if (ev.type == EVENT_TYPE_CUSTOM && ev.ref_id == TBIDC("select_list_selection_changed"))
+    {
+        for (int i = 0; i < source_->GetNumItems(); i++)
+        {
+            ListViewItem* item = source_->GetItem(i);
+
+            if (item->id == ev.target->GetID())
+            {
+                bool multi = false;
+                if (multiSelect_ && (ev.modifierkeys & TB_SHIFT || ev.modifierkeys & TB_CTRL || ev.modifierkeys & TB_SUPER))
+                    multi = true;
+
+                if (multi)
+                {
+                    if (item->GetSelected())
+                    {
+                        item->SetSelected(false);
+                        UpdateItemVisibility();
+                    }
+                    else                   {
+
+                        item->SetSelected(true);
+                        UpdateItemVisibility();
+                    }
+
+                    SetValueFirstSelected();
+
+                }
+                else
+                {
+                    SelectSingleItem(item);
+                }
+
+                return true;
+            }
+
+        }
+}
+
+    return UIWidget::OnEvent(ev);
+}
 
 
 }
 }

+ 18 - 1
Source/Atomic/UI/UIListView.h

@@ -58,16 +58,33 @@ public:
     bool GetExpanded(unsigned itemID);
     bool GetExpanded(unsigned itemID);
     bool GetExpandable(unsigned itemID);
     bool GetExpandable(unsigned itemID);
 
 
+    bool GetMultiSelect() const { return multiSelect_; }
+    void SetMultiSelect(bool value) { multiSelect_ = value; }
+
     void DeleteAllItems();
     void DeleteAllItems();
-    void SelectItemByID(const String& id, bool selected = true, bool focus = true);
+    void SelectItemByID(const String& id, bool selected = true);
 
 
     String GetHoverItemID() { return rootList_.Null() ? "" : rootList_->GetHoverItemID(); }
     String GetHoverItemID() { return rootList_.Null() ? "" : rootList_->GetHoverItemID(); }
     String GetSelectedItemID() { return rootList_.Null() ? "" : rootList_->GetSelectedItemID(); }
     String GetSelectedItemID() { return rootList_.Null() ? "" : rootList_->GetSelectedItemID(); }
 
 
     UISelectList* GetRootList() { return rootList_; }
     UISelectList* GetRootList() { return rootList_; }
 
 
+    void UpdateItemVisibility();
+
+    void SelectAllItems(bool select = true);
+
+protected:
+
+    virtual bool OnEvent(const tb::TBWidgetEvent &ev);
+
 private:
 private:
 
 
+    void SelectSingleItem(ListViewItem* item, bool expand = true);
+    void SetValueFirstSelected();
+    void Move(tb::SPECIAL_KEY key);
+
+    bool multiSelect_;
+
     SharedPtr<UISelectList> rootList_;
     SharedPtr<UISelectList> rootList_;
     ListViewItemSource* source_;
     ListViewItemSource* source_;
 
 

+ 12 - 6
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditHistory.cpp

@@ -24,8 +24,8 @@ SceneEditHistory::SceneEditHistory(Context* context, SceneEditor3D* sceneEditor)
 
 
     SubscribeToEvent(sceneEditor_->GetScene(), E_SCENEEDITADDREMOVENODES, HANDLER(SceneEditHistory, HandleSceneEditAddRemoveNodes));
     SubscribeToEvent(sceneEditor_->GetScene(), E_SCENEEDITADDREMOVENODES, HANDLER(SceneEditHistory, HandleSceneEditAddRemoveNodes));
 
 
-    SubscribeToEvent(sceneEditor_->GetScene(), E_NODEADDED, HANDLER(SceneEditHistory, HandleNodeAdded));
-    SubscribeToEvent(sceneEditor_->GetScene(), E_NODEREMOVED, HANDLER(SceneEditHistory, HandleNodeRemoved));
+    SubscribeToEvent(sceneEditor_->GetScene(), E_SCENEEDITNODEADDED, HANDLER(SceneEditHistory, HandleSceneEditNodeAdded));
+    SubscribeToEvent(sceneEditor_->GetScene(), E_SCENEEDITNODEREMOVED, HANDLER(SceneEditHistory, HandleSceneEditNodeRemoved));
 
 
 }
 }
 
 
@@ -61,27 +61,31 @@ void SceneEditHistory::HandleSceneEditAddRemoveNodes(StringHash eventType, Varia
         addingRemovingNodes_ = true;
         addingRemovingNodes_ = true;
         EndSelectionEdit(false);
         EndSelectionEdit(false);
 
 
-        curSelEditOp_ = new SelectionEditOp();
+        curSelEditOp_ = new SelectionEditOp(sceneEditor_->GetScene());
 
 
     }
     }
 }
 }
 
 
-void SceneEditHistory::HandleNodeAdded(StringHash eventType, VariantMap& eventData)
+void SceneEditHistory::HandleSceneEditNodeAdded(StringHash eventType, VariantMap& eventData)
 {
 {
     if (!addingRemovingNodes_)
     if (!addingRemovingNodes_)
         return;
         return;
 
 
+    assert(curSelEditOp_);
+
     Node* node = static_cast<Node*>(eventData[NodeAdded::P_NODE].GetPtr());
     Node* node = static_cast<Node*>(eventData[NodeAdded::P_NODE].GetPtr());
     Node* parent = static_cast<Node*>(eventData[NodeAdded::P_PARENT].GetPtr());
     Node* parent = static_cast<Node*>(eventData[NodeAdded::P_PARENT].GetPtr());
 
 
     curSelEditOp_->NodeAdded(node, parent);
     curSelEditOp_->NodeAdded(node, parent);
 }
 }
 
 
-void SceneEditHistory::HandleNodeRemoved(StringHash eventType, VariantMap& eventData)
+void SceneEditHistory::HandleSceneEditNodeRemoved(StringHash eventType, VariantMap& eventData)
 {
 {
     if (!addingRemovingNodes_)
     if (!addingRemovingNodes_)
         return;
         return;
 
 
+    assert(curSelEditOp_);
+
     Node* node = static_cast<Node*>(eventData[NodeAdded::P_NODE].GetPtr());
     Node* node = static_cast<Node*>(eventData[NodeAdded::P_NODE].GetPtr());
     Node* parent = static_cast<Node*>(eventData[NodeAdded::P_PARENT].GetPtr());
     Node* parent = static_cast<Node*>(eventData[NodeAdded::P_PARENT].GetPtr());
 
 
@@ -110,7 +114,7 @@ void SceneEditHistory::BeginSelectionEdit()
     if (!nodes.Size())
     if (!nodes.Size())
         return;
         return;
 
 
-    curSelEditOp_ = new SelectionEditOp();
+    curSelEditOp_ = new SelectionEditOp(sceneEditor_->GetScene());
     curSelEditOp_->SetNodes(nodes);
     curSelEditOp_->SetNodes(nodes);
 }
 }
 
 
@@ -146,6 +150,7 @@ void SceneEditHistory::Undo()
     undoHistory_.Pop();
     undoHistory_.Pop();
 
 
     op->Undo();
     op->Undo();
+    sceneEditor_->GetScene()->SendEvent(E_SCENEEDITSCENEMODIFIED);
 
 
     redoHistory_.Push(op);
     redoHistory_.Push(op);
 
 
@@ -168,6 +173,7 @@ void SceneEditHistory::Redo()
     redoHistory_.Pop();
     redoHistory_.Pop();
 
 
     op->Redo();
     op->Redo();
+    sceneEditor_->GetScene()->SendEvent(E_SCENEEDITSCENEMODIFIED);
 
 
     undoHistory_.Push(op);
     undoHistory_.Push(op);
 
 

+ 2 - 2
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditHistory.h

@@ -43,8 +43,8 @@ private:
     void HandleSceneEditBegin(StringHash eventType, VariantMap& eventData);
     void HandleSceneEditBegin(StringHash eventType, VariantMap& eventData);
     void HandleSceneEditEnd(StringHash eventType, VariantMap& eventData);
     void HandleSceneEditEnd(StringHash eventType, VariantMap& eventData);
     void HandleSceneEditAddRemoveNodes(StringHash eventType, VariantMap& eventData);
     void HandleSceneEditAddRemoveNodes(StringHash eventType, VariantMap& eventData);
-    void HandleNodeAdded(StringHash eventType, VariantMap& eventData);
-    void HandleNodeRemoved(StringHash eventType, VariantMap& eventData);
+    void HandleSceneEditNodeAdded(StringHash eventType, VariantMap& eventData);
+    void HandleSceneEditNodeRemoved(StringHash eventType, VariantMap& eventData);
 
 
     void AddUndoOp(SelectionEditOp* op);
     void AddUndoOp(SelectionEditOp* op);
 
 

+ 44 - 3
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditOp.cpp

@@ -10,7 +10,7 @@
 namespace AtomicEditor
 namespace AtomicEditor
 {
 {
 
 
-SelectionEditOp::SelectionEditOp() : SceneEditOp(SCENEEDIT_SELECTION)
+SelectionEditOp::SelectionEditOp(Scene *scene) : SceneEditOp(scene, SCENEEDIT_SELECTION)
 {
 {
 }
 }
 
 
@@ -180,9 +180,28 @@ bool SelectionEditOp::Undo()
 
 
         if (node->GetParent() != enode->parentBegin_)
         if (node->GetParent() != enode->parentBegin_)
         {
         {
-            node->Remove();
             if(enode->parentBegin_.NotNull())
             if(enode->parentBegin_.NotNull())
+            {
+                node->Remove();
                 enode->parentBegin_->AddChild(node);
                 enode->parentBegin_->AddChild(node);
+
+                VariantMap nodeAddedEventData;
+                nodeAddedEventData[SceneEditNodeAdded::P_NODE] = node;
+                nodeAddedEventData[SceneEditNodeAdded::P_PARENT] = enode->parentBegin_;
+                nodeAddedEventData[SceneEditNodeAdded::P_SCENE] = scene_;
+                scene_->SendEvent(E_SCENEEDITNODEADDED, nodeAddedEventData);
+
+            }
+            else
+            {
+                VariantMap nodeRemovedEventData;
+                nodeRemovedEventData[SceneEditNodeRemoved::P_NODE] = node;
+                nodeRemovedEventData[SceneEditNodeRemoved::P_PARENT] =  enode->parentEnd_;
+                nodeRemovedEventData[SceneEditNodeRemoved::P_SCENE] = scene_;
+                scene_->SendEvent(E_SCENEEDITNODEREMOVED, nodeRemovedEventData);
+                node->Remove();
+            }
+
         }
         }
 
 
         for (unsigned j = 0; j < enode->components_.Size(); j++)
         for (unsigned j = 0; j < enode->components_.Size(); j++)
@@ -247,9 +266,31 @@ bool SelectionEditOp::Redo()
 
 
         if (node->GetParent() != enode->parentEnd_)
         if (node->GetParent() != enode->parentEnd_)
         {
         {
-            node->Remove();
+
+
+
             if(enode->parentEnd_.NotNull())
             if(enode->parentEnd_.NotNull())
+            {
+                node->Remove();
                 enode->parentEnd_->AddChild(node);
                 enode->parentEnd_->AddChild(node);
+
+                VariantMap nodeAddedEventData;
+                nodeAddedEventData[SceneEditNodeAdded::P_NODE] = node;
+                nodeAddedEventData[SceneEditNodeAdded::P_PARENT] = enode->parentEnd_;
+                nodeAddedEventData[SceneEditNodeAdded::P_SCENE] = scene_;
+                scene_->SendEvent(E_SCENEEDITNODEADDED, nodeAddedEventData);
+
+            }
+            else
+            {
+                VariantMap nodeRemovedEventData;
+                nodeRemovedEventData[SceneEditNodeRemoved::P_NODE] = node;
+                nodeRemovedEventData[SceneEditNodeRemoved::P_PARENT] = enode->parentBegin_;
+                nodeRemovedEventData[SceneEditNodeRemoved::P_SCENE] = scene_;
+                scene_->SendEvent(E_SCENEEDITNODEREMOVED, nodeRemovedEventData);
+                node->Remove();
+            }
+
         }
         }
 
 
         for (unsigned j = 0; j < enode->components_.Size(); j++)
         for (unsigned j = 0; j < enode->components_.Size(); j++)

+ 3 - 2
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditOp.h

@@ -32,7 +32,7 @@ class SceneEditOp
 
 
 public:
 public:
 
 
-    SceneEditOp(SceneEditType type) { type_ = type; }
+    SceneEditOp(Scene* scene, SceneEditType type) { type_ = type; scene_ = scene;}
     virtual ~SceneEditOp() { }
     virtual ~SceneEditOp() { }
 
 
     virtual bool Undo() = 0;
     virtual bool Undo() = 0;
@@ -50,6 +50,7 @@ public:
         return true;
         return true;
     }
     }
 
 
+    SharedPtr<Scene> scene_;
     SceneEditType type_;
     SceneEditType type_;
 
 
 };
 };
@@ -59,7 +60,7 @@ class SelectionEditOp : public SceneEditOp
 
 
 public:
 public:
 
 
-    SelectionEditOp();
+    SelectionEditOp(Scene* scene);
     ~SelectionEditOp();
     ~SelectionEditOp();
 
 
     bool Undo();
     bool Undo();

+ 42 - 0
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3D.cpp

@@ -294,6 +294,48 @@ bool SceneEditor3D::Save()
 
 
 }
 }
 
 
+void SceneEditor3D::RegisterNode(Node * node)
+{
+    VariantMap eventData;
+    eventData[SceneEditAddRemoveNodes::P_END] = false;
+    scene_->SendEvent(E_SCENEEDITADDREMOVENODES, eventData);
+
+    // generate scene edit event
+
+    VariantMap nodeAddedEventData;
+    nodeAddedEventData[SceneEditNodeAdded::P_NODE] = node;
+    nodeAddedEventData[SceneEditNodeAdded::P_PARENT] = node->GetParent();
+    nodeAddedEventData[SceneEditNodeAdded::P_SCENE] = scene_;
+    scene_->SendEvent(E_SCENEEDITNODEADDED, nodeAddedEventData);
+
+    eventData[SceneEditAddRemoveNodes::P_END] = true;
+    scene_->SendEvent(E_SCENEEDITADDREMOVENODES, eventData);
+
+}
+
+void SceneEditor3D::RegisterNodes(const PODVector<Node*>& nodes)
+{
+    VariantMap eventData;
+    eventData[SceneEditAddRemoveNodes::P_END] = false;
+    scene_->SendEvent(E_SCENEEDITADDREMOVENODES, eventData);
+
+    // generate scene edit event
+
+    for (unsigned i = 0; i < nodes.Size(); i++)
+    {
+        Node* node = nodes[i];
+        VariantMap nodeAddedEventData;
+        nodeAddedEventData[SceneEditNodeAdded::P_NODE] = node;
+        nodeAddedEventData[SceneEditNodeAdded::P_PARENT] = node->GetParent();
+        nodeAddedEventData[SceneEditNodeAdded::P_SCENE] = scene_;
+        scene_->SendEvent(E_SCENEEDITNODEADDED, nodeAddedEventData);
+    }
+
+    eventData[SceneEditAddRemoveNodes::P_END] = true;
+    scene_->SendEvent(E_SCENEEDITADDREMOVENODES, eventData);
+
+}
+
 void SceneEditor3D::Undo()
 void SceneEditor3D::Undo()
 {
 {
     editHistory_->Undo();
     editHistory_->Undo();

+ 3 - 0
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3D.h

@@ -57,6 +57,9 @@ public:
     SceneSelection* GetSelection() { return selection_; }
     SceneSelection* GetSelection() { return selection_; }
     SceneView3D* GetSceneView3D() { return sceneView_; }
     SceneView3D* GetSceneView3D() { return sceneView_; }
 
 
+    void RegisterNode(Node* node);
+    void RegisterNodes(const PODVector<Node*>& nodes);
+
     Scene* GetScene() { return scene_; }
     Scene* GetScene() { return scene_; }
     Gizmo3D* GetGizmo() { return gizmo3D_; }
     Gizmo3D* GetGizmo() { return gizmo3D_; }
 
 

+ 17 - 0
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3DEvents.h

@@ -53,6 +53,23 @@ EVENT(E_SCENEEDITSTATECHANGE, SceneEditStateChange)
     PARAM(P_SERIALIZABLE, Serializable);     // Serializable
     PARAM(P_SERIALIZABLE, Serializable);     // Serializable
 }
 }
 
 
+/// A child node has been added to a parent node.
+EVENT(E_SCENEEDITNODEADDED, SceneEditNodeAdded)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_PARENT, Parent);                // Node pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+}
+
+/// A child node is about to be removed from a parent node.
+EVENT(E_SCENEEDITNODEREMOVED, SceneEditNodeRemoved)
+{
+    PARAM(P_SCENE, Scene);                  // Scene pointer
+    PARAM(P_PARENT, Parent);                // Node pointer
+    PARAM(P_NODE, Node);                    // Node pointer
+}
+
+
 EVENT(E_SCENEEDITADDREMOVENODES, SceneEditAddRemoveNodes)
 EVENT(E_SCENEEDITADDREMOVENODES, SceneEditAddRemoveNodes)
 {
 {
     PARAM(P_END, End);       // bool
     PARAM(P_END, End);       // bool

+ 92 - 22
Source/AtomicEditor/Editors/SceneEditor3D/SceneSelection.cpp

@@ -64,7 +64,7 @@ void SceneSelection::AddNode(Node* node, bool clear)
     }
     }
 }
 }
 
 
-void SceneSelection::RemoveNode(Node* node)
+void SceneSelection::RemoveNode(Node* node, bool quiet)
 {    
 {    
     SharedPtr<Node> _node(node);
     SharedPtr<Node> _node(node);
     if(!nodes_.Contains(_node))
     if(!nodes_.Contains(_node))
@@ -72,14 +72,15 @@ void SceneSelection::RemoveNode(Node* node)
 
 
     nodes_.Remove(_node);
     nodes_.Remove(_node);
 
 
+    if (quiet)
+        return;
+
     VariantMap eventData;
     VariantMap eventData;
     eventData[SceneNodeSelected::P_SCENE] = scene_;
     eventData[SceneNodeSelected::P_SCENE] = scene_;
     eventData[SceneNodeSelected::P_NODE] = node;
     eventData[SceneNodeSelected::P_NODE] = node;
     eventData[SceneNodeSelected::P_SELECTED] = false;    
     eventData[SceneNodeSelected::P_SELECTED] = false;    
     scene_->SendEvent(E_SCENENODESELECTED, eventData);
     scene_->SendEvent(E_SCENENODESELECTED, eventData);
 
 
-
-
 }
 }
 
 
 void SceneSelection::Clear()
 void SceneSelection::Clear()
@@ -95,37 +96,98 @@ void SceneSelection::Clear()
 
 
 void SceneSelection::Paste()
 void SceneSelection::Paste()
 {
 {
-    /*
-    if (clipboardNode_.NotNull() && selectedNode_.NotNull())
-    {
-        SharedPtr<Node> pasteNode(clipboardNode_->Clone());
 
 
-        VariantMap eventData;
-        eventData[EditorActiveNodeChange::P_NODE] = pasteNode;
-        SendEvent(E_EDITORACTIVENODECHANGE, eventData);
+    if (!clipBoardNodes_.Size())
+        return;
+
+    Vector<SharedPtr<Node>> newClipBoardNodes;
+
+    Node* parent = scene_;
+
+    if (nodes_.Size() == 1)
+        parent = nodes_[0];
+
+    Clear();
+
+    VariantMap eventData;
+    eventData[SceneEditAddRemoveNodes::P_END] = false;
+    scene_->SendEvent(E_SCENEEDITADDREMOVENODES, eventData);
+
+    for (unsigned i = 0; i < clipBoardNodes_.Size(); i++)
+    {
+        // Nodes must have a parent to clone, so first parent
+        Node* clipNode = clipBoardNodes_[i];
+
+        Matrix3x4 transform = clipNode->GetWorldTransform();
+
+        parent->AddChild(clipNode);
+        clipNode->SetWorldTransform(transform.Translation(), transform.Rotation(), transform.Scale());
+
+        // clone
+        newClipBoardNodes.Push(SharedPtr<Node>(clipNode->Clone()));
+        // remove from parent
+        newClipBoardNodes.Back()->Remove();
+        newClipBoardNodes.Back()->SetWorldTransform(transform.Translation(), transform.Rotation(), transform.Scale());
+
+        // generate scene edit event
+        VariantMap nodeAddedEventData;
+        nodeAddedEventData[SceneEditNodeAdded::P_NODE] = clipNode;
+        nodeAddedEventData[SceneEditNodeAdded::P_PARENT] = parent;
+        nodeAddedEventData[SceneEditNodeAdded::P_SCENE] = scene_;
+        scene_->SendEvent(E_SCENEEDITNODEADDED, nodeAddedEventData);
+    }
 
 
-        VariantMap editData;
-        editData[SceneEditNodeAddedRemoved::P_SCENE] = scene_;
-        editData[SceneEditNodeAddedRemoved::P_NODE] = pasteNode;
-        editData[SceneEditNodeAddedRemoved::P_ADDED] = true;
+    eventData[SceneEditAddRemoveNodes::P_END] = true;
+    scene_->SendEvent(E_SCENEEDITADDREMOVENODES, eventData);
 
 
-        scene_->SendEvent(E_SCENEEDITNODEADDEDREMOVED, editData);
+    for (unsigned i = 0; i < clipBoardNodes_.Size(); i++)
+    {
+        AddNode(clipBoardNodes_[i], false);
     }
     }
-    */
+
+    clipBoardNodes_ = newClipBoardNodes;
 
 
 }
 }
 
 
 
 
 void SceneSelection::Copy()
 void SceneSelection::Copy()
 {
 {
-    /*
+    clipBoardNodes_.Clear();
 
 
-    if (selectedNode_.NotNull())
+    for (unsigned i = 0; i < nodes_.Size(); i++)
     {
     {
-        clipboardNode_ = selectedNode_;
-    }
+        Node* node = nodes_[i];
+
+        if (!node->GetParent())
+        {
+            clipBoardNodes_.Clear();
+            LOGERROR("SceneSelection::Copy - unable to copy node to clipboard (no parent)");
+            return;
+        }
+
+        for (unsigned j = 0; j < nodes_.Size(); j++)
+        {
+            if ( i == j )
+                continue;
+
+            PODVector<Node*> children;
+            nodes_[j]->GetChildren(children, true);
+            if (children.Contains(node))
+            {
+                node = 0;
+                break;
+            }
+
+        }
+
+        if (node)
+        {
+            SharedPtr<Node> clipNode(node->Clone());
+            clipNode->Remove();
+            clipBoardNodes_.Push(clipNode);
+        }
 
 
-    */
+    }
 }
 }
 
 
 void SceneSelection::Delete()
 void SceneSelection::Delete()
@@ -141,7 +203,15 @@ void SceneSelection::Delete()
 
 
     for (unsigned i = 0; i < nodes.Size(); i++)
     for (unsigned i = 0; i < nodes.Size(); i++)
     {
     {
+        // generate scene edit event
+        VariantMap nodeRemovedEventData;
+        nodeRemovedEventData[SceneEditNodeAdded::P_NODE] = nodes[i];
+        nodeRemovedEventData[SceneEditNodeAdded::P_PARENT] = nodes[i]->GetParent();
+        nodeRemovedEventData[SceneEditNodeAdded::P_SCENE] = scene_;
+        scene_->SendEvent(E_SCENEEDITNODEREMOVED, nodeRemovedEventData);
+
         nodes[i]->Remove();
         nodes[i]->Remove();
+
     }
     }
 
 
     eventData[SceneEditAddRemoveNodes::P_END] = true;
     eventData[SceneEditAddRemoveNodes::P_END] = true;
@@ -202,7 +272,7 @@ void SceneSelection::DrawNodeDebug(Node* node, DebugRenderer* debug, bool drawNo
 void SceneSelection::HandleNodeRemoved(StringHash eventType, VariantMap& eventData)
 void SceneSelection::HandleNodeRemoved(StringHash eventType, VariantMap& eventData)
 {
 {
     Node* node = (Node*) (eventData[NodeRemoved::P_NODE].GetPtr());
     Node* node = (Node*) (eventData[NodeRemoved::P_NODE].GetPtr());
-    RemoveNode(node);
+    RemoveNode(node, true);
 }
 }
 
 
 
 

+ 3 - 1
Source/AtomicEditor/Editors/SceneEditor3D/SceneSelection.h

@@ -39,7 +39,7 @@ public:
 
 
     /// Add a node to the selection, if clear specified removes current nodes first
     /// Add a node to the selection, if clear specified removes current nodes first
     void AddNode(Node* node, bool clear = false);
     void AddNode(Node* node, bool clear = false);
-    void RemoveNode(Node* node);
+    void RemoveNode(Node* node, bool quiet = false);
     void GetBounds(BoundingBox& bbox);
     void GetBounds(BoundingBox& bbox);
 
 
     bool Contains(Node* node);
     bool Contains(Node* node);
@@ -58,6 +58,8 @@ private:
 
 
     WeakPtr<SceneEditor3D> sceneEditor3D_;
     WeakPtr<SceneEditor3D> sceneEditor3D_;
     WeakPtr<Scene> scene_;
     WeakPtr<Scene> scene_;
+
+    Vector<SharedPtr<Node>> clipBoardNodes_;
     Vector<SharedPtr<Node>> nodes_;
     Vector<SharedPtr<Node>> nodes_;
 
 
 };
 };

+ 6 - 14
Source/AtomicEditor/Editors/SceneEditor3D/SceneView3D.cpp

@@ -145,7 +145,7 @@ void SceneView3D::Disable()
 bool SceneView3D::GetOrbitting()
 bool SceneView3D::GetOrbitting()
 {
 {
     Input* input = GetSubsystem<Input>();
     Input* input = GetSubsystem<Input>();
-    return framedNode_.NotNull() && MouseInView() && input->GetKeyDown(KEY_ALT) && input->GetMouseButtonDown(MOUSEB_LEFT);
+    return framedBBox_.defined_ && MouseInView() && input->GetKeyDown(KEY_ALT) && input->GetMouseButtonDown(MOUSEB_LEFT);
 }
 }
 
 
 bool SceneView3D::GetZooming()
 bool SceneView3D::GetZooming()
@@ -601,18 +601,10 @@ void SceneView3D::HandleDragEnded(StringHash eventType, VariantMap& eventData)
 
 
     if (dragNode_.NotNull())
     if (dragNode_.NotNull())
     {
     {
-        /*
-        VariantMap neventData;
-        neventData[EditorActiveNodeChange::P_NODE] = dragNode_;
-        SendEvent(E_EDITORACTIVENODECHANGE, neventData);
-
-        VariantMap editData;
-        editData[SceneEditNodeAddedRemoved::P_SCENE] = scene_;
-        editData[SceneEditNodeAddedRemoved::P_NODE] = dragNode_;
-        editData[SceneEditNodeAddedRemoved::P_ADDED] = true;
-        scene_->SendEvent(E_SCENEEDITNODEADDEDREMOVED, editData);
-        */
-
+        PODVector<Node*> nodes;
+        nodes.Push(dragNode_);
+        sceneEditor_->RegisterNodes(nodes);
+        sceneEditor_->GetSelection()->AddNode(dragNode_, true);
     }
     }
 
 
     if (dragObject && dragObject->GetObject()->GetType() == ToolCore::Asset::GetTypeStatic())
     if (dragObject && dragObject->GetObject()->GetType() == ToolCore::Asset::GetTypeStatic())
@@ -668,7 +660,7 @@ void SceneView3D::FrameSelection()
     if (sphere.radius_ < .01f || sphere.radius_ > 512)
     if (sphere.radius_ < .01f || sphere.radius_ > 512)
         return;
         return;
 
 
-    //framedNode_ = selectedNode_;
+    framedBBox_ = bbox;
     cameraMoveStart_ = cameraNode_->GetWorldPosition();
     cameraMoveStart_ = cameraNode_->GetWorldPosition();
     cameraMoveTarget_ = bbox.Center() - (cameraNode_->GetWorldDirection() * sphere.radius_ * 3);
     cameraMoveTarget_ = bbox.Center() - (cameraNode_->GetWorldDirection() * sphere.radius_ * 3);
     cameraMoveTime_ = 0.0f;
     cameraMoveTime_ = 0.0f;

+ 1 - 1
Source/AtomicEditor/Editors/SceneEditor3D/SceneView3D.h

@@ -98,7 +98,7 @@ private:
     SharedPtr<DebugRenderer> debugRenderer_;
     SharedPtr<DebugRenderer> debugRenderer_;
     SharedPtr<Octree> octree_;
     SharedPtr<Octree> octree_;
 
 
-    WeakPtr<Node> framedNode_;
+    BoundingBox framedBBox_;
 
 
     SharedPtr<Scene> preloadResourceScene_;
     SharedPtr<Scene> preloadResourceScene_;
     String dragAssetGUID_;
     String dragAssetGUID_;

+ 19 - 29
Source/ThirdParty/TurboBadger/tb_select.cpp

@@ -187,6 +187,13 @@ void TBSelectList::ValidateList()
 
 
 	// FIX: Should not scroll just because we update the list. Only automatically first time!
 	// FIX: Should not scroll just because we update the list. Only automatically first time!
 	m_scroll_to_current = true;
 	m_scroll_to_current = true;
+
+    TBWidgetEvent ev(EVENT_TYPE_CUSTOM);
+    // TBIDC does not register the string with the UI system
+    TBID refid("select_list_validation_end");
+    ev.ref_id = refid;
+    InvokeEvent(ev);
+
 }
 }
 
 
 TBWidget *TBSelectList::CreateAndAddItemAfter(int index, TBWidget *reference)
 TBWidget *TBSelectList::CreateAndAddItemAfter(int index, TBWidget *reference)
@@ -242,20 +249,10 @@ TBID TBSelectList::GetSelectedItemID()
 
 
 void TBSelectList::SelectItem(int index, bool selected)
 void TBSelectList::SelectItem(int index, bool selected)
 {
 {
-	if (TBWidget *widget = GetItemWidget(index))
-    {
-        bool changed = widget->GetState(WIDGET_STATE_SELECTED) != selected;
-		widget->SetState(WIDGET_STATE_SELECTED, selected);
-        if (changed)
-        {
-            TBWidgetEvent ev(EVENT_TYPE_CUSTOM);
-            // TBIDC does not register the string with the UI system
-            TBID refid("select_list_selection_changed");
-            ev.ref_id = refid;
-            // forward to delegate
-            TBWidget::OnEvent(ev);
-        }
-    }
+    //if (TBWidget *widget = GetItemWidget(index))
+    //{
+    //    widget->SetState(WIDGET_STATE_SELECTED, selected);
+    //}
 }
 }
 
 
 TBWidget *TBSelectList::GetItemWidget(int index)
 TBWidget *TBSelectList::GetItemWidget(int index)
@@ -308,22 +305,15 @@ bool TBSelectList::OnEvent(const TBWidgetEvent &ev)
 
 
 		int index = ev.target->data.GetInt();
 		int index = ev.target->data.GetInt();
 
 
-        if (ev.modifierkeys & TB_SHIFT || ev.modifierkeys & TB_CTRL || ev.modifierkeys & TB_SUPER)
-        {
-            if (GetItemSelected(index))
-            {
-                SelectItem(index, false);
-            }
-            else
-            {
-               SetValue(index);
-               SelectItem(index, true);
-            }
-        }
-        else
+        if (TBWidget *widget = GetItemWidget(index))
         {
         {
-            SelectAllItems(false);
-            SetValue(index);
+            TBWidgetEvent change_ev(EVENT_TYPE_CUSTOM);
+            // TBIDC does not register the string with the UI system
+            TBID refid("select_list_selection_changed");
+            change_ev.ref_id = refid;
+            change_ev.modifierkeys = ev.modifierkeys;
+            // forward to delegate
+            widget->InvokeEvent(change_ev);
         }
         }
 
 
 		// If we're still around, invoke the click event too.
 		// If we're still around, invoke the click event too.