瀏覽代碼

Working TreeView for GuiEditor

This update includes a mostly working TreeView control for the GuiEditor.
Peter Robinson 2 年之前
父節點
當前提交
18fc3dfad5

+ 3 - 2
editor/GuiEditor/GuiEditor.cs

@@ -27,6 +27,7 @@ function GuiEditor::create( %this )
 	exec("./scripts/GuiEditorControlListBox.cs");
 	exec("./scripts/GuiEditorControlListBox.cs");
 	exec("./scripts/GuiEditorInspectorWindow.cs");
 	exec("./scripts/GuiEditorInspectorWindow.cs");
 	exec("./scripts/GuiEditorExplorerWindow.cs");
 	exec("./scripts/GuiEditorExplorerWindow.cs");
+    exec("./scripts/GuiEditorExplorerTree.cs");
 
 
 	%this.guiPage = EditorCore.RegisterEditor("Gui Editor", %this);
 	%this.guiPage = EditorCore.RegisterEditor("Gui Editor", %this);
 
 
@@ -112,14 +113,14 @@ function GuiEditor::create( %this )
         HorizSizing = "right";
         HorizSizing = "right";
         VertSizing = "bottom";
         VertSizing = "bottom";
         Position = "610 0";
         Position = "610 0";
-        Extent = "250  380";
+        Extent = "400  380";
         MinExtent = "100 100";
         MinExtent = "100 100";
         text = "Explorer";
         text = "Explorer";
         canMove = true;
         canMove = true;
         canClose = false;
         canClose = false;
         canMinimize = true;
         canMinimize = true;
         canMaximize = false;
         canMaximize = false;
-        resizeWidth = false;
+        resizeWidth = true;
         resizeHeight = true;
         resizeHeight = true;
     };
     };
     ThemeManager.setProfile(%this.explorerWindow, "windowProfile");
     ThemeManager.setProfile(%this.explorerWindow, "windowProfile");

+ 20 - 7
editor/GuiEditor/scripts/GuiEditorBrain.cs

@@ -7,7 +7,7 @@ function GuiEditorBrain::onAdd(%this)
 
 
 function GuiEditorBrain::onControlDragged(%this, %payload, %position)
 function GuiEditorBrain::onControlDragged(%this, %payload, %position)
 {
 {
-	%pos = VectorSub(%position, %this.getGlobalPosition());
+	%pos = VectorSub(%position, %this.getLocalPosition());
 	%x = getWord(%pos, 0);
 	%x = getWord(%pos, 0);
 	%y = getWord(%pos, 1);
 	%y = getWord(%pos, 1);
 	%target = GuiEditor.content.findHitControl(%x, %y);
 	%target = GuiEditor.content.findHitControl(%x, %y);
@@ -29,29 +29,42 @@ function GuiEditorBrain::onControlDropped(%this, %payload, %position)
    %x = getWord(%pos, 0);
    %x = getWord(%pos, 0);
    %y = getWord(%pos, 1);
    %y = getWord(%pos, 1);
 
 
-   if(%x > %this.root.extent.x || %y > %this.root.extent.y)
+   if(%x < %this.root.position.x || %y < %this.root.poisition.y || 
+    %x > (%this.root.extent.x + %this.root.position.x) || %y > (%this.root.extent.y + %this.root.position.y))
    {
    {
       messageBox("Error", "Cannot add a control outside the root gui element!");
       messageBox("Error", "Cannot add a control outside the root gui element!");
       return;
       return;
    }
    }
 
 
    %this.addNewCtrl(%payload);
    %this.addNewCtrl(%payload);
-
    %payload.setPositionGlobal(%x, %y);
    %payload.setPositionGlobal(%x, %y);
    %this.setFirstResponder();
    %this.setFirstResponder();
+   %this.postEvent("AddControl", %payload);
     %this.postEvent("Inspect", %payload);
     %this.postEvent("Inspect", %payload);
+   %this.schedule(100, "finishControlDropped", %payload, %x, %y);
+}
+
+function GuiEditorBrain::finishControlDropped(%this, %payload, %x, %y)
+{
+   %payload.setPositionGlobal(%x, %y);
+}
+
+function GuiEditorBrain::onInspect(%this, %ctrl)
+{
+    %this.clearSelection();
+	%this.select(%ctrl);
 }
 }
 
 
 function GuiEditorBrain::onSelect(%this, %ctrl)
 function GuiEditorBrain::onSelect(%this, %ctrl)
 {
 {
-	GuiEditorBrain.clearSelection();
-	GuiEditorBrain.select(%ctrl);
+	%this.clearSelection();
+	%this.select(%ctrl);
     %this.postEvent("Inspect", %ctrl);
     %this.postEvent("Inspect", %ctrl);
 }
 }
 
 
 function GuiEditorBrain::onClearSelected(%this)
 function GuiEditorBrain::onClearSelected(%this)
 {
 {
-    %this.postEvent("ClearInspect");
+    %this.postEvent("ClearInspectAll");
 }
 }
 
 
 function GuiEditorBrain::onSelectionParentChange(%this)
 function GuiEditorBrain::onSelectionParentChange(%this)
@@ -60,7 +73,7 @@ function GuiEditorBrain::onSelectionParentChange(%this)
 
 
 function GuiEditorBrain::onDelete(%this)
 function GuiEditorBrain::onDelete(%this)
 {
 {
-	%this.postEvent("ClearInspect", %ctrl);
+	%this.postEvent("ObjectRemoved", %ctrl);
 }
 }
 
 
 function GuiEditorBrain::onAddSelected(%this,%ctrl)
 function GuiEditorBrain::onAddSelected(%this,%ctrl)

+ 11 - 0
editor/GuiEditor/scripts/GuiEditorExplorerTree.cs

@@ -0,0 +1,11 @@
+
+function GuiEditorExplorerTree::onAdd(%this)
+{
+    %this.addListener(GuiEditor.brain);
+    %this.addListener(GuiEditor.inspectorWindow);
+}
+
+function GuiEditorExplorerTree::onClick(%this, %target)
+{
+    %this.postEvent("Inspect", %target);
+}

+ 36 - 2
editor/GuiEditor/scripts/GuiEditorExplorerWindow.cs

@@ -6,7 +6,7 @@ function GuiEditorExplorerWindow::onAdd(%this)
 		HorizSizing="width";
 		HorizSizing="width";
 		VertSizing="height";
 		VertSizing="height";
 		Position="0 0";
 		Position="0 0";
-		Extent="242 355";
+		Extent="392 355";
 		hScrollBar="alwaysOff";
 		hScrollBar="alwaysOff";
 		vScrollBar="alwaysOn";
 		vScrollBar="alwaysOn";
 		constantThumbHeight="0";
 		constantThumbHeight="0";
@@ -21,16 +21,50 @@ function GuiEditorExplorerWindow::onAdd(%this)
 
 
     %this.tree = new GuiTreeViewCtrl()
     %this.tree = new GuiTreeViewCtrl()
 	{
 	{
+		class="GuiEditorExplorerTree";
 		HorizSizing="width";
 		HorizSizing="width";
 		VertSizing="height";
 		VertSizing="height";
 		Position="0 0";
 		Position="0 0";
 		Extent="228 355";
 		Extent="228 355";
 	};
 	};
-	ThemeManager.setProfile(%this.tree, "panelProfile");
+	ThemeManager.setProfile(%this.tree, "listboxProfile");
 	%this.scroller.add(%this.tree);
 	%this.scroller.add(%this.tree);
 }
 }
 
 
 function GuiEditorExplorerWindow::open(%this, %object)
 function GuiEditorExplorerWindow::open(%this, %object)
 {
 {
     %this.tree.open(%object);
     %this.tree.open(%object);
+}
+
+function GuiEditorExplorerWindow::onInspect(%this, %ctrl)
+{
+	%index = %this.tree.findItemID(%ctrl.getID());
+	%this.tree.clearSelection();
+	%this.tree.setSelected(%index, true);
+}
+
+function GuiEditorExplorerWindow::onAlsoInspect(%this, %ctrl)
+{
+	%this.tree.setSelected(%ctrl, true);
+}
+
+function GuiEditorExplorerWindow::onClearInspect(%this, %ctrl)
+{
+	%this.tree.setSelected(%ctrl, false);
+}
+
+function GuiEditorExplorerWindow::onClearInspectAll(%this)
+{
+	%this.tree.clearSelection();
+}
+
+function GuiEditorExplorerWindow::onObjectRemoved(%this, %ctrl)
+{
+	%index = %this.tree.findItemID(%ctrl.getID());
+	%this.tree.deleteItem(%index);
+}
+
+function GuiEditorExplorerWindow::onAddControl(%this, %ctrl)
+{
+	%this.tree.refresh();
 }
 }

+ 2 - 0
editor/GuiEditor/scripts/GuiEditorInspectorWindow.cs

@@ -50,6 +50,8 @@ function GuiEditorInspectorWindow::onAdd(%this)
 	%this.scroller.add(%this.inspector);
 	%this.scroller.add(%this.inspector);
 
 
     %this.inspectList = new SimSet();
     %this.inspectList = new SimSet();
+
+	%this.inspector.addHiddenField("isContainer");
 }
 }
 
 
 function GuiEditorInspectorWindow::onRemove(%this)
 function GuiEditorInspectorWindow::onRemove(%this)

+ 1 - 0
engine/compilers/VisualStudio 2022/Torque 2D.vcxproj

@@ -1146,6 +1146,7 @@
     <ClInclude Include="..\..\source\gui\guiTextEditCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiTextEditCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiTextEditSliderCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiTextEditSliderCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiTreeViewCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiTreeViewCtrl.h" />
+    <ClInclude Include="..\..\source\gui\guiTreeViewCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiTypes.h" />
     <ClInclude Include="..\..\source\gui\guiTypes.h" />
     <ClInclude Include="..\..\source\gui\language\lang.h" />
     <ClInclude Include="..\..\source\gui\language\lang.h" />
     <ClInclude Include="..\..\source\gui\messageVector.h" />
     <ClInclude Include="..\..\source\gui\messageVector.h" />

+ 9 - 6
engine/compilers/VisualStudio 2022/Torque 2D.vcxproj.filters

@@ -765,9 +765,6 @@
     <ClCompile Include="..\..\source\gui\guiTextEditSliderCtrl.cc">
     <ClCompile Include="..\..\source\gui\guiTextEditSliderCtrl.cc">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="..\..\source\gui\guiTreeViewCtrl.cc">
-      <Filter>gui</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\gui\guiTypes.cc">
     <ClCompile Include="..\..\source\gui\guiTypes.cc">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClCompile>
     </ClCompile>
@@ -1342,6 +1339,9 @@
     <ClCompile Include="..\..\source\math\noise\RandomNumberGenerator.cc">
     <ClCompile Include="..\..\source\math\noise\RandomNumberGenerator.cc">
       <Filter>math\noise</Filter>
       <Filter>math\noise</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="..\..\source\gui\guiTreeViewCtrl.cc">
+      <Filter>gui</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\source\audio\audio.h">
     <ClInclude Include="..\..\source\audio\audio.h">
@@ -1968,9 +1968,6 @@
     <ClInclude Include="..\..\source\gui\guiTextEditSliderCtrl.h">
     <ClInclude Include="..\..\source\gui\guiTextEditSliderCtrl.h">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="..\..\source\gui\guiTreeViewCtrl.h">
-      <Filter>gui</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\gui\guiTypes.h">
     <ClInclude Include="..\..\source\gui\guiTypes.h">
       <Filter>gui</Filter>
       <Filter>gui</Filter>
     </ClInclude>
     </ClInclude>
@@ -3073,6 +3070,12 @@
     <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator_ScriptBinding.h">
     <ClInclude Include="..\..\source\math\noise\RandomNumberGenerator_ScriptBinding.h">
       <Filter>math\noise</Filter>
       <Filter>math\noise</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="..\..\source\gui\guiTreeViewCtrl.h">
+      <Filter>gui</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\source\gui\guiTreeViewCtrl_ScriptBinding.h">
+      <Filter>gui</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Torque 2D.rc" />
     <ResourceCompile Include="Torque 2D.rc" />

+ 1 - 0
engine/source/gui/buttons/guiDropDownCtrl.cc

@@ -74,6 +74,7 @@ GuiDropDownCtrl::GuiDropDownCtrl()
 	mIsOpen = false;
 	mIsOpen = false;
 	mActive = true;
 	mActive = true;
 	mText = StringTable->insert("none");
 	mText = StringTable->insert("none");
+	mIsContainer = false;
 
 
 	setField("profile", "GuiDropDownProfile");
 	setField("profile", "GuiDropDownProfile");
 
 

+ 1 - 0
engine/source/gui/guiColorPicker.cc

@@ -65,6 +65,7 @@ GuiColorPickerCtrl::GuiColorPickerCtrl()
    mSelectorGap = 1;
    mSelectorGap = 1;
    mActionOnMove = false;
    mActionOnMove = false;
    mShowSelector = false;
    mShowSelector = false;
+   mIsContainer = false;
 }
 }
 
 
 //--------------------------------------------------------------------------
 //--------------------------------------------------------------------------

+ 1 - 1
engine/source/gui/guiControl.cc

@@ -120,7 +120,7 @@ GuiControl::GuiControl()
    mTooltip             = StringTable->EmptyString;
    mTooltip             = StringTable->EmptyString;
    mTipHoverTime        = 1000;
    mTipHoverTime        = 1000;
    mTooltipWidth		= 250;
    mTooltipWidth		= 250;
-   mIsContainer         = false;
+   mIsContainer         = true;
    mTextWrap			= false;
    mTextWrap			= false;
    mTextExtend          = false;
    mTextExtend          = false;
    mUseInput            = true;
    mUseInput            = true;

+ 5 - 0
engine/source/gui/guiInputCtrl.cc

@@ -25,6 +25,11 @@
 
 
 IMPLEMENT_CONOBJECT(GuiInputCtrl);
 IMPLEMENT_CONOBJECT(GuiInputCtrl);
 
 
+GuiInputCtrl::GuiInputCtrl()
+{
+	mIsContainer = false;
+}
+
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 bool GuiInputCtrl::onWake()
 bool GuiInputCtrl::onWake()
 {
 {

+ 2 - 0
engine/source/gui/guiInputCtrl.h

@@ -38,6 +38,8 @@ class GuiInputCtrl : public GuiControl
    public:
    public:
       DECLARE_CONOBJECT(GuiInputCtrl);
       DECLARE_CONOBJECT(GuiInputCtrl);
 
 
+	  GuiInputCtrl();
+
       bool onWake();
       bool onWake();
       void onSleep();
       void onSleep();
 
 

+ 97 - 71
engine/source/gui/guiListBoxCtrl.cc

@@ -273,6 +273,10 @@ void GuiListBoxCtrl::setCurSel( S32 index )
    // If index -1 is specified, we clear the selection
    // If index -1 is specified, we clear the selection
    if( index == -1 )
    if( index == -1 )
    {
    {
+		for (auto item : mItems)
+		{
+			item->isSelected = false;
+		}
 	  mSelectedItems.clear();
 	  mSelectedItems.clear();
 	  return;
 	  return;
    }
    }
@@ -471,7 +475,7 @@ S32 GuiListBoxCtrl::insertItem( S32 index, StringTableEntry text, void *itemData
 	  return -1;
 	  return -1;
    }
    }
 
 
-   LBItem *newItem = new LBItem;
+   LBItem *newItem = createItem();
    if( !newItem )
    if( !newItem )
    {
    {
 	  Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
 	  Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
@@ -497,6 +501,16 @@ S32 GuiListBoxCtrl::insertItem( S32 index, StringTableEntry text, void *itemData
    return index;
    return index;
 }
 }
 
 
+GuiListBoxCtrl::LBItem* GuiListBoxCtrl::createItem()
+{
+	LBItem* newItem = new LBItem;
+	if (!newItem)
+	{
+		return nullptr;
+	}
+	return newItem;
+}
+
 S32 GuiListBoxCtrl::insertItemWithColor( S32 index, StringTableEntry text, ColorF color, void *itemData )
 S32 GuiListBoxCtrl::insertItemWithColor( S32 index, StringTableEntry text, ColorF color, void *itemData )
 {
 {
 	if( color == ColorF(-1, -1, -1) )
 	if( color == ColorF(-1, -1, -1) )
@@ -636,7 +650,6 @@ void GuiListBoxCtrl::onRender( Point2I offset, const RectI &updateRect )
 		mItemSize.x = clip.extent.x;
 		mItemSize.x = clip.extent.x;
 	}
 	}
 
 
-
 	for ( S32 i = 0; i < mItems.size(); i++)
 	for ( S32 i = 0; i < mItems.size(); i++)
 	{
 	{
 		// Only render visible items
 		// Only render visible items
@@ -713,19 +726,18 @@ void GuiListBoxCtrl::onTouchDragged(const GuiEvent &event)
 		return;
 		return;
 	}
 	}
 
 
-   Point2I localPoint = globalToLocalCoord(event.mousePoint);
-   S32 itemHit = (localPoint.y < 0) ? -1 : (S32)mFloor((F32)localPoint.y / (F32)mItemSize.y);
+	S32 hitIndex = getHitIndex(event);
 
 
-   if (itemHit >= mItems.size() || itemHit == -1)
+   if (hitIndex >= mItems.size() || hitIndex == -1)
 	   return;
 	   return;
 
 
-   LBItem *hitItem = mItems[itemHit];
+   LBItem *hitItem = mItems[hitIndex];
    if (hitItem == NULL || !hitItem->isActive)
    if (hitItem == NULL || !hitItem->isActive)
 	   return;
 	   return;
 
 
 	if(caller->isMethod("onTouchDragged"))
 	if(caller->isMethod("onTouchDragged"))
 	{
 	{
-		Con::executef(caller, 3, "onTouchDragged", Con::getIntArg(itemHit), hitItem->itemText, hitItem->ID);
+		Con::executef(caller, 3, "onTouchDragged", Con::getIntArg(hitIndex), hitItem->itemText, hitItem->ID);
 	}
 	}
 	else
 	else
 	{
 	{
@@ -744,87 +756,101 @@ void GuiListBoxCtrl::onTouchDown( const GuiEvent &event )
 
 
 	setFirstResponder();
 	setFirstResponder();
 
 
-   Point2I localPoint = globalToLocalCoord(event.mousePoint);
-   S32 itemHit = ( localPoint.y < 0 ) ? -1 : (S32)mFloor( (F32)localPoint.y / (F32)mItemSize.y );
+   S32 hitIndex = getHitIndex(event);
 
 
-   if ( itemHit >= mItems.size() || itemHit == -1 )
+   if ( hitIndex >= mItems.size() || hitIndex == -1 )
 	  return;
 	  return;
 
 
-   LBItem *hitItem = mItems[ itemHit ];
+   LBItem *hitItem = mItems[ hitIndex ];
    if ( hitItem == NULL || !hitItem->isActive)
    if ( hitItem == NULL || !hitItem->isActive)
 	  return;
 	  return;
 
 
-   // If we're not a multiple selection listbox, we simply select/unselect an item
+	handleItemClick(hitItem, hitIndex, event);
+}
+
+S32 GuiListBoxCtrl::getHitIndex(const GuiEvent& event)
+{
+	Point2I localPoint = globalToLocalCoord(event.mousePoint);
+	return (localPoint.y < 0) ? -1 : (S32)mFloor((F32)localPoint.y / (F32)mItemSize.y);
+}
+
+void GuiListBoxCtrl::handleItemClick(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
+{
    if( !mMultipleSelections )
    if( !mMultipleSelections )
    {
    {
-	  // No current selection?  Just select the cell and move on
-	  S32 selItem = getSelectedItem();
+	  handleItemClick_SingleSelection(hitItem, hitIndex, event);
+   }
+   else
+   {
+	   if (!handleItemClick_MultiSelection(hitItem, hitIndex, event))
+	   {
+		   return;
+	   }
+   }
+
+   handleItemClick_ClickCallbacks(hitItem, hitIndex, event);
+   mLastClickItem = hitItem;
+}
+
+void GuiListBoxCtrl::handleItemClick_SingleSelection(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
+{
+	// No current selection?  Just select the cell and move on
+	S32 selItem = getSelectedItem();
 
 
-	  if ( selItem != itemHit && selItem != -1 )
-		 clearSelection();
+	if (selItem != hitIndex && selItem != -1)
+		clearSelection();
 
 
-	  // Set the current selection
-	  setCurSel( itemHit );
+	// Set the current selection
+	setCurSel(hitIndex);
+}
 
 
-		if( itemHit == selItem && event.mouseClickCount == 2)
+bool GuiListBoxCtrl::handleItemClick_MultiSelection(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
+{
+	// Deal with multiple selections
+	if (event.modifier & SI_CTRL)
+	{
+		// Ctrl-Click toggles selection
+		if (hitItem->isSelected)
 		{
 		{
-			if(caller->isMethod("onDoubleClick") )
-				Con::executef(caller, 3, "onDoubleClick", Con::getIntArg(itemHit), hitItem->itemText, hitItem->ID);
+			removeSelection(hitItem, hitIndex);
+
+			// We return here when we deselect an item because we don't store last clicked when we deselect
+			return false;
 		}
 		}
-		else if (caller->isMethod("onClick"))
+		else
+			addSelection(hitItem, hitIndex);
+	}
+	else if (event.modifier & SI_SHIFT)
+	{
+		if (!mLastClickItem)
+			addSelection(hitItem, hitIndex);
+		else
+			setCurSelRange(getItemIndex(mLastClickItem), hitIndex);
+	}
+	else
+	{
+		if (getSelCount() != 0)
 		{
 		{
-			Con::executef(caller, 3, "onClick", Con::getIntArg(itemHit), hitItem->itemText, hitItem->ID);
+			S32 selItem = getSelectedItem();
+			if (selItem != -1 && mItems[selItem] != hitItem)
+				clearSelection();
 		}
 		}
-
-	  // Store the clicked item
-	  mLastClickItem = hitItem;
-
-	  return;
-   }
-   
-   // Deal with multiple selections
-   if( event.modifier & SI_CTRL)
-   {
-	  // Ctrl-Click toggles selection
-	  if( hitItem->isSelected )
-	  {
-		 removeSelection( hitItem, itemHit );
-
-		 // We return here when we deselect an item because we don't store last clicked when we deselect
-		 return;
-	  }
-	  else
-		 addSelection( hitItem, itemHit );
-   }
-   else if( event.modifier & SI_SHIFT )
-   {
-	  if( !mLastClickItem )
-		 addSelection( hitItem, itemHit );
-	  else
-		 setCurSelRange( getItemIndex( mLastClickItem ), itemHit );
-   }
-   else
-   {
-	  if( getSelCount() != 0 )
-	  {
-		 S32 selItem = getSelectedItem();
-		 if( selItem != -1 && mItems[selItem] != hitItem )
-			clearSelection();
-	  }
-	  addSelection( hitItem, itemHit );
-   }
-
-   if( hitItem == mLastClickItem && event.mouseClickCount == 2)
-   {
-		if(caller->isMethod("onDoubleClick") )
-			Con::executef(caller, 3, "onDoubleClick", Con::getIntArg(itemHit), hitItem->itemText, hitItem->ID);
+		addSelection(hitItem, hitIndex);
 	}
 	}
-   else if (caller->isMethod("onClick"))
-   {
-	   Con::executef(caller, 3, "onClick", Con::getIntArg(itemHit), hitItem->itemText, hitItem->ID);
-   }
+	return true;
+}
 
 
-   mLastClickItem = hitItem;
+void GuiListBoxCtrl::handleItemClick_ClickCallbacks(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
+{
+	if (hitItem == mLastClickItem && event.mouseClickCount == 2)
+	{
+		if (caller->isMethod("onDoubleClick"))
+			Con::executef(caller, 4, "onDoubleClick", Con::getIntArg(hitIndex), hitItem->itemText, hitItem->ID);
+	}
+	else if (caller->isMethod("onClick"))
+	{
+		Con::executef(caller, 4, "onClick", Con::getIntArg(hitIndex), hitItem->itemText, hitItem->ID);
+	}
 }
 }
 
 
 bool GuiListBoxCtrl::onKeyDown(const GuiEvent &event)
 bool GuiListBoxCtrl::onKeyDown(const GuiEvent &event)

+ 10 - 1
engine/source/gui/guiListBoxCtrl.h

@@ -56,6 +56,9 @@ public:
    class LBItem
    class LBItem
    {
    {
    public:
    public:
+      LBItem() : itemText(StringTable->EmptyString), isSelected(0), isActive(1), ID(0), itemData(nullptr), color(ColorF()), hasColor(0) { }
+	  virtual ~LBItem() { }
+
       StringTableEntry  itemText;
       StringTableEntry  itemText;
       bool              isSelected;
       bool              isSelected;
 	  bool				isActive;
 	  bool				isActive;
@@ -115,6 +118,7 @@ public:
    S32               addItemWithColor( StringTableEntry text, ColorF color = ColorF(-1, -1, -1), void *itemData = NULL);
    S32               addItemWithColor( StringTableEntry text, ColorF color = ColorF(-1, -1, -1), void *itemData = NULL);
    S32				 addItemWithID(StringTableEntry text, S32 ID = 0, void *itemData = NULL);
    S32				 addItemWithID(StringTableEntry text, S32 ID = 0, void *itemData = NULL);
    S32               insertItem( S32 index, StringTableEntry text, void *itemData = NULL );
    S32               insertItem( S32 index, StringTableEntry text, void *itemData = NULL );
+   virtual LBItem*	 createItem();
    S32               insertItemWithColor( S32 index, StringTableEntry text, ColorF color = ColorF(-1, -1, -1), void *itemData = NULL);
    S32               insertItemWithColor( S32 index, StringTableEntry text, ColorF color = ColorF(-1, -1, -1), void *itemData = NULL);
    S32               findItemText( StringTableEntry text, bool caseSensitive = false );
    S32               findItemText( StringTableEntry text, bool caseSensitive = false );
 
 
@@ -156,7 +160,12 @@ public:
    // Mouse Events
    // Mouse Events
    virtual void      onTouchDown( const GuiEvent &event );
    virtual void      onTouchDown( const GuiEvent &event );
    virtual void      onTouchDragged(const GuiEvent &event);
    virtual void      onTouchDragged(const GuiEvent &event);
-   virtual bool		onKeyDown(const GuiEvent &event);
+   virtual bool		 onKeyDown(const GuiEvent &event);
+   virtual S32		 getHitIndex(const GuiEvent& event);
+   virtual void      handleItemClick(LBItem* hitItem, S32 hitIndex, const GuiEvent& event);
+   virtual void      handleItemClick_SingleSelection(LBItem* hitItem, S32 hitIndex, const GuiEvent& event);
+   virtual bool      handleItemClick_MultiSelection(LBItem* hitItem, S32 hitIndex, const GuiEvent& event);
+   virtual void      handleItemClick_ClickCallbacks(LBItem* hitItem, S32 hitIndex, const GuiEvent& event);
 
 
    // Sorting
    // Sorting
    virtual void		 sortByText(bool increasing = true);
    virtual void		 sortByText(bool increasing = true);

+ 1 - 0
engine/source/gui/guiMessageVectorCtrl.cc

@@ -92,6 +92,7 @@ GuiMessageVectorCtrl::GuiMessageVectorCtrl()
    mSpecialColor.set(0, 0, 255);
    mSpecialColor.set(0, 0, 255);
 
 
    mMaxColorIndex = 9;
    mMaxColorIndex = 9;
+   mIsContainer = false;
 }
 }
 
 
 
 

+ 1 - 0
engine/source/gui/guiProgressCtrl.cc

@@ -37,6 +37,7 @@ GuiProgressCtrl::GuiProgressCtrl()
    mCurrent = 0.0f;
    mCurrent = 0.0f;
    mStart = 0.0f;
    mStart = 0.0f;
    mEnd = 0.0f;
    mEnd = 0.0f;
+   mIsContainer = false;
 
 
    setAnimationLength(250);
    setAnimationLength(250);
    setEasingFunction(EaseInOut);
    setEasingFunction(EaseInOut);

+ 1 - 0
engine/source/gui/guiSliderCtrl.cc

@@ -43,6 +43,7 @@ GuiSliderCtrl::GuiSliderCtrl(void)
     mDisplayValue = false;
     mDisplayValue = false;
     mMouseOver = false;
     mMouseOver = false;
     mDepressed = false;
     mDepressed = false;
+	mIsContainer = false;
 }
 }
 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------

+ 2 - 0
engine/source/gui/guiTextEditCtrl.cc

@@ -395,6 +395,8 @@ GuiTextEditCtrl::GuiTextEditCtrl()
    mSuspendVerticalScrollJump = false;
    mSuspendVerticalScrollJump = false;
    mTextBlockList = TextBlockList();
    mTextBlockList = TextBlockList();
    mScrollVelocity = 0;
    mScrollVelocity = 0;
+   mIsContainer = false;
+   mBounds.extent.set(220, 30);
 }
 }
 
 
 static EnumTable::Enums inputModeEnums[] =
 static EnumTable::Enums inputModeEnums[] =

+ 1 - 0
engine/source/gui/guiTextEditSliderCtrl.cc

@@ -37,6 +37,7 @@ GuiTextEditSliderCtrl::GuiTextEditSliderCtrl()
    mIncCounter = 0.0f;
    mIncCounter = 0.0f;
    mFormat = StringTable->insert("%3.2f");
    mFormat = StringTable->insert("%3.2f");
    mTextAreaHit = None;
    mTextAreaHit = None;
+   mIsContainer = false;
 }
 }
 
 
 GuiTextEditSliderCtrl::~GuiTextEditSliderCtrl()
 GuiTextEditSliderCtrl::~GuiTextEditSliderCtrl()

+ 262 - 3851
engine/source/gui/guiTreeViewCtrl.cc

@@ -19,3885 +19,296 @@
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 // IN THE SOFTWARE.
 // IN THE SOFTWARE.
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
-#include "memory/frameAllocator.h"
+
 #include "gui/guiTreeViewCtrl.h"
 #include "gui/guiTreeViewCtrl.h"
-#include "gui/containers/guiScrollCtrl.h"
-#include "console/consoleTypes.h"
-#include "console/console.h"
 #include "graphics/dgl.h"
 #include "graphics/dgl.h"
-#include "gui/guiTypes.h"
-#include "platform/event.h"
-
-IMPLEMENT_CONOBJECT(GuiTreeViewCtrl);
-
-//-----------------------------------------------------------------------------
-// TreeView Item 
-//-----------------------------------------------------------------------------
-GuiTreeViewCtrl::Item::Item( GuiControlProfile *pProfile )
-{
-   AssertFatal( pProfile != NULL , "Cannot create a tree item without a valid tree and control profile!");
-
-   mState               = 0;
-   mId                  = -1;
-   mTabLevel            = 0;
-   mIcon                = 0;
-   mDataRenderWidth     = 0;
-   mScriptInfo.mText    = NULL;
-   mScriptInfo.mValue   = NULL;
-   mInspectorInfo.mObject = NULL;
-   mParent              = NULL;
-   mChild               = NULL;
-   mNext                = NULL;
-   mPrevious            = NULL;
-   mProfile             = pProfile;
-}
-
-GuiTreeViewCtrl::Item::~Item()
-{
-   if( ! mState.test(InspectorData) )
-   {
-      if ( getText() )
-      {
-         delete [] getText();
-         setText(NULL);
-      }
-
-      if ( getValue() )
-      {
-         delete [] getValue();
-         setValue( NULL );
-      }
-   }
-}
-
-void GuiTreeViewCtrl::Item::setNormalImage(S8 id)
-{
-   if(mState.test(InspectorData))
-   {
-      Con::errorf("Tried to set normal image %d for item %d, which is InspectorData!", id, mId);
-      return;
-   }
-
-   mScriptInfo.mNormalImage = id;
-}
-
-void GuiTreeViewCtrl::Item::setExpandedImage(S8 id)
-{
-   if(mState.test(InspectorData))
-   {
-      Con::errorf("Tried to set expanded image %d for item %d, which is InspectorData!", id, mId);
-      return;
-   }
-
-   mScriptInfo.mExpandedImage = id;
-}
-
-void GuiTreeViewCtrl::Item::setText(char *txt)
-{
-   if(mState.test(InspectorData))
-   {
-      Con::errorf("Tried to set text for item %d, which is InspectorData!", mId);
-      return;
-   }
-
-   mScriptInfo.mText = txt;
-
-
-   // Update Render Data
-   if( !mProfile.isNull() )
-      mDataRenderWidth = getDisplayTextWidth( mProfile->getFont() );
-
-}
-
-void GuiTreeViewCtrl::Item::setValue(const char *val)
-{
-   if(mState.test(InspectorData))
-   {
-      Con::errorf("Tried to set value for item %d, which is InspectorData!", mId);
-      return;
-   }
-
-   mScriptInfo.mValue = const_cast<char*>(val); // mValue really ought to be a StringTableEntry
-
-   // Update Render Data
-   if( !mProfile.isNull() )
-      mDataRenderWidth = getDisplayTextWidth( mProfile->getFont());
-
-}
-
-const S8 GuiTreeViewCtrl::Item::getNormalImage() const
-{
-   if(mState.test(InspectorData))
-   {
-      Con::errorf("Tried to get the normal image for item %d, which is InspectorData!", mId);
-      return 0; // fail safe for width determinations
-   }
-
-   return mScriptInfo.mNormalImage;
-}
-
-const S8 GuiTreeViewCtrl::Item::getExpandedImage() const
-{
-   if(mState.test(InspectorData))
-   {
-      Con::errorf("Tried to get the expanded image for item %d, which is InspectorData!", mId);
-      return 0; // fail safe for width determinations
-   }
-
-   return mScriptInfo.mExpandedImage;
-}
-
-char *GuiTreeViewCtrl::Item::getText()
-{
-   if(mState.test(InspectorData))
-   {
-      Con::errorf("Tried to get the text for item %d, which is InspectorData!", mId);
-      return NULL;
-   }
-
-   return mScriptInfo.mText;
-}
-
-char *GuiTreeViewCtrl::Item::getValue()
-{
-   if(mState.test(InspectorData))
-   {
-      Con::errorf("Tried to get the value for item %d, which is InspectorData!", mId);
-      return NULL;
-   }
-
-   return mScriptInfo.mValue;
-}
-
-void GuiTreeViewCtrl::Item::setObject(SimObject *obj)
-{
-   if(!mState.test(InspectorData))
-   {
-      Con::errorf("Tried to set the object for item %d, which is not InspectorData!", mId);
-      return;
-   }
-
-   mInspectorInfo.mObject = obj;
-
-   // Update Render Data
-   if( !mProfile.isNull() )
-      mDataRenderWidth = getDisplayTextWidth( mProfile->getFont());
-
-}
-
-SimObject *GuiTreeViewCtrl::Item::getObject()
-{
-   if(!mState.test(InspectorData))
-   {
-      Con::errorf("Tried to get the object for item %d, which is not InspectorData!", mId);
-      return NULL;
-   }
-
-   return mInspectorInfo.mObject;
-}
-
-
-const U32 GuiTreeViewCtrl::Item::getDisplayTextLength()
-{
-   if(mState.test(Item::InspectorData))
-   {
-      SimObject *obj = getObject();
-
-      if(!obj)
-         return 0;
+#include "gui/guiDefaultControlRender.h"
+#include "gui/guiCanvas.h"
 
 
-      // For the results buffer, it's prefix along with a bunch of other stuff.
-      // So we'll be mostly accurate and add a bit of fudge.
-      return (16
-         + (obj->getName() ? dStrlen(obj->getName()) : 0) + dStrlen(obj->getClassName())
-         + dStrlen(obj->getIdString()) + 20
-         );
-   }
+#include "guiTreeViewCtrl_ScriptBinding.h"
 
 
-   char *pText = getText();
-   if( pText == NULL )
-      return 0;
-
-   return dStrlen( pText );
-}
-
-void GuiTreeViewCtrl::Item::getDisplayText(U32 bufLen, char *buf)
-{
-   FrameAllocatorMarker txtAlloc;
-
-   if(mState.test(Item::InspectorData))
-   {
-      // Inspector data!
-      SimObject *pObject = getObject();
-      if(pObject)
-      {
-         const char* pObjName = pObject->getName();
-         const char* pInternalName = pObject->getInternalName();
-         if( pObjName != NULL )
-            dSprintf(buf, bufLen, "%d: %s - %s", pObject->getId(), pObject->getClassName(), pObjName );
-         else if ( pInternalName != NULL )
-            dSprintf(buf, bufLen, "%d: %s [%s]", pObject->getId(), pObject->getClassName(), pInternalName);
-         else
-            dSprintf(buf, bufLen, "%d: %s", pObject->getId(), pObject->getClassName());
-
-      }
-   }
-   else
-   {
-      // Script data! (copy it in)
-      dStrncpy(buf, getText(), bufLen);
-   }
-}
-
-const S32 GuiTreeViewCtrl::Item::getDisplayTextWidth(GFont *font)
-{
-   if( !font )
-      return 0;
-
-   FrameAllocatorMarker txtAlloc;
-   U32 bufLen = getDisplayTextLength();
-   if( bufLen == 0 )
-      return 0;
-
-   char *buf = (char*)txtAlloc.alloc(bufLen);
-   getDisplayText(bufLen, buf);
-
-   return font->getStrWidth(buf);
-}
-
-const bool GuiTreeViewCtrl::Item::isParent() const
-{
-   if(mState.test(VirtualParent))
-   {
-      if( !isInspectorData() )
-         return true;
-
-      // Does our object have any children?
-      if(mInspectorInfo.mObject)
-      {
-         SimSet *pSimSet = dynamic_cast<SimSet*>( (SimObject*)mInspectorInfo.mObject);
-         if ( pSimSet != NULL && pSimSet->size() > 0)
-            return pSimSet->size();
-      }
-   }
-
-   // Otherwise, just return whether the child list is populated.
-   return mChild;
-}
-
-const bool GuiTreeViewCtrl::Item::isExpanded() const
-{
-   if(mState.test(InspectorData))
-      return mInspectorInfo.mObject ? mInspectorInfo.mObject->isExpanded() : false;
-   else
-      return mState.test(Expanded);
-}
-
-void GuiTreeViewCtrl::Item::setExpanded(bool f)
-{
-   if(mState.test(InspectorData) && !mInspectorInfo.mObject.isNull() )
-      mInspectorInfo.mObject->setExpanded(f);
-   else
-      mState.set(Expanded, f);
-}
-
-void GuiTreeViewCtrl::Item::setVirtualParent( bool value )
-{
-   mState.set(VirtualParent, value);
-}
-
-GuiTreeViewCtrl::Item *GuiTreeViewCtrl::Item::findChildByValue(const SimObject *obj)
-{
-   // Iterate over our children and try to find the given
-   // SimObject
-
-   Item *pResultObj = mChild;
-
-   while(pResultObj)
-   {
-      // Skip non-inspector data stuff.
-      if(pResultObj->mState.test(InspectorData))
-      {
-         if(pResultObj->getObject() == obj)
-            return pResultObj;
-      }
-      pResultObj = pResultObj->mNext;
-   }
-
-   // If the loop terminated we are NULL, otherwise we have the result in res.
-   return NULL;
-}
-
-GuiTreeViewCtrl::Item *GuiTreeViewCtrl::Item::findChildByValue( StringTableEntry Value )
-{
-   // Iterate over our children and try to find the given Value
-   // Note : This is a case-insensitive search
-   Item *pResultObj = mChild;
-
-   while(pResultObj)
-   {
-
-      // check the script value of the item against the specified value
-      if( pResultObj->mScriptInfo.mValue != NULL && dStricmp( pResultObj->mScriptInfo.mValue, Value ) == 0 )
-         return pResultObj;
-      pResultObj = pResultObj->mNext;
-   }
-   // If the loop terminated we didn't find an item with the specified script value
-   return NULL;
-}
-
-
-//------------------------------------------------------------------------------
+IMPLEMENT_CONOBJECT(GuiTreeViewCtrl);
 
 
 GuiTreeViewCtrl::GuiTreeViewCtrl()
 GuiTreeViewCtrl::GuiTreeViewCtrl()
 {
 {
-   VECTOR_SET_ASSOCIATION(mItems);
-   VECTOR_SET_ASSOCIATION(mVisibleItems);
-   VECTOR_SET_ASSOCIATION(mSelectedItems);
-   VECTOR_SET_ASSOCIATION(mSelected);
-
-   mItemFreeList  =  NULL;
-   mRoot          =  NULL;
-   mInstantGroup  =  0;
-   mItemCount     =  0;
-   mSelectedItem  =  0;
-   mStart         =  0;
-   mTicksPassed   =  0;
-   mTreeRefreshInterval   =  30;
-
-   mDraggedToItem =  0;
-   mOldDragY      = 0;
-   mCurrentDragCell = 0;
-   mPreviousDragCell = 0;
-   mDragMidPoint = NomDragMidPoint;
-   mMouseDragged = false;
-   mDebug = false;
-
-   // persist info..
-   mTabSize = 16;
-   mTextOffset = 2;
-   mFullRowSelect = false;
-   mItemHeight = 20;
-
-   //
-   setSize(Point2I(1, 0));
-
-   // Set up default state
-   mFlags.set(ShowTreeLines);
-   mFlags.set(IsEditable, false);
-
-   mDestroyOnSleep = true;
-   mSupportMouseDragging = true;
-   mMultipleSelections = true;
-   mDeleteObjectAllowed = true;
-   mDragToItemAllowed = true;
-
-   mBitmapBase       = StringTable->EmptyString;
-   mTexRollover      = NULL;
-   mTexSelected      = NULL;
-
-   
+	mActive = true;
+	mIsContainer = false;
+	mIndentSize = 10;
 }
 }
 
 
 GuiTreeViewCtrl::~GuiTreeViewCtrl()
 GuiTreeViewCtrl::~GuiTreeViewCtrl()
 {
 {
-   destroyTree();
-}
-
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::initPersistFields()
-{
-   Parent::initPersistFields();
-
-   addGroup("TreeView");
-   addField("tabSize",              TypeS32,    Offset(mTabSize,              GuiTreeViewCtrl));
-   addField("textOffset",           TypeS32,    Offset(mTextOffset,           GuiTreeViewCtrl));
-   addField("fullRowSelect",        TypeBool,   Offset(mFullRowSelect,        GuiTreeViewCtrl));
-   addField("itemHeight",           TypeS32,    Offset(mItemHeight,           GuiTreeViewCtrl));
-   addField("destroyTreeOnSleep",   TypeBool,   Offset(mDestroyOnSleep,       GuiTreeViewCtrl));
-   addField("MouseDragging",        TypeBool,   Offset(mSupportMouseDragging, GuiTreeViewCtrl));
-   addField("MultipleSelections",   TypeBool,   Offset(mMultipleSelections,   GuiTreeViewCtrl));
-   addField("DeleteObjectAllowed",  TypeBool,   Offset(mDeleteObjectAllowed,  GuiTreeViewCtrl));
-   addField("DragToItemAllowed",    TypeBool,   Offset(mDragToItemAllowed,    GuiTreeViewCtrl));
-   endGroup("TreeView");
-}
-
-//------------------------------------------------------------------------------
-
-GuiTreeViewCtrl::Item * GuiTreeViewCtrl::getItem(S32 itemId)
-{
-   if((itemId > 0) && (itemId <= mItems.size()))
-   {
-      if (mItems[itemId-1] != NULL)
-         return(mItems[itemId-1]);
-   }
-
-   return(0);
-}
-
-//------------------------------------------------------------------------------
-
-GuiTreeViewCtrl::Item * GuiTreeViewCtrl::createItem(S32 icon)
-{
-   Item * pNewItem = NULL;
-
-   // grab from the free list?
-   if( mItemFreeList )
-   {
-      pNewItem = mItemFreeList;
-      mItemFreeList = pNewItem->mNext;
-
-      // re-add to vector
-      mItems[ pNewItem->mId - 1 ] = pNewItem;
-   }
-   else
-   {
-      pNewItem = new Item( mProfile );
-
-      AssertFatal( pNewItem != NULL, "Fatal : unable to allocate tree item!");
-
-      mItems.push_back( pNewItem );
-
-      // set the id
-      pNewItem->mId = mItems.size();
-   }
-
-   // reset
-   if (icon)
-      pNewItem->mIcon = icon;
-   else
-      pNewItem->mIcon = Default; //default icon to stick next to an item
-
-   pNewItem->mState.clear();
-   pNewItem->mState = 0;
-   pNewItem->mTabLevel = 0;
-
-   // Null out item pointers
-   pNewItem->mNext = 0;
-   pNewItem->mPrevious = 0;
-   pNewItem->mChild = 0;
-   pNewItem->mParent = 0;
-
-   mItemCount++;
-
-   return pNewItem;
-}
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::destroyChildren(Item * item, Item * parent)
-{
-   if ( !item  || item == parent )
-      return;
-
-   if ( item->isParent() && item->mChild )
-      destroyChildren(item->mChild, parent);
-   else if( item->mNext )
-      destroyChildren(item->mNext, parent);
-   else
-   {
-      // destroy the item and back up
-      Item * pPrevItem = item->mPrevious;
-      destroyItem( item );
-      destroyChildren( pPrevItem, parent );
-   }
-}
-void GuiTreeViewCtrl::destroyItem(Item * item)
-{
-   if(!item)
-      return;
-
-   if(item->isInspectorData())
-   {
-      // make sure the SimObjectPtr is clean!
-      //Con::executef(this,2, "onDeleteObject",Con::getIntArg(item->mInspectorInfo.mObject->getIdString()));
-      SimObject *pObject = item->getObject();
-      if( pObject && pObject->isProperlyAdded() )
-         pObject->deleteObject();
-
-      item->setObject( NULL );
-   }
-   else
-   {
-      char *pCleanup = item->getText();
-      // Clean up the memory...
-      if ( pCleanup != NULL )
-      {
-         delete []pCleanup;
-         item->setText( NULL );
-      }
-
-      pCleanup = item->getValue();
-      if ( pCleanup != NULL )
-      {
-         delete []pCleanup;
-         item->setValue( NULL );
-      }
-   }
-
-   // unlink
-   if( item->mPrevious )
-      item->mPrevious->mNext = item->mNext;
-   if( item->mNext )
-      item->mNext->mPrevious = item->mPrevious;
-   if( item->mParent && ( item->mParent->mChild == item ) )
-      item->mParent->mChild = item->mNext;
-
-   // remove from vector
-   mItems[item->mId-1] = 0;
-
-   // set as root free item
-   item->mNext = mItemFreeList;
-   mItemFreeList = item;
-   mItemCount--;
-}
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::deleteItem(Item *item)
-{
-   removeItem(item->mId);
-}
-
-//------------------------------------------------------------------------------
-
-void GuiTreeViewCtrl::destroyTree()
-{
-   // clear the item list
-   for(U32 i = 0; i < (U32)mItems.size(); i++)
-   {
-      Item *pFreeItem = mItems[ i ];
-      if( pFreeItem != NULL )
-         delete pFreeItem;
-   }
-
-   mItems.clear();
-
-   // clear the free list
-   while(mItemFreeList)
-   {
-      Item *next = mItemFreeList->mNext;
-      delete mItemFreeList;
-      mItemFreeList = next;
-   }
-
-   mVisibleItems.clear();
-   mSelectedItems.clear();
-
-   //
-   mRoot          = NULL;
-   mItemFreeList  = NULL;
-   mItemCount     = 0;
-   mSelectedItem  = 0;
-   mDraggedToItem = 0;
-}
-
-//------------------------------------------------------------------------------
-
-void GuiTreeViewCtrl::buildItem( Item* item, U32 tabLevel, bool bForceFullUpdate )
-{
-   if (!item || !mActive || !isVisible() || !mProfile  )
-      return;
-
-   // If it's inspector data, make sure we still have it, if not, kill it.
-   if(item->isInspectorData() && !item->getObject() )
-   {
-      removeItem(item->mId);
-      return;
-   }
-
-   // If it's a virtual parent, give a chance to update itself...
-   if(item->mState.test( Item::VirtualParent) )
-   {
-      // If it returns false the item has been removed.
-      if(!onVirtualParentBuild(item, bForceFullUpdate))
-         return;
-   }
-
-   item->mTabLevel = tabLevel;
-   mVisibleItems.push_back( item );
-
-   if ( mProfile != NULL && mProfile->getFont(mFontSizeAdjust) )
-   {
-      S32 width = ( tabLevel + 1 ) * mTabSize + item->getDisplayTextWidth(mProfile->getFont(mFontSizeAdjust));
-      if ( mProfile->mBitmapArrayRects.size() > 0 )
-         width += mProfile->mBitmapArrayRects[0].extent.x;
-      
-      width += (item->mTabLevel+1) * mItemHeight; // using mItemHeight for icon width, close enough
-                                                  // this will only fail if somebody starts using super wide icons.
-
-      if ( width > mMaxWidth )
-         mMaxWidth = width;
-   }
-
-   // if expanded, then add all the children items as well
-  if ( item->isExpanded() || bForceFullUpdate)
-   {
-      Item * child = item->mChild;
-      while ( child )
-      {
-         // Bit of a hack so we can safely remove items as we
-         // traverse.
-         Item *pChildTemp = child;
-         child = child->mNext;
-
-         buildItem( pChildTemp, tabLevel + 1, bForceFullUpdate );
-      }
-   }
-}
-
-//------------------------------------------------------------------------------
-
-void GuiTreeViewCtrl::buildVisibleTree(bool bForceFullUpdate)
-{
-   // Recursion Prevention.
-   if( mFlags.test( BuildingVisTree ) )
-      return;
-   mFlags.set( BuildingVisTree, true );
-
-   mMaxWidth = 0;
-   mVisibleItems.clear();
-
-   // Update the flags.
-   mFlags.clear(RebuildVisible);
-
-   // build the root items
-   Item *traverse = mRoot;
-   while(traverse)
-   {
-      buildItem(traverse, 0, bForceFullUpdate);
-      traverse = traverse->mNext;
-   }
-
-   // adjust the GuiArrayCtrl
-   mCellSize.set(mMaxWidth+1, mItemHeight);
-   setSize(Point2I(1, mVisibleItems.size()));
-   syncSelection();
-
-   // Done Recursing.
-   mFlags.clear( BuildingVisTree );
-}
-
-//------------------------------------------------------------------------------
-
-bool GuiTreeViewCtrl::scrollVisible( S32 itemId )
-{
-   Item* item = getItem(itemId);
-   if(item)
-      return scrollVisible(item);
-
-   return false;
-}
-bool GuiTreeViewCtrl::scrollVisible( Item *item )
-{
-   // Now, make sure it's visible (ie, all parents expanded)
-   Item *parent = item->mParent;
-
-   if( !item->isInspectorData() && item->mState.test(Item::VirtualParent) )
-      onVirtualParentExpand(item);
-
-   while(parent)
-   {
-      parent->setExpanded(true);
-
-      if( !parent->isInspectorData() && parent->mState.test(Item::VirtualParent) )
-         onVirtualParentExpand(parent);
-
-      parent = parent->mParent;
-   }
-
-   // Get our scroll-pappy, if any.
-   GuiScrollCtrl *pScrollParent = dynamic_cast<GuiScrollCtrl*>( getParent() );
-
-   if ( !pScrollParent )
-   {
-      Con::warnf("GuiTreeViewCtrl::scrollVisible - parent control is not a GuiScrollCtrl!");
-      return false;
-   }
-
-   // And now, build the visible tree so we know where we have to scroll.
-   buildVisibleTree();
-
-   // All done, let's figure out where we have to scroll...
-   for(S32 i=0; i<mVisibleItems.size(); i++)
-   {
-      if(mVisibleItems[i] == item)
-      {
-         pScrollParent->scrollRectVisible(RectI(0, i * mItemHeight, mMaxWidth, mItemHeight));
-         return true;
-      }
-   }
-
-   // If we got here, it's probably bad...
-   Con::errorf("GuiTreeViewCtrl::scrollVisible - was unable to find specified item in visible list!");
-   return false;
-}
-
-//------------------------------------------------------------------------------
-
-S32 GuiTreeViewCtrl::insertItem(S32 parentId, const char * text, const char * value, const char * iconString, S16 normalImage, S16 expandedImage)
-{
-   if( ( parentId < 0 ) || ( parentId > mItems.size() ) )
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::insertItem: invalid parent id!");
-      return 0;
-   }
-
-   if((parentId != 0) && (mItems[parentId-1] == 0))
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::insertItem: parent item invalid!");
-      return 0;
-   }
-
-
-   const char * pItemText  = ( text != NULL ) ? dStrdup( text ) : "";
-   const char * pItemValue = ( value != NULL ) ? dStrdup( value ) : "";
-
-   S32 icon = getIcon(iconString);
-
-   // create an item (assigns id)
-   Item * pNewItem = createItem(icon);
-   if( pNewItem == NULL )
-      return 0;
-
-//   // Ugh.  This code bothers me. - JDD
-//   pNewItem->setText( new char[dStrlen( pItemText ) + 1] );
-//   dStrcpy( pNewItem->getText(), pItemText );
-//   pNewItem->setValue( new char[dStrlen( pItemValue ) + 1] );
-//   dStrcpy( pNewItem->getValue(), pItemValue );
-   // paxorr fix:
-   char *tmp = new char[dStrlen( pItemText ) + 1];
-   dStrcpy( tmp, pItemText );
-   pNewItem->setText( tmp );
-   tmp = new char[dStrlen( pItemValue ) + 1];
-   dStrcpy( tmp, pItemValue );
-   pNewItem->setValue( tmp );
-   
-   pNewItem->setNormalImage( (S8)normalImage );
-   pNewItem->setExpandedImage( (S8)expandedImage );
-
-   // root level?
-   if(parentId == 0)
-   {
-      // insert back
-      if( mRoot != NULL )
-      {
-         Item * pTreeTraverse = mRoot;
-         while( pTreeTraverse != NULL && pTreeTraverse->mNext != NULL )
-            pTreeTraverse = pTreeTraverse->mNext;
-
-         pTreeTraverse->mNext = pNewItem;
-         pNewItem->mPrevious = pTreeTraverse;
-      }
-      else
-         mRoot = pNewItem;
-
-      mFlags.set(RebuildVisible);
-   }
-   else if( mItems.size() >= ( parentId - 1 ) )
-   {
-      Item * pParentItem = mItems[parentId-1];
-
-      // insert back
-      if( pParentItem != NULL && pParentItem->mChild)
-      {
-         Item * pTreeTraverse = pParentItem->mChild;
-         while( pTreeTraverse != NULL && pTreeTraverse->mNext != NULL )
-            pTreeTraverse = pTreeTraverse->mNext;
-
-         pTreeTraverse->mNext = pNewItem;
-         pNewItem->mPrevious = pTreeTraverse;
-      }
-      else
-         pParentItem->mChild = pNewItem;
-
-      pNewItem->mParent = pParentItem;
-
-      if( pParentItem->isExpanded() )
-         mFlags.set(RebuildVisible);
-   }
-
-   //
-   if(mFlags.test(RebuildVisible))
-      buildVisibleTree();
-
-   return pNewItem->mId;
-}
-
-//------------------------------------------------------------------------------
-
-bool GuiTreeViewCtrl::removeItem(S32 itemId)
-{
-   // tree?
-   if(itemId == 0)
-   {
-      destroyTree();
-      return(true);
-   }
-
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      //Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::removeItem: invalid item id!");
-      return false;
-   }
-
-   // root?
-   if(item == mRoot)
-      mRoot = item->mNext;
-
-   // Dispose of any children...
-   if (item->mChild)
-      destroyChildren(item->mChild, item);
-
-   // Kill the item...
-   destroyItem(item);
-
-   // Update the rendered tree...
-   buildVisibleTree();
-
-   return true;
-}
-
-
-void GuiTreeViewCtrl::removeAllChildren(S32 itemId)
-{
-   Item * item = getItem(itemId);
-   if(item)
-   {
-      destroyChildren(item->mChild, item);
-   }
-}
-//------------------------------------------------------------------------------
-
-const S32 GuiTreeViewCtrl::getFirstRootItem() const
-{
-   return (mRoot ? mRoot->mId : 0);
 }
 }
 
 
-//------------------------------------------------------------------------------
-
-S32 GuiTreeViewCtrl::getChildItem(S32 itemId)
+GuiTreeViewCtrl::TreeItem* GuiTreeViewCtrl::grabItemPtr(S32 index)
 {
 {
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getChild: invalid item id!");
-      return(0);
-   }
+	// Range Check
+	if (index >= mItems.size() || index < 0)
+	{
+		Con::warnf("GuiListBoxCtrl::grabItemPtr - index out of range!");
+		return nullptr;
+	}
 
 
-   return(item->mChild ? item->mChild->mId : 0);
+	// Grab our item
+	return dynamic_cast<GuiTreeViewCtrl::TreeItem*>(mItems[index]);
 }
 }
 
 
-S32 GuiTreeViewCtrl::getParentItem(S32 itemId)
+void GuiTreeViewCtrl::initPersistFields()
 {
 {
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getParent: invalid item id!");
-      return(0);
-   }
-
-   return(item->mParent ? item->mParent->mId : 0);
+	Parent::initPersistFields();
 }
 }
 
 
-S32 GuiTreeViewCtrl::getNextSiblingItem(S32 itemId)
+void GuiTreeViewCtrl::onPreRender()
 {
 {
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getNextSibling: invalid item id!");
-      return(0);
-   }
+	
+}
+
+void GuiTreeViewCtrl::onRender(Point2I offset, const RectI& updateRect)
+{
+	RectI clip = dglGetClipRect();
+	if (mFitParentWidth && (mBounds.extent.x != clip.extent.x || mItemSize.x != clip.extent.x))
+	{
+		mBounds.extent.x = clip.extent.x;
+		mItemSize.x = clip.extent.x;
+	}
+
+	for (S32 i = 0, j = 0; i < mItems.size(); i++)
+	{
+		// Only render visible items
+		if ((j + 1) * mItemSize.y + offset.y < updateRect.point.y)
+			continue;
+
+		// Break out once we're no longer in visible item range
+		if (j * mItemSize.y + offset.y >= updateRect.point.y + updateRect.extent.y)
+			break;
+
+		RectI itemRect = RectI(offset.x, offset.y + (j * mItemSize.y), mItemSize.x, mItemSize.y);
+
+		TreeItem* treeItem = dynamic_cast<TreeItem*>(mItems[i]);
+
+		if(!treeItem || treeItem->isVisible)
+		{
+			// Render our item
+			onRenderItem(itemRect, mItems[i]);
+			j++;
+		}
+	}
+}
+
+void GuiTreeViewCtrl::onRenderItem(RectI& itemRect, LBItem* item)
+{
+	TreeItem* treeItem = dynamic_cast<TreeItem*>(item);
+	SimObject* obj = static_cast<SimObject*>(item->itemData);
+	if (!treeItem)
+	{
+		Parent::onRenderItem(itemRect, item);
+		return;
+	}
+
+	Point2I cursorPt = Point2I(0, 0);
+	GuiCanvas* root = getRoot();
+	if (root)
+	{
+		cursorPt = root->getCursorPos();
+	}
+	GuiControlState currentState = GuiControlState::NormalState;
+	if (!mActive || !item->isActive)
+		currentState = GuiControlState::DisabledState;
+	else if (item->isSelected)
+		currentState = GuiControlState::SelectedState;
+	else if (itemRect.pointInRect(cursorPt))
+		currentState = GuiControlState::HighlightState;
+	RectI ctrlRect = applyMargins(itemRect.point, itemRect.extent, currentState, mProfile);
+
+	if (!ctrlRect.isValidRect())
+	{
+		return;
+	}
+
+	renderUniversalRect(ctrlRect, mProfile, currentState);
+
+	//Render Text
+	dglSetBitmapModulation(getFontColor(mProfile, currentState));
+	RectI fillRect = applyBorders(ctrlRect.point, ctrlRect.extent, currentState, mProfile);
+	RectI contentRect = applyPadding(fillRect.point, fillRect.extent, currentState, mProfile);
+
+	// Indent by level
+	contentRect.point.x += (treeItem->level * contentRect.extent.y);
+	contentRect.extent.x -= (treeItem->level * contentRect.extent.y);
+
+	// Render open/close triangle
+	if(obj)
+	{
+		SimSet* setObj = dynamic_cast<SimSet*>(obj);
+		GuiControl* guiCtrl = dynamic_cast<GuiControl*>(obj);
+		bool showTriangle = (guiCtrl && guiCtrl->mIsContainer) || (!guiCtrl && setObj && setObj->size() > 0);
+		if (showTriangle)
+		{
+			RectI drawArea = RectI(contentRect.point.x, contentRect.point.y, contentRect.extent.y, contentRect.extent.y);
+			treeItem->triangleArea.set(drawArea.point, drawArea.extent);
+			ColorI color = mProfile->getFontColor(currentState);
+			renderTriangleIcon(drawArea, color, treeItem->isOpen ? GuiDirection::Down : GuiDirection::Right, 8);
+		}
+	}
+	contentRect.point.x += contentRect.extent.y;
+	contentRect.extent.x -= contentRect.extent.y;
+
+	renderText(contentRect.point, contentRect.extent, item->itemText, mProfile);
+}
+
+S32 GuiTreeViewCtrl::getHitIndex(const GuiEvent& event)
+{
+	Point2I localPoint = globalToLocalCoord(event.mousePoint);
+	if (localPoint.y < 0)
+	{
+		return -1;
+	}
+	S32 slot = (S32)mFloor((F32)localPoint.y / (F32)mItemSize.y);
+	for (S32 i = 0, j = 0; i < mItems.size(); i++)
+	{
+		TreeItem* treeItem = dynamic_cast<TreeItem*>(mItems[i]);
+		if (treeItem && treeItem->isVisible)
+		{
+			if (j == slot)
+			{
+				return i;
+			}
+			j++;
+		}
+	}
+}
+
+void GuiTreeViewCtrl::handleItemClick(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
+{
+	TreeItem* treeItem = dynamic_cast<TreeItem*>(hitItem);
+	if (treeItem)
+	{
+		if (treeItem->triangleArea.pointInRect(event.mousePoint))
+		{
+			treeItem->isOpen = !treeItem->isOpen;
+			setBranchesVisible(treeItem, treeItem->isOpen);
+			return;
+		}
+	}
+
+	Parent::handleItemClick(hitItem, hitIndex, event);
+}
+
+void GuiTreeViewCtrl::handleItemClick_ClickCallbacks(LBItem* hitItem, S32 hitIndex, const GuiEvent& event)
+{
+	TreeItem* treeItem = dynamic_cast<TreeItem*>(hitItem);
+	if (!treeItem)
+	{
+		Parent::handleItemClick_ClickCallbacks(hitItem, hitIndex, event);
+		return;
+	}
+		
+	SimObject* obj = static_cast<SimObject*>(treeItem->itemData);
+	if (hitItem == mLastClickItem && event.mouseClickCount == 2)
+	{
+		if (caller->isMethod("onDoubleClick"))
+			Con::executef(caller, 2, "onDoubleClick", Con::getIntArg(obj->getId()));
+	}
+	else if (caller->isMethod("onClick"))
+	{
+		Con::executef(caller, 2, "onClick", Con::getIntArg(obj->getId()));
+	}
+}
+
+void GuiTreeViewCtrl::inspectObject(SimObject* obj)
+{
+	clearItems();
+	mRootObject = obj;
+
+	StringTableEntry text = getObjectText(obj);
+	S32 id = addItemWithID(text, obj->getId(), obj);
+	TreeItem* treeItem = grabItemPtr(id);
+	treeItem->level = 0;
+	addBranches(treeItem, obj, 1);
+}
+
+void GuiTreeViewCtrl::addBranches(TreeItem* treeItem, SimObject* obj, U16 level)
+{
+	SimSet* setObj = dynamic_cast<SimSet*>(obj);
+	if(setObj)
+	{
+		for(auto sub : *setObj)
+		{
+			StringTableEntry text = getObjectText(sub);
+			S32 id = addItemWithID(text, sub->getId(), sub);
+			TreeItem* branch = grabItemPtr(id);
+			branch->level = level;
+			branch->trunk = treeItem;
+			treeItem->branchList.push_back(branch);
+
+			addBranches(branch, sub, level + 1);
+		}
+	}
+}
+
+GuiListBoxCtrl::LBItem* GuiTreeViewCtrl::createItem()
+{
+	LBItem* newItem = new TreeItem;
+	if (!newItem)
+	{
+		return nullptr;
+	}
+	return newItem;
+}
+
+void GuiTreeViewCtrl::refreshTree()
+{
+	if (mRootObject)
+	{
+		inspectObject(mRootObject);
+	}
+}
+
+StringTableEntry GuiTreeViewCtrl::getObjectText(SimObject* obj)
+{
+	char buffer[1024];
+	if (obj)
+	{
+		const char* pObjName = obj->getName();
+		const char* pInternalName = obj->getInternalName();
+		if (pObjName != NULL)
+			dSprintf(buffer, sizeof(buffer), "%d: %s - %s", obj->getId(), obj->getClassName(), pObjName);
+		else if (pInternalName != NULL)
+			dSprintf(buffer, sizeof(buffer), "%d: %s [%s]", obj->getId(), obj->getClassName(), pInternalName);
+		else
+			dSprintf(buffer, sizeof(buffer), "%d: %s", obj->getId(), obj->getClassName());
+	}
 
 
-   return(item->mNext ? item->mNext->mId : 0);
-}
+	return StringTable->insert(buffer, true);
+}
 
 
-S32 GuiTreeViewCtrl::getPrevSiblingItem(S32 itemId)
+void GuiTreeViewCtrl::calculateHeaderExtent()
 {
 {
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getPrevSibling: invalid item id!");
-      return(0);
-   }
+	if(mProfile)
+	{
+		GuiBorderProfile* topProfile = mProfile->getTopBorder();
+		GuiBorderProfile* bottomProfile = mProfile->getBottomBorder();
 
 
-   return(item->mPrevious ? item->mPrevious->mId : 0);
-}
+		S32 topSize = (topProfile) ? topProfile->getMargin(NormalState) + topProfile->getBorder(NormalState) + topProfile->getPadding(NormalState) : 0;
+		S32 bottomSize = (bottomProfile) ? bottomProfile->getMargin(NormalState) + bottomProfile->getBorder(NormalState) + bottomProfile->getPadding(NormalState) : 0;
 
 
-//------------------------------------------------------------------------------
+		GFont* font = mProfile->getFont();
+		S32 fontSize = (font) ? font->getHeight() : 0;
 
 
-S32 GuiTreeViewCtrl::getItemCount()
-{
-   return(mItemCount);
-}
+		S32 height = topSize + bottomSize + fontSize;
+		S32 width = mBounds.extent.x;
 
 
-S32 GuiTreeViewCtrl::getSelectedItem()
-{
-   return mSelectedItem;
+	}
 }
 }
 
 
-//------------------------------------------------------------------------------
-
-void GuiTreeViewCtrl::moveItemUp( S32 itemId )
-{
-   GuiTreeViewCtrl::Item* pItem = getItem( itemId );
-   if ( !pItem )
-   {
-      Con::errorf( ConsoleLogEntry::General, "GuiTreeViewCtrl::moveItemUp: invalid item id!");
-      return;
-   }
-
-   Item * pParent   = pItem->mParent;
-   Item * pPrevItem = pItem->mPrevious;
-   if ( pPrevItem == NULL || pParent == NULL )
-   {
-      Con::errorf( ConsoleLogEntry::General, "GuiTreeViewCtrl::moveItemUp: Unable to move item up, bad data!");
-      return;
-   }
-
-   //  Diddle the linked list!
-   if ( pPrevItem->mPrevious )
-      pPrevItem->mPrevious->mNext = pItem;
-   else if ( pItem->mParent )
-      pItem->mParent->mChild = pItem;
-
-   if ( pItem->mNext )
-      pItem->mNext->mPrevious = pPrevItem;
-
-   pItem->mPrevious = pPrevItem->mPrevious;
-   pPrevItem->mNext = pItem->mNext;
-   pItem->mNext = pPrevItem;
-   pPrevItem->mPrevious = pItem;
-
-   // Update SimObjects if Appropriate.
-   SimObject * pSimObject = NULL;
-   SimSet    * pParentSet = NULL;
-
-   // Fetch Current Add Set
-   if( pParent->isInspectorData() )
-      pParentSet = dynamic_cast<SimSet*>( pParent->getObject() );
-   else
-   {
-      // parent is probably script data so we search up the tree for a
-      // set to put our object in
-      Item * pTraverse = pItem->mParent;
-      while ( pTraverse != NULL && !pTraverse->isInspectorData() )
-         pTraverse = pTraverse->mParent;
-
-      // found an ancestor who is an inspectorData?
-      pParentSet = pTraverse->isInspectorData() ? dynamic_cast<SimSet*>( pTraverse->getObject() ) : NULL;
-   }
-
-   // Reorder the item and make sure that the children of the item get updated
-   // correctly prev item may be script... so find a prevItem if there is.
-   // We only need to reorder if there you move it above an inspector item.
-   if ( pSimObject != NULL && pParentSet != NULL )
-   {
-      Item * pTraverse = pItem->mNext;
-
-      while(pTraverse)
-      {
-         if (pTraverse->isInspectorData())
-            break;
-         pTraverse = pTraverse->mNext;
-      }
-
-      if (pTraverse && pItem->getObject() &&  pTraverse->getObject())
-         pParentSet->reOrder(pItem->getObject(), pTraverse->getObject());
-   }
-
-   buildVisibleTree();
-}
-void GuiTreeViewCtrl::moveItemDown( S32 itemId )
+void GuiTreeViewCtrl::setBranchesVisible(TreeItem* treeItem, bool isVisible)
 {
 {
-   GuiTreeViewCtrl::Item* item = getItem( itemId );
-   if ( !item )
-   {
-      Con::errorf( ConsoleLogEntry::General, "GuiTreeViewCtrl::moveItemDown: invalid item id!");
-      return;
-   }
-
-   Item* nextItem = item->mNext;
-   if ( !nextItem )
-   {
-      Con::errorf( ConsoleLogEntry::General, "GuiTreeViewCtrl::moveItemDown: no next sibling?");
-      return;
-   }
-
-   //  Diddle the linked list!
-   if ( nextItem->mNext )
-      nextItem->mNext->mPrevious = item;
-
-   if ( item->mPrevious )
-      item->mPrevious->mNext = nextItem;
-   else if ( item->mParent )
-      item->mParent->mChild = nextItem;
-
-   item->mNext = nextItem->mNext;
-   nextItem->mPrevious = item->mPrevious;
-   item->mPrevious = nextItem;
-   nextItem->mNext = item;
-
-   // And update the simobjects if apppropriate...
-   SimObject * simobj = NULL;
-   if (item->isInspectorData())
-      simobj = item->getObject();
-
-   SimSet *parentSet = NULL;
-
-   // grab the current parentSet if there is any...
-   if(item->mParent->isInspectorData())
-      parentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
-   else
-   {
-      // parent is probably script data so we search up the tree for a
-      // set to put our object in
-      Item * temp = item->mParent;
-      while (!temp->isInspectorData())
-         temp = temp->mParent;
-
-      // found an ancestor who is an inspectorData?
-      parentSet = temp->isInspectorData() ? dynamic_cast<SimSet*>(temp->getObject()) : NULL;
-   }
-
-   // Reorder the item and make sure that the children of the item get updated
-   // correctly prev item may be script... so find a prevItem if there is.
-   // We only need to reorder if there you move it above an inspector item.
-   if (simobj && parentSet)
-   {
-      Item * temp = item->mPrevious;
-
-      while(temp)
-      {
-         if (temp->isInspectorData())
-            break;
-         temp = temp->mPrevious;
-      }
-
-      if (temp && item->getObject() && temp->getObject())
-         parentSet->reOrder(temp->getObject(), item->getObject());
-   }
-
-     buildVisibleTree();
-}
-
-
-
-//------------------------------------------------------------------------------
-
-bool GuiTreeViewCtrl::onWake()
-{
-   if(!Parent::onWake())
-      return false;
-
-   // If destroy on sleep, then we have to give things a chance to rebuild.
-   if(mDestroyOnSleep)
-   {
-      destroyTree();
-      Con::executef(this, 1, "onWake");
-
-      // (Re)build our icon table.
-      const char * res = Con::executef(this, 1, "onDefineIcons");
-
-      // If no icons were defined in script then use defaults.
-      if(!(dAtob(res)))
-      {
-         buildIconTable(NULL);
-      }
-   }
-
-   // Update the row height, if appropriate.
-   // DEPRECIATED
-   /*
-   if(mProfile->mAutoSizeHeight)
-   {
-      // make sure it's big enough for both bitmap AND font...
-      mItemHeight = getMax((S32)mFont->getHeight(), (S32)mProfile->mBitmapArrayRects[0].extent.y);
-   }
-   */
-
-   return true;
-}
-
-void GuiTreeViewCtrl::onSleep()
-{
-   Parent::onSleep();
-
-   // If appropriate, blast the tree. (We probably rebuild it on wake.)
-   if( mDestroyOnSleep )
-      destroyTree();
-}
-
-bool GuiTreeViewCtrl::buildIconTable(const char * icons)
-{
-   // Icons should be designated by the bitmap/png file names (minus the file extensions)
-   // and separated by colons (:). This list should be synchronized with the Icons enum.
-
-   // This is an abominal piece of code. -- BJG
-   if (!icons)
-   {
-      icons =  "^Sandbox/gui/images/default:"
-               "^Sandbox/gui/images/simgroup:"
-               "^Sandbox/gui/images/simgroupClosed:"
-               "^Sandbox/gui/images/simgroupSelected:"
-               "^Sandbox/gui/images/simgroupSelectedClosed:"
-               "^Sandbox/gui/images/Camera:"
-               "^Sandbox/gui/images/iconVisible:"
-               "^Sandbox/gui/images/iconLocked:";
-   }
-
-   // Figure the size of the buffer we need...
-   const char* temp = dStrchr( icons, '\t' );
-   U32 textLen = temp ? (U32)( temp - icons ) : dStrlen( icons );
-
-   // Allocate temporary space.
-   FrameAllocatorMarker txtBuff;
-   char* drawText = (char*)txtBuff.alloc(sizeof(char) * (textLen + 4));
-   dStrncpy( drawText, icons, textLen );
-   drawText[textLen] = '\0';
-
-   U32 numIcons = 0;
-   char *buf = (char*)txtBuff.alloc(sizeof(char) * 256);
-   char* token = dStrtok( drawText, ":" );
-
-   // Count the number of icons and store them.
-   while (token && numIcons < MaxIcons)
-   {
-      dSprintf( buf, sizeof( char ) * 256, "%s", token );
-      mIconTable[numIcons] = TextureHandle( buf, TextureHandle::BitmapKeepTexture );
-      token = dStrtok( NULL, ":" );
-      numIcons++;
-   }
-
-   return true;
-}
-
-//------------------------------------------------------------------------------
-
-void GuiTreeViewCtrl::onPreRender()
-{
-   Parent::onPreRender();
-
-   S32 nRootItemId = getFirstRootItem();
-   if( nRootItemId == 0 )
-      return;
-
-   Item *pRootItem = getItem( nRootItemId );
-   if( pRootItem == NULL )
-      return;
-
-   mTicksPassed++;
-
-   if( mTicksPassed > mTreeRefreshInterval ) 
-   {
-      // Update every render in case new objects are added
-      buildVisibleTree();
-
-      mTicksPassed = 0;
-   }
-
-}
-
-//------------------------------------------------------------------------------
-
-bool GuiTreeViewCtrl::hitTest(const Point2I & pnt, Item* & item, BitSet32 & flags)
-{
-
-   // Initialize some things.
-   const Point2I pos = globalToLocalCoord(pnt);
-   flags.clear();
-   item = 0;
-
-   // get the hit cell
-   Point2I cell((pos.x < 0 ? -1 : pos.x / mCellSize.x),
-                (pos.y < 0 ? -1 : pos.y / mCellSize.y));
-
-   // valid?
-   if((cell.x < 0 || cell.x >= mSize.x) ||
-      (cell.y < 0 || cell.y >= mSize.y))
-      return false;
-
-   flags.set(OnRow);
-
-   // Grab the cell.
-   if (cell.y >= mVisibleItems.size())
-      return false; //Invalid cell, so don't do anything
-
-   item = mVisibleItems[cell.y];
-
-   S32 min = mTabSize * item->mTabLevel;
-
-   // left of icon/text?
-   if(pos.x < min)
-   {
-      flags.set(OnIndent);
-      return true;
-   }
-
-   // check image
-   S32 image = BmpChild;
-
-   if(item->isInspectorData())
-      image = item->isExpanded() ? BmpExp : BmpCon;
-   else
-      image = item->isExpanded() ? item->getExpandedImage() : item->getNormalImage();
-
-   if((image >= 0) && (image < mProfile->mBitmapArrayRects.size()))
-      min += mProfile->mBitmapArrayRects[image].extent.x;
-
-   // Is it on the image?
-   if(pos.x < min)
-   {
-      flags.set(OnImage);
-      return(true);
-   }
-
-   // Bump over to the start of the text.
-   min += mTextOffset;
-
-   // Check against the text.
-   FrameAllocatorMarker txtAlloc;
-   U32 bufLen = item->getDisplayTextLength();
-   char *buf = (char*)txtAlloc.alloc(bufLen);
-   item->getDisplayText(bufLen, buf);
-
-   min += mProfile->getFont(mFontSizeAdjust)->getStrWidth(buf);
-   if(pos.x < min)
-      flags.set(OnText);
-
-   return true;
-}
-
-void GuiTreeViewCtrl::setInstantGroup(SimObject * obj)
-{
-   // make sure we're talking about a group.
-   SimGroup * grp = dynamic_cast<SimGroup*>(obj);
-
-   // Set the instant group variable.
-   if(grp)
-   {
-      Con::setVariable("instantGroup", grp->getIdString());
-
-    // Notify Script 
-      Con::executef(this,2,"onInstantGroupSelected",Con::getIntArg(grp->getId()));
-   }
-}
-
-void GuiTreeViewCtrl::syncSelection()
-{
-   // for each visible item check to see if it is on the mSelected list.
-   // if it is then make sure that it is on the mSelectedItems list as well.
-   for (S32 i = 0; i < mVisibleItems.size(); i++) 
-   {
-      for (S32 j = 0; j < mSelected.size(); j++) 
-      {
-         if (mVisibleItems[i]->mId == mSelected[j]) 
-         {
-            // check to see if it is on the visible items list.
-            bool addToSelectedItems = true;
-            for (S32 k = 0; k < mSelectedItems.size(); k++) 
-            {
-               if (mSelected[j] == mSelectedItems[k]->mId) 
-               {
-                  // don't add it
-                  addToSelectedItems = false;
-               }
-            }
-            if (addToSelectedItems) 
-            {
-               mVisibleItems[i]->mState.set(Item::Selected, true);
-               mSelectedItems.push_front(mVisibleItems[i]);
-               break;
-            }
-         } 
-         else if (mVisibleItems[i]->isInspectorData()) 
-         {
-            if (mVisibleItems[i]->getObject() && mVisibleItems[i]->getObject()->getId() == mSelected[j]) 
-            {
-               // check to see if it is on the visible items list.
-               bool addToSelectedItems = true;
-               for (S32 k = 0; k < mSelectedItems.size(); k++) 
-               {
-                  if (mSelectedItems[k]->isInspectorData()) 
-                  {
-                     if (mSelected[j] == mSelectedItems[k]->getObject()->getId()) 
-                     {
-                        // don't add it
-                        addToSelectedItems = false;
-                     }
-                  } 
-                  else 
-                  {
-                     if (mSelected[j] == mSelectedItems[k]->mId) 
-                     {
-                        // don't add it
-                        addToSelectedItems = false;
-                     }
-                  }
-               }
-               if (addToSelectedItems) 
-               {
-                  mVisibleItems[i]->mState.set(Item::Selected, true);
-                  mSelectedItems.push_front(mVisibleItems[i]);
-                  break;
-               }
-            }
-         }
-
-      }
-
-   }
-}
-
-void GuiTreeViewCtrl::removeSelection(S32 itemId)
-{
-   if (mDebug)
-      Con::printf("removeSelection called");
-   Item * item = getItem(itemId);
-
-   // the item may have been selected at one point but was never created/visible in the tree
-   // so remove it.
-   for (S32 j = 0; j <mSelected.size(); j++) 
-   {
-      if (item) 
-      {
-         if (item->isInspectorData()) 
-         {
-            if (item->getObject() && item->getObject()->getId() == mSelected[j]) 
-            {
-               mSelected.erase(j);
-               break;
-            }
-         }
-      }
-
-      if (mSelected[j] == itemId) 
-      {
-         mSelected.erase(j);
-         break;
-      }
-   }
-
-   if(!item)
-   {
-      // maybe what we were passed wasn't an item id but an object id.
-      for (S32 i = 0; i <mItems.size(); i++) 
-      {
-         if (mItems[i] != NULL) 
-         {
-            if (mItems[i]->isInspectorData()) 
-            {
-               if (mItems[i]->getObject()->getId() == itemId) 
-               {
-                  item = mItems[i];
-                  break;
-               }
-            }
-         }
-      }
-
-      if (!item) 
-      {
-         //Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::removeSelection: invalid item id! Perhaps it isn't visible yet");
-         return;
-      }
-   }
-
-   item->mState.set(Item::Selected, false);
-   
-   for (S32 i = 0; i < mSelectedItems.size(); i++) 
-   {
-      if (mSelectedItems[i] == item) 
-      {
-         mSelectedItems.erase(i);
-         break;
-      }
-   }
-
-   // Callback - onRemoveSelection( %itemID )
-   if (item->getObject())
-      Con::executef(this, 2, "onRemoveSelection", Con::getIntArg(item->getObject()->getId()));
-}
-
-void GuiTreeViewCtrl::addSelection(S32 itemId)
-{
-   if (mDebug)
-      Con::printf("addSelection called");
-
-   Item * item = getItem(itemId);
-
-   S32 itr; // used to loop thru items
-   bool foundMatch = false;
-
-   if(!item)
-   {
-      // maybe what we were passed wasn't an item id but an object id.
-      for (itr = 0; itr <mItems.size(); itr++)
-      {
-         if (mItems[itr] != NULL)
-         {
-            if (mItems[itr]->isInspectorData())
-            {
-               if ( mItems[itr]->getObject() && mItems[itr]->getObject()->getId() == itemId)
-               {
-                  item = mItems[itr];
-                  //looks like it is. check to see if it is on the list
-                  bool alreadySelected = false;
-                  Vector<Item *>::iterator i;
-                  for(i = mSelectedItems.begin(); i != mSelectedItems.end(); i++)
-                  {
-                     if (*(i) == item)
-                     {
-                        //already a selected item which means this call should be ignored
-                        alreadySelected = true;
-                        return;
-                     }
-                  }
-                  break;
-               }
-            }
-         }
-      }
-
-      if (!item)
-      {
-         // Do we want to allow more than one selected item?
-         if( !mMultipleSelections )
-            clearSelection();
-
-         // rdbnote: this isn't going to be very fast, but we need to make sure we're not adding things to this list twice!!
-         // in a perfect world, code would be cleanly written enough to not have this problem..
-         foundMatch = false;
-         for (itr = 0; itr < mSelected.size(); itr++)
-         {
-            if (mSelected[itr] == itemId)
-               foundMatch = true;
-         }
-
-         //Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::addSelection: invalid item id! Perhaps it isn't visible yet.");
-         if (!foundMatch)
-            mSelected.push_front(itemId);
-
-         return;
-      }
-   }
-   else
-   {
-      // Do we want to allow more than one selected item?
-      if( !mMultipleSelections )
-         clearSelection();
-
-      // rdbnote: this isn't going to be very fast, but we need to make sure we're not adding things to this list twice!!
-      // in a perfect world, code would be cleanly written enough to not have this problem..
-      foundMatch = false;
-      for (itr = 0; itr < mSelected.size(); itr++)
-      {
-         if (mSelected[itr] == itemId)
-            foundMatch = true;
-      }
-
-      // regardless of whether we found an item, we keep track of the Id that was passed
-      // as the item may simply not have been created/visible yet.
-      if (!foundMatch)
-         mSelected.push_front(itemId);
-   }
-
-   item->mState.set(Item::Selected, true);
-
-   // Also make it so we can see it if we didn't already.
-   scrollVisible(item);
-
-   // Do we want to allow more than one selected item?
-   //if( !mMultipleSelections )
-   //   clearSelection();
-
-   // rdbnote: this isn't going to be very fast, but we need to make sure we're not adding things to this list twice!!
-   // in a perfect world, code would be cleanly written enough to not have this problem..
-   foundMatch = false;
-   for (itr = 0; itr < mSelectedItems.size(); itr++)
-   {
-      if (mSelectedItems[itr]->mId == item->mId)
-         foundMatch = true;
-   }
-
-   if (!foundMatch)
-      mSelectedItems.push_front(item);
-
-   // Callback - onAddSelection( %itemID )
-   if (item->getObject())
-      Con::executef(this, 2, "onAddSelection", Con::getIntArg(item->getObject()->getId()));
-}
-
-
-void GuiTreeViewCtrl::onItemSelected( Item *item )
-{
-   char buf[16];
-   dSprintf(buf, 16, "%d", item->mId);
-   if (item->isInspectorData())
-   {
-       if(item->getObject())
-      Con::executef(this, 2, "onSelect", Con::getIntArg(item->getObject()->getId()));
-      if (!(item->isParent()) && item->getObject())
-         Con::executef(this, 2, "onInspect", Con::getIntArg(item->getObject()->getId()));
-   }
-   else
-   {
-      Con::executef(this, 2, "onSelect", buf);
-      if (!(item->isParent()))
-         Con::executef(this, 2, "onInspect", buf);
-   }
-   mSelectedItem = item->getID();
-}
-
-bool GuiTreeViewCtrl::setItemSelected(S32 itemId, bool select)
-{
-   Item * item = getItem(itemId);
-
-   if (select)
-   {
-      if (mDebug) Con::printf("setItemSelected called true");
-
-      // rdbnote: this isn't going to be very fast, but we need to make sure we're not adding things to this list twice!!
-      // in a perfect world, code would be cleanly written enough to not have this problem..
-      bool foundMatch = false;
-      for (S32 itr = 0; itr < mSelected.size(); itr++)
-      {
-         if (mSelected[itr] == itemId)
-            foundMatch = true;
-      }
-
-      if (!foundMatch)
-         mSelected.push_front(itemId);
-   }
-   else
-   {
-      if (mDebug) Con::printf("setItemSelected called false");
-
-      // remove it from the mSelected list
-      for (S32 j = 0; j <mSelected.size(); j++)
-      {
-         if (item)
-         {
-            if (item->isInspectorData())
-            {
-               if (item->getObject())
-               {
-                  if(item->getObject()->getId() == mSelected[j])
-                  {
-                     mSelected.erase(j);
-                     break;
-                  }
-               }
-               else
-               {
-                  // Zombie, kill it!
-                  mSelected.erase(j);
-                  j--;
-               }
-            }
-         }
-
-         if (mSelected[j] == itemId)
-         {
-            mSelected.erase(j);
-            break;
-         }
-      }
-   }
-
-   if(!item)
-   {
-      // maybe what we were passed wasn't an item id but an object id.
-      for (S32 i = 0; i <mItems.size(); i++)
-      {
-         if (mItems[i] != NULL)
-         {
-            if (mItems[i]->isInspectorData())
-            {
-               if (mItems[i]->getObject())
-               {
-                  if(mItems[i]->getObject()->getId() == itemId)
-                  {
-                     item = mItems[i];
-                     break;
-                  }
-               }
-               else
-               {
-                  // It's a zombie, blast it.
-                  mItems.erase(i);
-                  i--;
-               }
-            }
-         }
-      }
-
-      if (!item)
-      {
-         //Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::setItemSelected: invalid item id! Perhaps it isn't visible yet.");
-         return(false);
-      }
-   }
-
-   if(select)
-   {
-      addSelection( item->mId );
-      onItemSelected( item );
-   }
-   else
-   {
-      // unselect the item, if it's present.
-      item->mState.set(Item::Selected, false);
-
-      if (item->isInspectorData() && item->getObject())
-         Con::executef(this, 2, "onUnSelect", Con::getIntArg(item->getObject()->getId()));
-      else
-         Con::executef(this, 2, "onUnSelect", Con::getIntArg(item->mId));
-
-      // remove it from the selected items list
-      for (S32 i = 0; i < mSelectedItems.size(); i++)
-      {
-         if (mSelectedItems[i] == item)
-         {
-            mSelectedItems.erase(i);
-            break;
-         }
-      }
-   }
-
-   setUpdate();
-   return(true);
-}
-
-// Given an item's index in the selection list, return its itemId
-S32 GuiTreeViewCtrl::getSelectedItem(S32 index)
-{
-   if(index >= 0 && index < getSelectedItemsCount())
-   {
-      return mSelectedItems[index]->mId;
-   }
-
-   return -1;
-}
-bool GuiTreeViewCtrl::setItemExpanded(S32 itemId, bool expand)
-{
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::setItemExpanded: invalid item id!");
-      return(false);
-   }
-
-   if(item->isExpanded() == expand)
-      return(true);
-
-   // expand parents
-   if(expand)
-   {
-      while(item)
-      {
-         if(item->mState.test(Item::VirtualParent))
-            onVirtualParentExpand(item);
-
-         item->setExpanded(true);
-         item = item->mParent;
-      }
-   }
-   else
-   {
-      if(item->mState.test(Item::VirtualParent))
-         onVirtualParentCollapse(item);
-
-      item->setExpanded(false);
-   }
-   return(true);
-}
-
-
-bool GuiTreeViewCtrl::setItemValue(S32 itemId, StringTableEntry Value)
-{
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::setItemValue: invalid item id!");
-      return(false);
-   }
-
-   item->setValue( ( Value ) ? Value : "" );
-
-   return(true);
-}
-
-const char * GuiTreeViewCtrl::getItemText(S32 itemId)
-{
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getItemText: invalid item id!");
-      return("");
-   }
-
-   return(item->getText() ? item->getText() : "");
-}
-
-const char * GuiTreeViewCtrl::getItemValue(S32 itemId)
-{
-   Item * item = getItem(itemId);
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getItemValue: invalid item id!");
-      return("");
-   }
-
-   if(item->mState.test(Item::InspectorData))
-   {
-      // If it's InspectorData, we let people use this call to get an object reference.
-      return item->mInspectorInfo.mObject->getIdString();
-   }
-   else
-   {
-      // Just return the script value...
-      return(item->getValue() ? item->getValue() : "");
-   }
-}
-
-bool GuiTreeViewCtrl::editItem( S32 itemId, const char* newText, const char* newValue )
-{
-   Item* item = getItem( itemId );
-   if ( !item )
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::editItem: invalid item id!");
-      return false;
-   }
-
-   if ( item->mState.test(Item::InspectorData) )
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::editItem: item %d is inspector data and may not be modified!", itemId);
-      return false;
-   }
-
-   delete [] item->getText();
-   item->setText (new char[dStrlen( newText ) + 1]);
-   dStrcpy( item->getText(), newText );
-
-   delete [] item->getValue();
-   item->setValue( new char[dStrlen( newValue ) + 1] );
-   dStrcpy( item->getValue(), newValue );
-
-   // Update the widths and such:
-   buildVisibleTree();
-   return true;
-}
-
-void GuiTreeViewCtrl::deleteSelection()
-{
-   Con::executef(this, 1, "onDeleteSelection");
-
-   if (mSelectedItems.empty())
-   {
-      for (S32 i = 0; i < mSelected.size(); i++)
-      {
-         S32 objectId = mSelected[i];
-
-         // find the object
-         SimObject* obj = Sim::findObject(objectId);
-         obj->deleteObject();
-      }
-   }
-   else
-   {
-      Vector<Item*> delSelection;
-      delSelection = mSelectedItems;
-      mSelectedItems.clear();
-      while (!delSelection.empty())
-      {
-         Item * item = delSelection.front();
-         setItemSelected(item->mId,false);
-         if ( item->mParent )
-            deleteItem( item );
-         
-         delSelection.pop_front();      
-      }
-   }
-
-   mSelected.clear();
-   mSelectedItems.clear();
-   Con::executef( this, 1, "onObjectDeleteCompleted");   
-}
-
-//------------------------------------------------------------------------------
-// keyboard movement of items is restricted to just one item at a time
-// if more than one item is selected then movement operations are not performed
-bool GuiTreeViewCtrl::onKeyDown( const GuiEvent& event )
-{
-   if ( !mVisible || !mActive || !mAwake )
-      return true;
-
-   // All the keyboard functionality requires a selected item, so if none exists...
-
-   // Deal with enter and delete
-   if ( event.modifier == 0 )
-   {
-      if ( event.keyCode == KEY_RETURN )
-      {
-         if ( mAltConsoleCommand[0] )
-            Con::evaluate( mAltConsoleCommand );
-         return true;
-      }
-
-      if ( event.keyCode == KEY_DELETE && mDeleteObjectAllowed )
-      {
-         // Don't delete the root!
-         if (mSelectedItems.empty())
-            return true;
-
-         //this may be fighting with the world editor delete
-         deleteSelection();
-         return true;
-      }
- 
-      //call a generic bit of script that will let the subclass know that a key was pressed
-      Con::executef(this, 3, "onKeyDown", Con::getIntArg(event.modifier), Con::getIntArg(event.keyCode));
-   }
-
-   // only do operations if only one item is selected
-   if ( mSelectedItems.empty() || (mSelectedItems.size() > 1))
-      return true;
-
-   Item* item = mSelectedItems.first();
-
-   if ( !item )
-      return true;
-
-   // The Alt key lets you move items around!
-   if ( mFlags.test(IsEditable) && event.modifier & SI_ALT )
-   {
-      switch ( event.keyCode )
-      {
-      case KEY_UP:
-         // Move us up.
-         if ( item->mPrevious )
-         {
-            moveItemUp( item->mId );
-            scrollVisible(item);
-         }
-         return true;
-
-      case KEY_DOWN:
-         // Move the item under us up.
-         if ( item->mNext )
-         {
-            moveItemUp( item->mNext->mId );
-            scrollVisible(item);
-         }
-         return true;
-
-      case KEY_LEFT:
-         if ( item->mParent )
-         {
-            if ( item->mParent->mParent )
-            {
-               // Ok, we have both an immediate parent, and a grandparent.
-
-               // The goal of left-arrow alt is to become the child of our
-               // grandparent, ie, to become a sibling of our parent.
-
-               // First, unlink item from its siblings.
-               if ( item->mPrevious )
-                  item->mPrevious->mNext = item->mNext;
-               else
-                  item->mParent->mChild = item->mNext;
-
-               if ( item->mNext )
-                  item->mNext->mPrevious = item->mPrevious;
-
-               // Now, relink as the next sibling of our parent.
-               item->mPrevious = item->mParent;
-               item->mNext = item->mParent->mNext;
-
-               // If there was already a next sibling, deal with that case.
-               if ( item->mNext )
-                  item->mNext->mPrevious = item;
-               item->mParent->mNext = item;
-
-               // Snag the current parent set if any...
-               SimSet *parentSet = NULL;
-
-               if(item->mParent->isInspectorData())
-                  parentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
-               else
-               {
-                  // parent is probably script data so we search up the tree for a
-                  // set to put our object in
-                  Item * temp = item->mParent;
-                  while (!temp->isInspectorData())
-                     temp = temp->mParent;
-                  // found a ancestor who is an inspectorData
-                  if (temp->isInspectorData())
-                     parentSet = dynamic_cast<SimSet*>(temp->getObject());
-                  else parentSet = NULL;
-               }
-
-               // Get our active SimObject if any
-               SimObject *simObj = NULL;
-               if(item->isInspectorData())
-                  simObj = item->getObject();
-
-               // Remove from the old parentset...
-               if(simObj && parentSet) {
-                  if (parentSet->size()>0)
-                  {
-                     SimObject *lastObject = parentSet->last();
-                     parentSet->removeObject(simObj);
-                     parentSet->reOrder(lastObject);
-                  } else
-                     parentSet->removeObject(simObj);
-               }
-
-               // And finally, update our item
-               item->mParent = item->mParent->mParent;
-
-               // Snag the newparent set if any...
-               SimSet *newParentSet = NULL;
-
-               if(item->mParent->isInspectorData())
-                  newParentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
-               else
-               {
-                  // parent is probably script data so we search up the tree for a
-                  // set to put our object in
-                  Item * temp = item->mParent;
-                  while (!temp->isInspectorData())
-                     temp = temp->mParent;
-                  // found a ancestor who is an inspectorData
-                  if (temp->isInspectorData())
-                     newParentSet = dynamic_cast<SimSet*>(temp->getObject());
-                  else newParentSet = NULL;
-               }
-               if(simObj && newParentSet)
-               {
-
-                  newParentSet->addObject(simObj);
-                  Item * temp = item->mNext;
-                  // item->mNext may be script, so find an inspector item to reorder with if any
-
-                  if (temp) {
-                     do {
-                        if (temp->isInspectorData())
-                           break;
-                        temp = temp->mNext;
-                     } while (temp);
-                     if (temp && item->getObject() && temp->getObject()) //do we still have a item->mNext? If not then don't bother reordering
-                        newParentSet->reOrder(item->getObject(), temp->getObject());
-                  }
-
-               } else if (!simObj&&newParentSet) {
-                  // our current item is script data. but it may have children who
-                  // is inspector data who need an updated set
-                  if (item->mChild)
-                     inspectorSearch(item->mChild, item, parentSet, newParentSet);
-
-               }
-
-               // And update everything hurrah.
-               buildVisibleTree();
-               scrollVisible(item);
-            }
-         }
-         return true;
-
-      case KEY_RIGHT:
-         if ( item->mPrevious )
-         {
-            // Make the item the last child of its previous sibling.
-
-            // First, unlink from the current position in the list
-            item->mPrevious->mNext = item->mNext;
-
-            if ( item->mNext )
-               item->mNext->mPrevious = item->mPrevious;
-
-            // Get the object we're poking with.
-            SimObject *simObj = NULL;
-            SimSet *parentSet = NULL;
-            if(item->isInspectorData())
-               simObj = item->getObject();
-            if(item->mParent->isInspectorData())
-               parentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
-            else {
-               // parent is probably script data so we search up the tree for a
-               // set to put our object in
-               Item * temp = item->mParent;
-               while (!temp->isInspectorData())
-                  temp = temp->mParent;
-               // found an ancestor who is an inspectorData
-               if (temp->isInspectorData())
-                  parentSet = dynamic_cast<SimSet*>(temp->getObject());
-            }
-
-            // If appropriate, remove from the current SimSet.
-            if(parentSet && simObj) {
-               if (parentSet->size()>0)
-               {
-                  SimObject *lastObject = parentSet->last();
-                  parentSet->removeObject(simObj);
-                  parentSet->reOrder(lastObject);
-               } else
-                  parentSet->removeObject(simObj);
-            }
-
-
-            // Now, make our previous sibling our parent...
-            item->mParent = item->mPrevious;
-            item->mNext = NULL;
-
-            // And sink us down to the end of its siblings, if appropriate.
-            if ( item->mParent->mChild )
-            {
-               Item* temp = item->mParent->mChild;
-               while ( temp->mNext )
-                  temp = temp->mNext;
-
-               temp->mNext = item;
-               item->mPrevious = temp;
-            }
-            else
-            {
-               // only child...<sniff>
-               item->mParent->mChild = item;
-               item->mPrevious = NULL;
-            }
-
-            // Make sure the new parent is expanded:
-            if ( !item->mParent->mState.test( Item::Expanded ) )
-               setItemExpanded( item->mParent->mId, true );
-
-            // Snag the new parent simset if any.
-            SimSet *newParentSet = NULL;
-
-            // new parent might be script. so figure out what set we need to add it to.
-            if(item->mParent->isInspectorData())
-               newParentSet = dynamic_cast<SimSet*>(item->mParent->getObject());
-            else
-            {
-               // parent is probably script data so we search up the tree for a
-               // set to put our object in
-               if (mDebug) Con::printf("oh nos my parent is script!");
-               Item * temp = item->mParent;
-               while (!temp->isInspectorData())
-                  temp = temp->mParent;
-               // found a ancestor who is an inspectorData
-               if (temp->isInspectorData())
-                  newParentSet = dynamic_cast<SimSet*>(temp->getObject());
-               else newParentSet = NULL;
-            }
-            // Add the item's SimObject to the new parent simset, at the end.
-            if(newParentSet && simObj)
-               newParentSet->addObject(simObj);
-            else if (!simObj&&newParentSet&&parentSet) {
-               // our current item is script data. but it may have children who
-               // is inspector data who need an updated set
-
-               if (item->mChild) {
-                  inspectorSearch(item->mChild, item, parentSet, newParentSet);
-               }
-
-            }
-            scrollVisible(item);
-         }
-         return true;
-      }
-   }
-
-   // Explorer-esque navigation...
-   switch( event.keyCode )
-   {
-   case KEY_UP:
-      // Select previous visible item:
-      if ( item->mPrevious )
-      {
-         item = item->mPrevious;
-         while ( item->isParent() && item->isExpanded() )
-         {
-            item = item->mChild;
-            while ( item->mNext )
-               item = item->mNext;
-         }
-         setItemSelected(mSelectedItems.first()->mId,false);
-         setItemSelected( item->mId, true );
-         scrollVisible(item);
-         return true;
-      }
-
-      // or select parent:
-      if ( item->mParent )
-      {
-         setItemSelected(mSelectedItems.first()->mId,false);
-         setItemSelected( item->mParent->mId, true );
-         scrollVisible(item->mParent);
-         return true;
-      }
-
-      return false;
-      break;
-
-   case KEY_DOWN:
-      // Selected child if it is visible:
-      if ( item->isParent() && item->isExpanded() )
-      {
-         setItemSelected(mSelectedItems.first()->mId,false);
-         setItemSelected( item->mChild->mId, true );
-         scrollVisible(item->mChild);
-         return true;
-      }
-      // or select next sibling (recursively):
-      do
-      {
-         if ( item->mNext )
-         {
-            setItemSelected(mSelectedItems.first()->mId,false);
-            setItemSelected(item->mNext->mId, true );
-            scrollVisible(item->mNext);
-            return true;
-         }
-
-         item = item->mParent;
-      } while ( item );
-
-      return false;
-      break;
-
-   case KEY_LEFT:
-      // Contract current menu:
-      if ( item->isExpanded() )
-      {
-         setItemExpanded( item->mId, false );
-         scrollVisible(item);
-         return true;
-      }
-      // or select parent:
-      if ( item->mParent )
-      {
-         setItemSelected(mSelectedItems.first()->mId,false);
-         setItemSelected( item->mParent->mId, true );
-         scrollVisible(item->mParent);
-         return true;
-      }
-
-      return false;
-      break;
-
-   case KEY_RIGHT:
-      // Expand selected item:
-      if ( item->isParent() )
-      {
-         if ( !item->isExpanded() )
-         {
-            setItemExpanded( item->mId, true );
-            scrollVisible(item);
-            return true;
-         }
-
-         // or select child:
-         setItemSelected(mSelectedItems.first()->mId,false);
-         setItemSelected( item->mChild->mId, true );
-         scrollVisible(item->mChild);
-         return true;
-      }
-
-      return false;
-      break;
-   }
-
-   // Not processed, so pass the event on:
-   return Parent::onKeyDown( event );
-}
-
-
-
-//------------------------------------------------------------------------------
-// on mouse up look at the current item and check to see if it is valid
-// to move the selected item(s) to it.
-void GuiTreeViewCtrl::onTouchUp(const GuiEvent &event)
-{
-   if( !mActive || !mAwake || !mVisible )
-      return;
-
-   mouseUnlock();
-
-   if ( mSelectedItems.empty())
-   {
-      mDragMidPoint = NomDragMidPoint;
-      return;
-   }
-   
-   if (!mMouseDragged) 
-      return;
-   else
-      mMouseDragged = false;
-
-   Item* newItem = NULL;
-   Item* newItem2 = NULL;
-
-   if (mFlags.test(IsEditable))
-   {
-      Parent::onTouchMove( event );
-      if (mOldDragY != mMouseOverCell.y)
-      {
-
-         mOldDragY = mMouseOverCell.y;
-         BitSet32 hitFlags = 0;
-         if ( !hitTest( event.mousePoint, newItem2, hitFlags ) )
-         {
-            mDragMidPoint = NomDragMidPoint;
-            return;
-         }
-
-         newItem2->mState.clear(Item::MouseOverBmp | Item::MouseOverText );
-         
-         // if the newItem isn't in the mSelectedItemList then continue.
-
-         Vector<Item *>::iterator k;
-         for(k = mSelectedItems.begin(); k != mSelectedItems.end(); k++) 
-         {
-            newItem = newItem2;
-            
-            if (*(k) == newItem) 
-            {
-               mDragMidPoint = NomDragMidPoint;
-               return;
-            }
-
-            Item * temp = *(k);
-            Item * grandpaTemp = newItem->mParent;
-            
-            // grandpa check, kick out if an item would be its own ancestor
-            while (grandpaTemp)
-            {
-               if (temp == grandpaTemp)
-               {
-                  if (mDebug)
-                  {
-                     Con::printf("grandpa check");
-
-                     if (temp->isInspectorData())
-                        Con::printf("temp's name: %s",temp->getObject()->getName());
-
-                     if (grandpaTemp->isInspectorData())
-                        Con::printf("grandpa's name: %s",grandpaTemp->getObject()->getName());
-                  }
-
-                  mDragMidPoint = NomDragMidPoint;
-                  return;
-               }
-
-               grandpaTemp = grandpaTemp->mParent;
-            }
-         }
-
-
-         for (S32 i = 0; i <mSelectedItems.size();i++) 
-         {
-            newItem = newItem2;
-            Item * item = mSelectedItems[i];
-
-            if (mDebug) Con::printf("----------------------------");
-         
-            // clear old highlighting of the item
-            item->mState.clear(Item::MouseOverBmp | Item::MouseOverText );
-
-            // move the selected item to the newItem
-            Item* oldParent = item->mParent;
-            // Snag the current parent set if any for future reference
-            SimSet *parentSet = NULL;
-
-            if(oldParent->isInspectorData())
-               parentSet = dynamic_cast<SimSet*>(oldParent->getObject());
-            else 
-            {
-               // parent is probably script data so we search up the tree for a
-               // set to put our object in
-               Item * temp = oldParent;
-               while (temp) 
-               {
-                  if (temp->isInspectorData())
-                     break;
-                  temp = temp->mParent;
-               }
-               // found an ancestor who is an inspectorData
-               if (temp) 
-               {
-                  if (temp->isInspectorData())
-                     parentSet = dynamic_cast<SimSet*>(temp->getObject());
-               }
-            }
-
-            // unlink from the current position in the list
-            unlinkItem(item);
-
-            // update the parent's children
-
-            // check if we an only child
-            if (item->mParent->mChild == item)
-            {
-               if (item->mNext)
-                  item->mParent->mChild = item->mNext;
-               else
-                  item->mParent->mChild = NULL;
-            }
-
-            if (mDragMidPoint != NomDragMidPoint)
-            {
-
-               //if it is below an expanded tree, place as last item in the tree
-               //if it is below a parent who isn't expanded put below it
-
-               // position the item above or below another item
-               if (mDragMidPoint == AbovemDragMidPoint)
-               {
-                  // easier to treat everything as "Below the mDragMidPoint" so make some adjustments
-                  if (mDebug) Con::printf("adding item above mDragMidPoint");
-
-                  // above the mid point of an item, so grab either the parent
-                  // or the previous sibling
-
-                  // does the item have a previous sibling?
-                  if (newItem->mPrevious)
-                  {
-                     newItem = newItem->mPrevious;
-
-                     if (mDebug) Con::printf("treating as if below an item that isn't expanded");
-
-                     // otherwise add below that item as a sibling
-                     item->mParent = newItem->mParent;
-                     item->mPrevious = newItem;
-                     item->mNext = newItem->mNext;
-                     if (newItem->mNext)
-                        newItem->mNext->mPrevious = item;
-                     newItem->mNext = item;
-                  } 
-                  else
-                  {
-                     if (mDebug) Con::printf("treating as if adding below the parent of the item");
-
-                     // instead we add as the first item below the newItem's parent
-                     item->mParent = newItem->mParent;
-                     item->mNext = newItem;
-                     item->mPrevious = NULL;
-                     newItem->mPrevious = item;
-                     item->mParent->mChild = item;
-
-                  }
-               }
-               else if (mDragMidPoint == BelowmDragMidPoint)
-               {
-                  if ((newItem->isParent())&&(newItem->isExpanded()))
-                  {
-                     if (mDebug) Con::printf("adding item to an expanded parent below the mDragMidPoint");
-
-                     item->mParent = newItem;
-
-                     // then add the new item as a child
-                     item->mNext = newItem->mChild;
-                     if (newItem->mChild)
-                        newItem->mChild->mPrevious = item;
-                     item->mParent->mChild = item;
-                     item->mPrevious = NULL;
-                  }
-                  else if ((!newItem->mNext)&&(newItem->mParent)&&(newItem->mParent->mParent)) 
-                  {
-                     // add below it's parent.
-                     if (mDebug) Con::printf("adding below a tree");
-
-                     item->mParent = newItem->mParent->mParent;
-                     item->mNext = newItem->mParent->mNext;
-                     item->mPrevious = newItem->mParent;
-
-                     if (newItem->mParent->mNext)
-                        newItem->mParent->mNext->mPrevious = item;
-
-                     newItem->mParent->mNext = item;
-                  }
-                  else 
-                  {
-                     // adding below item not as a child
-                     if (mDebug) Con::printf("adding item below the mDragMidPoint of an item");
-
-                     item->mParent = newItem->mParent;
-                     // otherwise the item is a sibling
-                     if (newItem->mNext)
-                        newItem->mNext->mPrevious = item;
-                     item->mNext = newItem->mNext;
-                     item->mPrevious = newItem;
-                     newItem->mNext = item;
-                  }
-               }
-            }
-            // if we're not allowed to add to items, then try to add to the parent of the hit item.
-            // if we are, just add to the item we hit.
-            else 
-            {
-               if (mDebug) 
-               {
-                  if (item->isInspectorData() && item->getObject())
-                     Con::printf("Item: %i",item->getObject()->getId());
-                  if (newItem->isInspectorData() && newItem->getObject())
-                     Con::printf("Parent: %i",newItem->getObject()->getId());
-                  Con::printf("dragged onto an item");
-               }
-               
-               // if the hit item is not already a group, and we're not allowed to drag to items, 
-               // then try to add to the parent.
-               if(!mDragToItemAllowed && !newItem->isParent())
-               {
-                   // add to the item's parent.
-                  if(!newItem->mParent || !newItem->mParent->isParent())
-                  {
-                     if(mDebug)
-                        Con::printf("could not find the parent of that item. dragging to an item is not allowed, kicking out.");
-                     mDragMidPoint = NomDragMidPoint;
-                     return;
-                  }
-                  newItem = newItem->mParent;
-               }
-               
-               // new parent is the item in the current cell
-               item->mParent = newItem;
-               
-               // adjust children if any
-               if (newItem->mChild)
-               {
-                  if (mDebug) Con::printf("not the first child");
-                  
-                  // put it at the top of the list (easier to find if there are many children)
-                  if (newItem->mChild)
-                     newItem->mChild->mPrevious = item;
-                  item->mNext = newItem->mChild;
-                  newItem->mChild = item;
-                  item->mPrevious = NULL;
-               }
-               else 
-               {
-                  if (mDebug) Con::printf("first child");
-                  
-                  // only child
-                  newItem->mChild = item;
-                  item->mNext = NULL;
-                  item->mPrevious = NULL;
-               }
-            }
-
-            // expand the item we added to, if it isn't expanded already
-            if ( !item->mParent->mState.test( Item::Expanded ) )
-               setItemExpanded( item->mParent->mId, true );
-
-            //----------------------------------------------------------------
-            // handle objects
-
-            // Get our active SimObject if any
-            SimObject *simObj = NULL;
-            if(item->isInspectorData()) 
-            {
-               simObj = item->getObject();
-            }
-
-            // Remove from the old parentset
-            if((simObj && parentSet)&&(oldParent != item->mParent))
-            {
-               if (mDebug) Con::printf("removing item from old parentset");
-            
-               // hack to get around the way removeObject takes the last item of the set
-               // and moves it into the place of the object we removed
-               if (parentSet->size()>0)
-               {
-                  SimObject *lastObject = parentSet->last();
-                  parentSet->removeObject(simObj);
-                  parentSet->reOrder(lastObject);
-               }
-               else
-               {
-                  parentSet->removeObject(simObj);
-               }
-            }
-
-            // Snag the newparent set if any...
-            SimSet *newParentSet = NULL;
-
-            if(item->mParent->isInspectorData()) 
-            {
-               if (mDebug) Con::printf("getting a new parent set");
-
-               SimObject * tmpObj = item->mParent->getObject();
-               newParentSet = dynamic_cast<SimSet*>(tmpObj);
-            }
-            else
-            {
-               // parent is probably script data so we search up the tree for a
-               // set to put our object in
-               if (mDebug) Con::printf("oh nos my parent is script!");
-
-               Item * temp = item->mParent;
-               while (temp) 
-               {
-                  if (temp->isInspectorData())
-                     break;
-                  temp = temp->mParent;
-               }
-               
-               // found a ancestor who is an inspectorData
-               if (temp) 
-               {
-                  if (temp->isInspectorData())
-                     newParentSet = dynamic_cast<SimSet*>(temp->getObject());
-               } 
-               else 
-               {
-                  newParentSet = NULL;
-               }
-            }
-
-            if(simObj && newParentSet)
-            {
-               if (mDebug) Con::printf("simobj and new ParentSet");
-
-               if (oldParent != item->mParent)
-                  newParentSet->addObject(simObj);
-
-                             //order the objects in the simset according to their
-                             //order in the tree view control
-                             if(!item->mNext)
-                             {
-                                    if(!item->mPrevious) break;
-                                    //bring to the end of the set
-                                    SimObject *prevObject = item->mPrevious->getObject();
-                                    if (prevObject && item->getObject()) 
-                                    {
-                                        newParentSet->reOrder(item->getObject(), prevObject);
-                                    }
-                                }
-                                else
-                                {
-                                    //reorder within the set
-                                    SimObject *nextObject = item->mNext->getObject();
-                                    if(nextObject && item->getObject())
-                                    {
-                                        newParentSet->reOrder(item->getObject(), nextObject);
-                                    }
-                                }
-            } 
-            else if (!simObj&&newParentSet) 
-            {
-               // our current item is script data. but it may have children who
-               // is inspector data who need an updated set
-               if (mDebug) Con::printf("no simobj but new parentSet");
-               if (item->mChild)
-                  inspectorSearch(item->mChild, item, parentSet, newParentSet);
-
-            }
-            else if (simObj&&!newParentSet) 
-            {
-               if (mDebug) Con::printf("simobject and no new parent set");
-            }
-            else
-               if (mDebug) Con::printf("no simobject and no new parent set");
-         }
-
-         // And update everything.
-         scrollVisible(newItem);
-      }
-   }
-
-   mDragMidPoint = NomDragMidPoint;
-}
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::onTouchDragged(const GuiEvent &event)
-{
-    if(!mSupportMouseDragging) return;
-   if( !mActive || !mAwake || !mVisible )
-      return;
-
-   if (mSelectedItems.size() == 0)
-      return;
-   Point2I pt = globalToLocalCoord(event.mousePoint);
-   Parent::onTouchMove(event);
-   mouseLock();
-   mMouseDragged = true;
-   // whats our mDragMidPoint?
-   mCurrentDragCell = mMouseOverCell.y;
-   S32 midpCell = mCurrentDragCell * mItemHeight + (mItemHeight/2);
-   S32 currentY = pt.y;
-   S32 yDiff = currentY-midpCell;
-   S32 variance = (mItemHeight/5);
-   if (mPreviousDragCell >= 0)
-      mVisibleItems[mPreviousDragCell]->mState.clear( Item::MouseOverBmp | Item::MouseOverText );
-
-   if (mAbs(yDiff) > variance)
-   {
-      //above or below an item?
-      if (yDiff < 0)
-         mDragMidPoint = AbovemDragMidPoint;
-      else
-         mDragMidPoint = BelowmDragMidPoint;
-   } else
-   {
-      mDragMidPoint = NomDragMidPoint;
-      // highlight the current item
-      // hittest to detect whether we are on an item
-      // ganked from onMouseMouse
-
-      // used for tracking what our last cell was so we can clear it.
-      mPreviousDragCell = mCurrentDragCell;
-      if (mCurrentDragCell >= 0)
-      {
-
-         Item* item = NULL;
-         BitSet32 hitFlags = 0;
-         if ( !hitTest( event.mousePoint, item, hitFlags ) )
-            return;
-
-         if ( hitFlags.test( OnImage ) )
-            item->mState.set( Item::MouseOverBmp );
-
-         if ( hitFlags.test( OnText ))
-            item->mState.set( Item::MouseOverText );
-
-         // Always redraw the entire mouse over item, since we are distinguishing
-         // between the bitmap and the text:
-         setUpdateRegion( Point2I( mMouseOverCell.x * mCellSize.x, mMouseOverCell.y * mCellSize.y ), mCellSize );
-      }
-   }
-}
-
-void GuiTreeViewCtrl::onMiddleMouseDown(const GuiEvent & event)
-{
-   //for debugging items
-   if (mDebug) {
-      Item* item;
-      BitSet32 hitFlags = 0;
-      hitTest( event.mousePoint, item, hitFlags );
-      Con::printf("debugging %d", item->mId);
-      Point2I pt = globalToLocalCoord(event.mousePoint);
-      if (item->isInspectorData() && item->getObject()) {
-         Con::printf("object data:");
-         Con::printf("name:%s",item->getObject()->getName());
-         Con::printf("className:%s",item->getObject()->getClassName());
-      }
-      Con::printf("contents of mSelectedItems:");
-      for(S32 i = 0; i < mSelectedItems.size(); i++) {
-         if (mSelectedItems[i]->isInspectorData()) {
-            Con::printf("%d",mSelectedItems[i]->getObject()->getId());
-         } else
-            Con::printf("wtf %d", mSelectedItems[i]);
-      }
-      Con::printf("contents of mSelected");
-      for (S32 j = 0; j < mSelected.size(); j++) {
-         Con::printf("%d", mSelected[j]);
-      }
-      S32 mCurrentDragCell = mMouseOverCell.y;
-      S32 midpCell = (mCurrentDragCell) * mItemHeight + (mItemHeight/2);
-      S32 currentY = pt.y;
-      S32 yDiff = currentY-midpCell;
-      Con::printf("cell info: (%d,%d) mCurrentDragCell=%d est=(%d,%d,%d) ydiff=%d",pt.x,pt.y,mCurrentDragCell,mCurrentDragCell*mItemHeight, midpCell, (mCurrentDragCell+1)*mItemHeight,yDiff);
-   }
-}
-
-
-void GuiTreeViewCtrl::onTouchDown(const GuiEvent & event)
-{
-   if( !mActive || !mAwake || !mVisible )
-   {
-      Parent::onTouchDown(event);
-      return;
-   }
-   if ( mProfile->mCanKeyFocus )
-      setFirstResponder();
-
-   Item * item = 0;
-   BitSet32 hitFlags;
-   mOldDragY = 0;
-   mDragMidPoint = NomDragMidPoint;
-
-   //
-   if(!hitTest(event.mousePoint, item, hitFlags))
-      return;
-
-   //
-   if(event.modifier & SI_CTRL)
-   {
-      bool selectFlag = item->mState.test(Item::Selected);
-      if (selectFlag == true)
-      {
-         // already selected, so unselect it and remove it
-         removeSelection(item->mId);
-         if (item->isInspectorData() && item->getObject())
-            Con::executef(this,2,"onRemoveSelection",Con::getIntArg(item->getObject()->getId()));
-      } else
-      {
-         // otherwise select it and add it to the list
-         // check if it is already on the list.
-         /*bool newSelection = true;
-         for (S32 i = 0; i < mSelectedItems.size(); i++) {
-         if (mSelectedItems[i] == item) {
-         newSelection = false;
-         }
-         }*/
-         //if (newSelection) {
-         addSelection(item->mId);
-         if (item->isInspectorData() && item->getObject())
-            Con::executef(this,2,"onAddSelection",Con::getIntArg(item->getObject()->getId()));
-         //}
-
-
-
-      }
-   }
-   else if (event.modifier & SI_SHIFT)
-   {
-      // is something already selected?
-      S32 firstSelectedIndex = 0;
-      Item * firstItem = NULL;
-      if (!mSelectedItems.empty())
-      {
-         firstItem = mSelectedItems.front();
-         for (S32 i = 0; i < mVisibleItems.size();i++)
-         {
-            if (mVisibleItems[i] == mSelectedItems.front())
-            {
-               firstSelectedIndex = i;
-               break;
-            }
-         }
-         S32 mCurrentDragCell = mMouseOverCell.y;
-         if (mVisibleItems[firstSelectedIndex] != firstItem )
-         {
-            /*
-            Con::printf("something isn't right...");
-            if (mVisibleItems[firstSelectedIndex]->isInspectorData())
-            Con::printf("visibleItem %s",mVisibleItems[firstSelectedIndex]->getObject()->getName());
-            if (firstItem->isInspectorData())
-            Con::printf("firstItem %s",firstItem->getObject()->getName());
-            */
-         }
-         else
-         {
-            // select the cells
-
-            if ((mCurrentDragCell) < firstSelectedIndex)
-            {
-               //select up
-               for (S32 j = (mCurrentDragCell); j < firstSelectedIndex; j++) {
-                  //if the item isn't already selected, then select it
-                  bool newSelection = true;
-                  Vector<Item *>::iterator k;
-                  for(k = mSelectedItems.begin(); k != mSelectedItems.end(); k++)
-                  {
-                     if (mVisibleItems[j] == *(k)){
-                        newSelection = false;
-                        break;
-                     }
-                  }
-                  if (newSelection)
-                  {
-                     addSelection(mVisibleItems[j]->mId);
-                     if (mVisibleItems[j]->isInspectorData())
-                        Con::executef(this,2,"onAddSelection",Con::getIntArg(mVisibleItems[j]->getObject()->getId()));
-                  }
-               }
-            }
-            else
-            {
-               // select down
-               for (S32 j = firstSelectedIndex+1; j < (mCurrentDragCell+1); j++) {
-                  bool newSelection = true;
-                  Vector<Item *>::iterator k;
-                  for(k = mSelectedItems.begin(); k != mSelectedItems.end(); k++) {
-                     if (mVisibleItems[j] == *(k)){
-                        newSelection = false;
-                        break;
-                     }
-                  }
-                  if (newSelection)
-                  {
-                     addSelection(mVisibleItems[j]->mId);
-                     if (mVisibleItems[j]->isInspectorData())
-                        Con::executef(this,2,"onAddSelection",Con::getIntArg(mVisibleItems[j]->getObject()->getId()));
-                  }
-               }
-            }
-         }
-      }
-   }
-   else if (event.modifier & SI_ALT)
-   {
-      if (item->isInspectorData() && item->getObject())
-      {
-         setInstantGroup(item->getObject());
-         mInstantGroup = item->mId;
-      }
-   } else if (!hitFlags.test(OnImage))
-   {
-      // first check to see if the item is already selected
-      bool newSelection = true;
-      Vector<Item *>::iterator k;
-      for(k = mSelectedItems.begin(); k != mSelectedItems.end(); k++) {
-         if(*(k) == item)
-         {
-            newSelection = false;
-            break;
-         }
-      }
-
-
-      // if the item is not already selected then we have a
-      //newly selected item, so clear our list of selected items
-      if (newSelection)
-      {
-         clearSelection();
-         //Con::executef(this, 1, "onClearSelection");
-         //mSelectedItems.clear();
-         setItemSelected(item->mId,true);
-      }
-   }
-   if ( hitFlags.test( OnText ) && ( event.mouseClickCount > 1 ) && mAltConsoleCommand[0] )
-      Con::evaluate( mAltConsoleCommand );
-
-   if(!item->isParent())
-      return;
-
-   //
-   if ( mFullRowSelect || hitFlags.test( OnImage ) )
-   {
-      item->setExpanded(!item->isExpanded());
-      if( !item->isInspectorData() && item->mState.test(Item::VirtualParent) )
-         onVirtualParentExpand(item);
-      scrollVisible(item);
-   }
-}
-
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::onTouchMove( const GuiEvent &event )
-{
-   if ( mMouseOverCell.y >= 0 && mVisibleItems.size() > mMouseOverCell.y)
-      mVisibleItems[mMouseOverCell.y]->mState.clear( Item::MouseOverBmp | Item::MouseOverText );
-
-   Parent::onTouchMove( event );
-
-   if ( mMouseOverCell.y >= 0 )
-   {
-      Item* item = NULL;
-      BitSet32 hitFlags = 0;
-      if ( !hitTest( event.mousePoint, item, hitFlags ) )
-         return;
-
-      if ( hitFlags.test( OnImage ) )
-         item->mState.set( Item::MouseOverBmp );
-
-      if ( hitFlags.test( OnText ))
-         item->mState.set( Item::MouseOverText );
-
-      // Always redraw the entire mouse over item, since we are distinguishing
-      // between the bitmap and the text:
-      setUpdateRegion( Point2I( mMouseOverCell.x * mCellSize.x, mMouseOverCell.y * mCellSize.y ), mCellSize );
-   }
-}
-
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::onTouchEnter( const GuiEvent &event )
-{
-   Parent::onTouchEnter( event );
-   onTouchMove( event );
-}
-
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::onTouchLeave( const GuiEvent &event )
-{
-   if ( mMouseOverCell.y >= 0 && mVisibleItems.size() > mMouseOverCell.y)
-      mVisibleItems[mMouseOverCell.y]->mState.clear( Item::MouseOverBmp | Item::MouseOverText );
-
-   Parent::onTouchLeave( event );
-}
-
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::onRightMouseDown(const GuiEvent & event)
-{
-   if(!mActive)
-   {
-      Parent::onRightMouseDown(event);
-      return;
-   }
-
-   Item * item = NULL;
-   BitSet32 hitFlags;
-
-   //
-   if(!hitTest(event.mousePoint, item, hitFlags))
-      return;
-
-   //
-   char bufs[2][32];
-   dSprintf(bufs[0], 32, "%d", item->mId);
-   dSprintf(bufs[1], 32, "%d %d", event.mousePoint.x, event.mousePoint.y);
-
-   if (item->isInspectorData() && item->getObject())
-      Con::executef(this,4, "onRightMouseDown", bufs[0],bufs[1],Con::getIntArg(item->getObject()->getId()));
-   else
-      Con::executef(this, 3, "onRightMouseDown", bufs[0], bufs[1]);
-}
-
-//------------------------------------------------------------------------------
-
-void GuiTreeViewCtrl::onRender(Point2I offset, const RectI &updateRect)
-{
-   // Get all our contents drawn!
-   Parent::onRender(offset,updateRect);
-
-   // Deal with drawing the drag & drop line, if any...
-   dglSetClipRect(updateRect);
-
-   // only do it if we have a mDragMidPoint
-   if (mDragMidPoint == NomDragMidPoint || !mSupportMouseDragging )
-      return;
-
-   ColorF greyLine(0.5,0.5,0.5,1);
-   Point2F squarePt;
-
-   glLineWidth(2.f);
-   // draw mDragMidPoint lines with a diamond
-   if (mDragMidPoint == AbovemDragMidPoint)
-   {
-      S32 tempY = mItemHeight*mCurrentDragCell+offset.y ;
-      squarePt.y = (F32)tempY;
-      squarePt.x = (F32)(125.0f+offset.x);
-      dglDrawLine(0+offset.x, tempY, 250+offset.x, tempY,greyLine);
-      dglDraw2DSquare(squarePt, 6, 90 );
-
-   }
-   if (mDragMidPoint == BelowmDragMidPoint)
-   {
-      S32 tempY2 = mItemHeight*(mCurrentDragCell+1) +offset.y;
-      squarePt.y = (F32)tempY2;
-      squarePt.x = (F32)(125.0f+offset.x);
-      dglDrawLine(0+offset.x, tempY2, 250+offset.x, tempY2,greyLine);
-      dglDraw2DSquare(squarePt,6, 90 );
-
-   }
-
-   glLineWidth(1.f);
-}
-
-void GuiTreeViewCtrl::onRenderCell(Point2I offset, Point2I cell, bool, bool )
-{
-   if( !mVisibleItems.size() )
-      return;
-
-   // Do some sanity checking and data retrieval.
-   AssertFatal(cell.y < mVisibleItems.size(), "GuiTreeViewCtrl::onRenderCell: invalid cell");
-   Item * item = mVisibleItems[cell.y];
-
-   // If there's no object, deal with it.
-   if(item->isInspectorData())
-      if(!item->getObject())
-         return;
-
-   RectI drawRect( offset, mCellSize );
-   dglClearBitmapModulation();
-
-   FrameAllocatorMarker txtBuff;
-
-   // Ok, we have the item. There are a few possibilities at this point:
-   //    - We need to draw inheritance lines and a treeview-chosen icon
-   //       OR
-   //    - We have to draw an item-dependent icon
-   //    - If we're mouseover, we have to highlight it.
-   //
-   //    - We have to draw the text for the item
-   //       - Taking into account various mouseover states
-   //       - Taking into account the value (set or not)
-   //       - If it's an inspector data, we have to do some custom rendering
-
-   // Ok, first draw the tab and icon.
-
-   // Do we draw the tree lines?
-   if(mFlags.test(ShowTreeLines))
-   {
-      drawRect.point.x += ( mTabSize * item->mTabLevel );
-      Item* parent = item->mParent;
-      for ( S32 i = item->mTabLevel; ( parent && i > 0 ); i-- )
-      {
-         drawRect.point.x -= mTabSize;
-         if ( parent->mNext )
-            dglDrawBitmapSR( mProfile->mTextureHandle, drawRect.point, mProfile->mBitmapArrayRects[BmpLine] );
-
-         parent = parent->mParent;
-      }
-   }
-
-   // Now, the icon...
-   drawRect.point.x = offset.x + mTabSize * item->mTabLevel;
-
-   // First, draw the rollover glow, if it's an inner node.
-   if ( item->isParent() && item->mState.test( Item::MouseOverBmp ) )
-      dglDrawBitmapSR( mProfile->mTextureHandle, drawRect.point, mProfile->mBitmapArrayRects[BmpGlow] );
-
-   // Now, do we draw a treeview-selected item or an item dependent one?
-   S32 newOffset = 0; // This is stored so we can render glow, then update render pos.
-
-   if(item->isInspectorData())
-   {
-      S32 bitmap = 0;
-
-      // Ok, draw the treeview lines as appropriate.
-      if ( !item->isParent() )
-      {
-         bitmap = item->mNext ? BmpChild : BmpLastChild;
-      }
-      else
-      {
-         bitmap = item->isExpanded() ? BmpExp : BmpCon;
-
-         if ( item->mParent || item->mPrevious )
-            bitmap += ( item->mNext ? 3 : 2 );
-         else
-            bitmap += ( item->mNext ? 1 : 0 );
-      }
-
-      if ( ( bitmap >= 0 ) && ( bitmap < mProfile->mBitmapArrayRects.size() ) )
-      {
-         dglDrawBitmapSR( mProfile->mTextureHandle, drawRect.point, mProfile->mBitmapArrayRects[bitmap] );
-         newOffset = mProfile->mBitmapArrayRects[bitmap].extent.x;
-      }
-
-      // draw lock icon if need be
-      S32 icon = Lock1;
-      S32 icon2 = Hidden;
-
-      if (item->getObject() && item->getObject()->isLocked())
-      {
-         if (mIconTable[icon])
-         {
-            //drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth();
-            drawRect.point.x += mIconTable[icon].getWidth();
-            dglDrawBitmap( mIconTable[icon], drawRect.point, 0 );
-         }
-      }
-
-      if (item->getObject() && item->getObject()->isHidden())
-      {
-         if (mIconTable[icon2])
-         {
-            //drawRect.point.x = offset.x + mTabSize * item->mTabLevel + mIconTable[icon].getWidth();
-            drawRect.point.x += mIconTable[icon2].getWidth();
-            dglDrawBitmap( mIconTable[icon2], drawRect.point, 0 );
-         }
-      }
-
-
-      SimObject * pObject = item->getObject();
-      SimGroup  * pGroup  = ( pObject == NULL ) ? NULL : dynamic_cast<SimGroup*>( pObject );
-
-      // draw the icon associated with the item
-      if (item->isParent())
-      {
-         if ( pGroup != NULL)
-         {
-            if (item->isExpanded())
-               item->mIcon = SimGroup1;
-            else
-               item->mIcon = SimGroup2;
-         }
-         else
-            item->mIcon = SimGroup2;
-      }
-      
-      if (mInstantGroup == item->mId)
-      {
-         if (item->isInspectorData())
-         {
-            if ( pGroup != NULL )
-            {
-               if (item->isExpanded())
-                  item->mIcon = SimGroup3;
-               else
-                  item->mIcon = SimGroup4;
-            }
-         }
-      }
-
-
-      if (item->mIcon)
-      {
-         if (mIconTable[item->mIcon])
-         {
-            S32 iconHeight = (mItemHeight - mIconTable[item->mIcon].getHeight()) / 2;
-            S32 oldHeight = drawRect.point.y;
-            if(iconHeight > 0)
-               drawRect.point.y += iconHeight;
-            drawRect.point.x += mIconTable[item->mIcon].getWidth();
-            dglDrawBitmap( mIconTable[item->mIcon], drawRect.point, 0 );
-            drawRect.point.y = oldHeight;
-         }
-      }
-   }
-   else
-   {
-      S32 bitmap = 0;
-
-      // Ok, draw the treeview lines as appropriate.
-      if ( !item->isParent() )
-         bitmap = item->mNext ? BmpChild : BmpLastChild;
-      else
-      {
-         bitmap = item->isExpanded() ? BmpExp : BmpCon;
-
-         if ( item->mParent || item->mPrevious )
-            bitmap += ( item->mNext ? 3 : 2 );
-         else
-            bitmap += ( item->mNext ? 1 : 0 );
-      }
-
-      if ( ( bitmap >= 0 ) && ( bitmap < mProfile->mBitmapArrayRects.size() ) )
-      {
-         dglDrawBitmapSR( mProfile->mTextureHandle, drawRect.point, mProfile->mBitmapArrayRects[bitmap] );
-         newOffset = mProfile->mBitmapArrayRects[bitmap].extent.x;
-      }
-
-      S32 icon = item->isExpanded() ? item->mScriptInfo.mExpandedImage : item->mScriptInfo.mNormalImage;
-      if ( icon )
-      {
-         if (mIconTable[icon])
-         {
-            S32 iconHeight = (mItemHeight - mIconTable[icon].getHeight()) / 2;
-            S32 oldHeight = drawRect.point.y;
-            if(iconHeight > 0)
-               drawRect.point.y += iconHeight;
-            drawRect.point.x += mIconTable[icon].getWidth();
-            dglDrawBitmap( mIconTable[icon], drawRect.point, 0 );
-            drawRect.point.y = oldHeight;
-         }
-      }
-   }
-
-   // Ok, update offset so we can render some text!
-   drawRect.point.x += newOffset;
-
-   // Ok, now we're off to rendering the actual data for the treeview item.
-
-   U32 bufLen = item->mDataRenderWidth + 1;
-   char *displayText = (char *)txtBuff.alloc(bufLen);
-   displayText[bufLen-1] = 0;
-   item->getDisplayText(bufLen, displayText);
-
-   // Draw the rollover/selected bitmap, if one was specified.
-   drawRect.extent.x = mProfile->getFont(mFontSizeAdjust)->getStrWidth( displayText ) + ( 2 * mTextOffset );
-   if ( item->mState.test( Item::Selected ) && mTexSelected )
-      dglDrawBitmapStretch( mTexSelected, drawRect );
-   else if ( item->mState.test( Item::MouseOverText ) && mTexRollover )
-      dglDrawBitmapStretch( mTexRollover, drawRect );
-
-   // Offset a bit so as to space text properly.
-   drawRect.point.x += mTextOffset;
-
-   // Determine what color the font should be.
-   ColorI fontColor;
-
-   fontColor = item->mState.test( Item::Selected ) ? mProfile->mFontColorSL :
-             ( item->mState.test( Item::MouseOverText ) ? mProfile->mFontColorHL : mProfile->mFontColor );
-
-   if (item->mState.test(Item::Selected))
-   {
-      dglDrawRectFill(drawRect, mProfile->mFillColorHL);
-   }
-   else if (item->mState.test(Item::MouseOverText))
-   {
-      dglDrawRectFill(drawRect, mProfile->mFontColorNA);
-   }
-   
-   if( mInstantGroup == item->mId)
-   {
-        fontColor	=	mProfile->mFontColorHL;
-   }
-   
-   dglSetBitmapModulation( fontColor );
-
-   // Center the text horizontally.
-   S32 height = (mItemHeight - mProfile->getFont(mFontSizeAdjust)->getHeight()) / 2;
-
-   if(height > 0)
-      drawRect.point.y += height;
-
-   // JDD - offset by two pixels or so to keep the text from rendering RIGHT ONTOP of the outline
-   drawRect.point.x += 2;
-
-   dglDrawText( mProfile->getFont(mFontSizeAdjust), drawRect.point, displayText, mProfile->mFontColors );
-
-}
-
-//------------------------------------------------------------------------------
-void GuiTreeViewCtrl::clearSelection()
-{
-   while (!mSelectedItems.empty())
-   {
-      if(!setItemSelected(mSelectedItems.last()->mId, false))
-         mSelectedItems.pop_back();
-   }
-
-   mSelectedItems.clear();
-   mSelected.clear();
-   
-   Con::executef(this, 1, "onClearSelection");
-}
-
-void GuiTreeViewCtrl::lockSelection(bool lock)
-{
-   for(U32 i = 0; i < (U32)mSelectedItems.size(); i++)
-   {
-      if(mSelectedItems[i]->isInspectorData())
-         mSelectedItems[i]->getObject()->setLocked(lock);
-   }
-}
-void GuiTreeViewCtrl::hideSelection(bool hide)
-{
-   for (U32 i = 0; i < (U32)mSelectedItems.size(); i++)
-   {
-      if (mSelectedItems[i]->isInspectorData())
-         mSelectedItems[i]->getObject()->setHidden(hide);
-   }
-
-}
-
-//------------------------------------------------------------------------------
-
-// handles icon assignments
-S32 GuiTreeViewCtrl::getIcon(const char * iconString)
-{
-   if( iconString == NULL ) 
-      return Default;
-
-   S32 icon = Default;
-
-   if (!dStrcmp(iconString, "SimGroup"))
-      icon = SimGroup1;
-
-   return icon;
-}
-
-void GuiTreeViewCtrl::addInspectorDataItem(Item *parent, SimObject *obj)
-{
-   S32 icon = getIcon(obj->getClassName());
-   Item *item = createItem(icon);
-   item->mState.set(Item::InspectorData);
-
-   // Deal with child objects...
-   if(dynamic_cast<SimSet*>(obj))
-      item->mState.set(Item::VirtualParent);
-
-   // Actually store the data!
-   item->setObject(obj);
-
-   // Now add us to the data structure...
-   if(parent)
-   {
-      // Add as child of parent.
-      if(parent->mChild)
-      {
-         Item * traverse = parent->mChild;
-         while(traverse->mNext)
-            traverse = traverse->mNext;
-
-         traverse->mNext = item;
-         item->mPrevious = traverse;
-      }
-      else
-         parent->mChild = item;
-
-      item->mParent = parent;
-   }
-   else
-   {
-      // If no parent, add to root.
-      item->mNext = mRoot;
-      mRoot = item;
-      item->mParent = NULL;
-   }
-
-   if(!parent || parent->isExpanded())
-      mFlags.set(RebuildVisible);
-
-   buildVisibleTree();
-
-}
-
-void GuiTreeViewCtrl::unlinkItem(Item * item)
-{
-   if (item->mPrevious)
-      item->mPrevious->mNext = item->mNext;
-
-   if (item->mNext)
-      item->mNext->mPrevious = item->mPrevious;
-}
-
-bool GuiTreeViewCtrl::childSearch(Item * item, SimObject *obj, bool yourBaby)
-{
-   Item * temp = item->mChild;
-   while (temp)
-   {
-      //do you have my baby?
-      if (temp->isInspectorData())
-      {
-         if (temp->getObject() == obj)
-            yourBaby = false; //probably a child of an inner script
-      }
-      yourBaby = childSearch(temp,obj, yourBaby);
-      temp = temp->mNext;
-   }
-   return yourBaby;
-}
-
-void GuiTreeViewCtrl::inspectorSearch(Item * item, Item * parent, SimSet * parentSet, SimSet * newParentSet)
-{
-   if (!parentSet||!newParentSet)
-      return;
-
-   if (item == parent->mNext)
-      return;
-
-   if (item)
-   {
-      if (item->isInspectorData())
-      {
-         // remove the object from the parentSet and add it to the newParentSet
-         SimObject* simObj = item->getObject();
-
-         if (parentSet->size())
-         {
-            SimObject *lastObject = parentSet->last();
-            parentSet->removeObject(simObj);
-            parentSet->reOrder(lastObject);
-         }
-         else
-            parentSet->removeObject(simObj);
-
-         newParentSet->addObject(simObj);
-
-         if (item->mNext)
-         {
-            inspectorSearch(item->mNext, parent, parentSet, newParentSet);
-            return;
-         }
-         else
-         {
-            // end of children so backing up
-            if (item->mParent == parent)
-               return;
-            else
-            {
-               inspectorSearch(item->mParent->mNext, parent, parentSet, newParentSet);
-               return;
-            }
-         }
-      }
-
-      if (item->mChild)
-      {
-         inspectorSearch(item->mChild, parent, parentSet, newParentSet);
-         return;
-      }
-
-      if (item->mNext)
-      {
-         inspectorSearch(item->mNext, parent, parentSet, newParentSet);
-         return;
-      }
-   }
-}
-bool GuiTreeViewCtrl::onVirtualParentBuild(Item *item, bool bForceFullUpdate)
-{
-   if(!item->mState.test(Item::InspectorData))
-      return true;
-
-   // Blast an item if it doesn't have a corresponding SimObject...
-   if(item->mInspectorInfo.mObject == NULL)
-   {
-      removeItem(item->mId);
-      return false;
-   }
-
-   // Skip the next stuff unless we're expanded...
-     if(!item->isExpanded() && !bForceFullUpdate)
-      return true;
-
-   // Verify that we have all the kids we should in here...
-   SimSet *srcObj = dynamic_cast<SimSet*>(&(*item->mInspectorInfo.mObject));
-
-   // If it's not a SimSet... WTF are we doing here?
-   if(!srcObj)
-      return true;
-
-   SimSet::iterator i;
-
-   // This is slow but probably ok.
-   for(i = srcObj->begin(); i != srcObj->end(); i++)
-   {
-      SimObject *obj = *i;
-
-      // If we can't find it, add it.
-      // unless it has a parent that is a child that is a script
-      Item *res = item->findChildByValue(obj);
-
-      bool foundChild = true;
-
-      // search the children. if any of them are the parent of the object then don't add it.
-      foundChild = childSearch(item,obj,foundChild);
-
-      if(!res && foundChild)
-      {
-         if (mDebug) Con::printf("adding something");
-         addInspectorDataItem(item, obj);
-      }
-   }
-
-   return true;
-}
-
-bool GuiTreeViewCtrl::onVirtualParentExpand(Item *item)
-{
-   // Do nothing...
-   return true;
-}
-
-bool GuiTreeViewCtrl::onVirtualParentCollapse(Item *item)
-{
-   // Do nothing...
-   return true;
-}
-
-void GuiTreeViewCtrl::inspectObject(SimObject *obj, bool okToEdit)
-{
-   destroyTree();
-   mFlags.set(IsEditable, okToEdit);
-
-   //build our icon table
-   const char * res  = Con::executef(this, 1, "onDefineIcons");
-
-   if(!(dAtob(res)))
-   {
-      // if no icons were defined in script then use defaults.
-      buildIconTable(NULL);
-   }
-
-   addInspectorDataItem(NULL, obj);
-}
-
-S32 GuiTreeViewCtrl::findItemByName(const char *name)
-{
-   for (S32 i = 0; i < mItems.size(); i++) 
-   {
-      if (mItems[i] != NULL)
-      {
-         if (dStrcmp(mItems[i]->getText(),name) == 0) 
-            return mItems[i]->mId;
-      }
-   }
-
-   return 0;
-}
-
-StringTableEntry GuiTreeViewCtrl::getTextToRoot( S32 itemId, const char * delimiter )
-{
-   Item * item = getItem(itemId);
-
-   if(!item)
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getTextToRoot: invalid start item id!");
-      return StringTable->EmptyString;
-   }
-
-   if(item->isInspectorData())
-   {
-      Con::errorf(ConsoleLogEntry::General, "GuiTreeViewCtrl::getTextToRoot: cannot get text to root of inspector data items");
-      return StringTable->EmptyString;
-   }
-
-   char bufferOne[1024];
-   char bufferTwo[1024];
-   char bufferNodeText[128];
-
-   dMemset( bufferOne, 0, sizeof(bufferOne) );
-   dMemset( bufferTwo, 0, sizeof(bufferTwo) );
-
-   dStrcpy( bufferOne, item->getText() );
-
-   Item *prevNode = item->mParent;
-   while ( prevNode )
-   {
-      dMemset( bufferNodeText, 0, sizeof(bufferNodeText) );
-      dStrcpy( bufferNodeText, prevNode->getText() );
-      dSprintf( bufferTwo, 1024, "%s%s%s",bufferNodeText, delimiter, bufferOne );
-      dStrcpy( bufferOne, bufferTwo );
-      dMemset( bufferTwo, 0, sizeof(bufferTwo) );
-      prevNode = prevNode->mParent;
-   }
-
-   // Return the result, StringTable-ized.
-   return StringTable->insert( bufferOne );
-}
-
-//------------------------------------------------------------------------------
-ConsoleMethod(GuiTreeViewCtrl, findItemByName, S32, 3, 3, "(name) Find item by name\n"
-              "@param name The name of the desired object.\n"
-              "@return Returns the ID of the object, or -1 on failure (not found).")
-{
-   return(object->findItemByName(argv[2]));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, insertItem, S32, 4, 8, "(TreeItemId parent, name, value, icon, normalImage=0, expandedImage=0) Adds item to tree control.\n"
-              "@param parent The new item's parent.\n"
-              "@param name The name of the new item.\n"
-              "@param value The new item's value.\n"
-              "@param icon The new item's icon\n"
-              "@return Returns the new item's ID.")
-{
-   S32 norm=0, expand=0;
-
-   if (argc > 6) 
-   {
-      norm = dAtoi(argv[6]);
-      if(argc > 7)
-         expand = dAtoi(argv[7]);
-   }
-
-   return(object->insertItem(dAtoi(argv[2]),  argv[3], argv[4], argv[5], norm, expand));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, lockSelection, void, 2, 3, "([bool lock]) Set whether the selection is to be locked."
-              "@param lock Boolean flag for whether or not the current selected object should be locked\n"
-              "@return No return value.")
-{
-   bool lock = true;
-   if(argc == 3)
-      lock = dAtob(argv[2]);
-   object->lockSelection(lock);
-}
-
-ConsoleMethod(GuiTreeViewCtrl, clearSelection, void, 2, 2, "() Clear selection\n"
-              "@return No return value.")
-{
-   object->clearSelection();
-}
-
-ConsoleMethod(GuiTreeViewCtrl, deleteSelection, void, 2, 2, "() Delete all selected items.\n"
-              "@return No return value.\n")
-{
-   object->deleteSelection();
-}
-
-ConsoleMethod(GuiTreeViewCtrl, addSelection, void, 3, 3, "(string ID) Select an item"
-              "@param ID The ID of the item to select.\n"
-              "@return No return value.")
-{
-   S32 id = dAtoi(argv[2]);
-   object->addSelection(id);
-}
-
-ConsoleMethod(GuiTreeViewCtrl, addChildSelectionByValue, void, 4, 4, "(TreeItemId parent, value)")
-{
-   S32 id = dAtoi(argv[2]);
-   GuiTreeViewCtrl::Item* parentItem = object->getItem(id);
-   if (parentItem)
-   {
-      GuiTreeViewCtrl::Item* child = parentItem->findChildByValue(argv[3]);
-      if (child)
-         object->addSelection(child->getID());
-   }
-}
-
-ConsoleMethod(GuiTreeViewCtrl, removeSelection, void, 3, 3, "(string ID) Deselects given item.\n"
-              "@param ID The ID of the item to deselect.\n"
-              "@return No return value.")
-{
-   S32 id = dAtoi(argv[2]);
-   object->removeSelection(id);
-}
-
-ConsoleMethod(GuiTreeViewCtrl, removeChildSelectionByValue, void, 4, 4, "removeChildSelectionByValue(TreeItemId parent, value)")
-{
-   S32 id = dAtoi(argv[2]);
-   GuiTreeViewCtrl::Item* parentItem = object->getItem(id);
-   if(parentItem)
-   {
-      GuiTreeViewCtrl::Item* child = parentItem->findChildByValue(argv[3]);
-      if(child)
-         object->removeSelection(child->getID());
-   }
-}
-
-ConsoleMethod(GuiTreeViewCtrl, selectItem, bool, 3, 4, "(TreeItemId item, [bool select=true]) Selects item.")
-{
-   S32 id = dAtoi(argv[2]);
-   bool select = true;
-   if(argc == 4)
-      select = dAtob(argv[3]);
-
-   return(object->setItemSelected(id, select));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, expandItem, bool, 3, 4, "(TreeItemId item, [bool expand=true]) Deselects item")
-{
-   S32 id = dAtoi(argv[2]);
-   bool expand = true;
-   if(argc == 4)
-      expand = dAtob(argv[3]);
-   return(object->setItemExpanded(id, expand));
-}
-
-// Make the given item visible.
-ConsoleMethod(GuiTreeViewCtrl, scrollVisible, void, 3, 3, "(TreeItemId item) Make the given item visible.\n"
-              "@param ID of the desired item.\n"
-              "@return No return value.")
-{
-   object->scrollVisible(dAtoi(argv[2]));
-}
-
-
-ConsoleMethod(GuiTreeViewCtrl, buildIconTable, bool, 3,3, "(string icons) Icons should be designated by the bitmap/png file names (minus the file extensions) "
-              "and separated by colons (:). This list should be synchronized with the Icons enum.\n"
-              "@param icons The list of icons to add sepated by colons.\n"
-              "@return Returns true on success, false otherwise.")
-{   
-   const char * icons = argv[2];
-   return object->buildIconTable(icons);
-}
-
-ConsoleMethod( GuiTreeViewCtrl, open, void, 3, 4, "(SimSet obj, bool okToEdit=true) Set the root of the tree view to the specified object, or to the root set.")
-{
-   SimSet *treeRoot = NULL;
-   SimObject* target = Sim::findObject(argv[2]);
-
-   bool okToEdit = true;
-
-   if (argc == 4)
-      okToEdit = dAtob(argv[3]);
-
-   if (target)
-      treeRoot = dynamic_cast<SimSet*>(target);
-
-   if (! treeRoot)
-      Sim::findObject(RootGroupId, treeRoot);
-
-   object->inspectObject(treeRoot,okToEdit);
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getItemText, const char *, 3, 3, "(TreeItemId item)")
-{
-   return(object->getItemText(dAtoi(argv[2])));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getItemValue, const char *, 3, 3, "(TreeItemId item)")
-{
-   return(object->getItemValue(dAtoi(argv[2])));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, editItem, bool, 5, 5, "(TreeItemId item, string newText, string newValue)")
-{
-   return(object->editItem(dAtoi(argv[2]), argv[3], argv[4]));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, removeItem, bool, 3, 3, "(TreeItemId item)")
-{
-   return(object->removeItem(dAtoi(argv[2])));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, removeAllChildren, void, 3, 3, "removeAllChildren(TreeItemId parent)")
-{
-   object->removeAllChildren(dAtoi(argv[2]));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, clear, void, 2, 2, "() - empty tree")
-{
-   object->removeItem(0);
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getFirstRootItem, S32, 2, 2, "Get id for root item.")
-{
-   return(object->getFirstRootItem());
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getChild, S32, 3, 3, "(TreeItemId item)")
-{
-   return(object->getChildItem(dAtoi(argv[2])));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, buildVisibleTree, void, 3, 3, "Build the visible tree")
-{
-   object->buildVisibleTree(dAtob(argv[2]));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getParent, S32, 3, 3, "(TreeItemId item)")
-{
-   return(object->getParentItem(dAtoi(argv[2])));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getNextSibling, S32, 3, 3, "(TreeItemId item)")
-{
-   return(object->getNextSiblingItem(dAtoi(argv[2])));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getPrevSibling, S32, 3, 3, "(TreeItemId item)")
-{
-   return(object->getPrevSiblingItem(dAtoi(argv[2])));
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getItemCount, S32, 2, 2, "() @return Returns the number of items in control")
-{
-   return(object->getItemCount());
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getSelectedItem, S32, 2, 2, "() @return Returns the ID of the selected item.")
-{
-   return ( object->getSelectedItem() );
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getSelectedObject, S32, 2, 2, "() @return Returns the currently selected simObject in inspector mode or -1")
-{
-   GuiTreeViewCtrl::Item *item = object->getItem( object->getSelectedItem() );
-   if( item != NULL && item->isInspectorData() )
-   {
-      SimObject *obj = item->getObject();
-      if( obj != NULL )
-         return object->getId();
-   }
-
-   return -1;
-}
-
-ConsoleMethod(GuiTreeViewCtrl, moveItemUp, void, 3, 3, "(TreeItemId item)")
-{
-   object->moveItemUp( dAtoi( argv[2] ) );
-}
-
-ConsoleMethod(GuiTreeViewCtrl, getSelectedItemsCount, S32, 2, 2, "")
-{
-   return ( object->getSelectedItemsCount() );
-}
-
-ConsoleMethod(GuiTreeViewCtrl, moveItemDown, void, 3, 3, "(TreeItemId item)")
-{
-   object->moveItemDown( dAtoi( argv[2] ) );
-}
-
-//-----------------------------------------------------------------------------
-
-ConsoleMethod(GuiTreeViewCtrl, getTextToRoot, const char*,4,4,"(TreeItemId item,Delimiter=none) gets the text from the current node to the root, concatenating at each branch upward, with a specified delimiter optionally")
-{
-   if ( argc < 4 )
-   {
-      Con::warnf("GuiTreeViewCtrl::getTextToRoot - Invalid number of arguments!");
-      return ("");
-   }
-   S32 itemId = dAtoi( argv[2] );
-   StringTableEntry delimiter = argv[3];
-
-   return object->getTextToRoot( itemId, delimiter );
-}
-
-ConsoleMethod(GuiTreeViewCtrl,getSelectedItemList,const char*, 2,2,"returns a space seperated list of mulitple item ids")
-{
-    char* buff = Con::getReturnBuffer(1024);
-    dSprintf(buff,1024,"");
-
-    for(int i = 0; i < object->mSelected.size(); i++)
-    {
-        S32 id  = object->mSelected[i];
-        //get the current length of the buffer
-        U32	len = dStrlen(buff);
-        //the start of the buffer where we want to write
-        char* buffPart = buff+len;
-        //the size of the remaining buffer (-1 cause dStrlen doesn't count the \0)
-        S32 size	=	1024-len-1;
-        //write it:
-        if(size < 1)
-        {
-            Con::errorf("GuiTreeViewCtrl::getSelectedItemList - Not enough room to return our object list");
-            return buff;
-        }
-
-        dSprintf(buffPart,size,"%d ", id);
-    }
-//mSelected
-
-    return buff;
-}
-
-//------------------------------------------------------------------------------
-S32 GuiTreeViewCtrl::findItemByObjectId(S32 iObjId)
-{  
-   for (S32 i = 0; i < mItems.size(); i++)
-   {
-      if (mItems[i] != NULL)
-      {
-         SimObject* pObj = mItems[i]->getObject();
-         if(pObj && pObj->getId() == iObjId)
-            return mItems[i]->mId;
-      }
-   }
-
-   return -1;
-}
-
-//------------------------------------------------------------------------------
-ConsoleMethod(GuiTreeViewCtrl, findItemByObjectId, S32, 3, 3, "(find item by object id and returns the mId)")
-{
-   return(object->findItemByObjectId(dAtoi(argv[2])));
-}
-
-//------------------------------------------------------------------------------
-bool GuiTreeViewCtrl::scrollVisibleByObjectId(S32 objID)
-{
-   S32 itemID = findItemByObjectId(objID);
-
-   if(itemID == -1)
-   {
-      // we did not find the item in our current items
-      // we should try to find and show the parent of the item.
-      SimObject *obj = Sim::findObject(objID);
-
-      if(!obj || !obj->getGroup())
-         return false;
-    
-      // if we can't show the parent, we fail.
-      if(! scrollVisibleByObjectId(obj->getGroup()->getId()) )
-         return false;
-      
-      // get the parent. expand the parent. rebuild the tree. this ensures that
-      // we'll be able to find the child item we're targeting.
-      S32 parentID = findItemByObjectId(obj->getGroup()->getId());
-      AssertFatal(parentID != -1, "We were able to show the parent, but could not then find the parent. This should not happen.");
-      Item *parentItem = getItem(parentID);
-      parentItem->setExpanded(true);
-      buildVisibleTree();
-      
-      // NOW we should be able to find the object. if not... something's wrong.
-      itemID = findItemByObjectId(objID);
-      AssertWarn(itemID != -1,"GuiTreeViewCtrl::scrollVisibleByObjectId() found the parent, but can't find it's immediate child. This should not happen.");
-      if(itemID == -1)
-         return false;
-   }
-   
-   // ok, item found. scroll to it.
-   scrollVisible(itemID);
-   
-   return true;
-}
-
-//------------------------------------------------------------------------------
-ConsoleMethod(GuiTreeViewCtrl, scrollVisibleByObjectId, S32, 3, 3, "(show item by object id. returns true if sucessful.)")
-{
-   return(object->scrollVisibleByObjectId(dAtoi(argv[2])));
-}
-
-
+	for (auto branch : treeItem->branchList)
+	{
+		if(!isVisible || branch->isOpen)
+		{
+			setBranchesVisible(branch, isVisible);
+		}
+		branch->isVisible = isVisible;
+	}
+}

+ 62 - 369
engine/source/gui/guiTreeViewCtrl.h

@@ -23,384 +23,77 @@
 #ifndef _GUI_TREEVIEWCTRL_H
 #ifndef _GUI_TREEVIEWCTRL_H
 #define _GUI_TREEVIEWCTRL_H
 #define _GUI_TREEVIEWCTRL_H
 
 
-#include "collection/bitSet.h"
-#include "math/mRect.h"
-#include "gui/guiControl.h"
-#include "gui/guiArrayCtrl.h"
+#include "gui/guiListBoxCtrl.h"
+#include <vector>
 
 
 //------------------------------------------------------------------------------
 //------------------------------------------------------------------------------
 
 
-class GuiTreeViewCtrl : public GuiArrayCtrl
+class GuiTreeViewCtrl : public GuiListBoxCtrl
 {
 {
-   private:
-      typedef GuiArrayCtrl Parent;
-
-   public:
-      /// @section GuiTreeViewCtrl_Intro Introduction
-      /// @nosubgrouping
-
-      ///
-      struct Item
-      {
-
-         enum ItemState
-         {
-            Selected       = BIT(0),
-            Expanded       = BIT(1),
-            Focus          = BIT(2),
-            MouseOverBmp   = BIT(3),
-            MouseOverText  = BIT(4),
-            InspectorData  = BIT(5), ///< Set if we're representing some inspector
-                                     /// info (ie, use mInspectorInfo, not mScriptInfo)
-            VirtualParent  = BIT(6), ///< This indicates that we should be rendered as
-                                     ///  a parent even though we don't have any children.
-                                     ///  This is useful for preventing scenarios where
-                                     ///  we might want to create thousands of
-                                     ///  Items that might never be shown (for instance
-                                     ///  if we're browsing the object hierarchy in
-                                     ///  Torque, which might have thousands of objects).
-         };
-
-         BitSet32                mState;
-         SimObjectPtr<GuiControlProfile> mProfile;
-         S16                     mId;
-         U16                     mTabLevel;
-         Item *                  mParent;
-         Item *                  mChild;
-         Item *                  mNext;
-         Item *                  mPrevious;
-         S32                     mIcon; //stores the icon that will represent the item in the tree
-         S32                     mDataRenderWidth; /// this stores the pixel width needed
-                                                   /// to render the item's data in the 
-                                                   /// onRenderCell function to optimize
-                                                   /// for speed.
-
-
-         Item( GuiControlProfile *pProfile );
-         ~Item();
-
-         struct ScriptTag
-         {
-            S8                      mNormalImage;
-            S8                      mExpandedImage;
-            char*                   mText;
-            char*                   mValue;
-         } mScriptInfo;
-         struct InspectorTag
-         {
-            SimObjectPtr<SimObject> mObject;
-         } mInspectorInfo;
-
-         /// @name Get Methods
-         /// @{
-
-         ///
-         const S8 getNormalImage() const;
-         const S8 getExpandedImage() const;
-         char *getText();
-         char *getValue();
-         inline const S16 getID() const { return mId; };
-         SimObject *getObject();
-         const U32 getDisplayTextLength();
-         const S32 getDisplayTextWidth(GFont *font);
-         void getDisplayText(U32 bufLen, char *buf);
-         /// @}
-
-
-         /// @name Set Methods
-         /// @{
-
-         /// Set whether an item is expanded or not (showing children or having them hidden)
-         void setExpanded(const bool f);
-         /// Set the image to display when an item IS expanded
-         void setExpandedImage(const S8 id);
-         /// Set the image to display when an item is NOT expanded
-         void setNormalImage(const S8 id);
-         /// Assign a SimObject pointer to an inspector data item
-         void setObject(SimObject *obj);
-         /// Set the items displayable text (caption)
-         void setText(char *txt);
-         /// Set the items script value (data)
-         void setValue(const char *val);
-         /// Set the items virtual parent flag
-         void setVirtualParent( bool value );
-         /// @}
-
-
-         /// @name State Retrieval
-         /// @{
-
-         /// Returns true if this item is expanded. For
-         /// inspector objects, the expansion is stored
-         /// on the SimObject, for other things we use our
-         /// bit vector.
-         const bool isExpanded() const;
-
-         /// Returns true if an item is inspector data
-         /// or false if it's just an item.
-         inline const bool isInspectorData() const { return mState.test(InspectorData); };
-
-         /// Returns true if we should show the expand art
-         /// and make the item interact with the mouse as if
-         /// it were a parent.
-         const bool isParent() const;
-         /// @}
-
-         /// @name Searching Methods
-         /// @{
-
-         /// Find an inspector data item by it's SimObject pointer
-         Item *findChildByValue(const SimObject *obj);
-
-         /// Find a regular data item by it's script value
-         Item *findChildByValue(StringTableEntry Value);
-         /// @}
-
-      };
-
-      /// @name Enums
-      /// @{
-
-      ///
-      enum TreeState
-      {
-         RebuildVisible    = BIT(0), ///< Temporary flag, we have to rebuild the tree.
-         IsInspector       = BIT(1), ///< We are mapping a SimObject hierarchy.
-         IsEditable        = BIT(2), ///< We allow items to be moved around.
-         ShowTreeLines     = BIT(3), ///< Should we render tree lines or just icons?
-         BuildingVisTree   = BIT(4), ///< We are currently building the visible tree (prevent recursion)
-      };
+private:
+	typedef GuiListBoxCtrl Parent;
 
 
 protected:
 protected:
-  		enum
-		{
-         MaxIcons = 32,
-		};
-
-      enum Icons
-      {
-         Default1 = 0,
-         SimGroup1,
-         SimGroup2,
-         SimGroup3,
-         SimGroup4,
-         Camera,
-         Hidden,
-         Lock1,
-         Lock2,
-         Default,
-         Icon31,
-         Icon32
-      };
-
-      enum mDragMidPointFlags
-      {
-            NomDragMidPoint,
-            AbovemDragMidPoint,
-            BelowmDragMidPoint
-      };
+	SimObjectPtr<SimObject> mRootObject;
+	S32 mIndentSize;
 
 
-      ///
-      enum HitFlags
-      {
-         OnIndent       = BIT(0),
-         OnImage        = BIT(1),
-         OnText         = BIT(2),
-         OnRow          = BIT(3),
-      };
-
-      ///
-      enum BmpIndices
-      {
-         BmpDunno,
-         BmpLastChild,
-         BmpChild,
-         BmpExp,
-         BmpExpN,
-         BmpExpP,
-         BmpExpPN,
-         BmpCon,
-         BmpConN,
-         BmpConP,
-         BmpConPN,
-         BmpLine,
-         BmpGlow,
-      };
-
-
-      /// @}
 public:
 public:
+	GuiTreeViewCtrl();
+	virtual ~GuiTreeViewCtrl();
+	static void initPersistFields();
+
+	class TreeItem : public GuiListBoxCtrl::LBItem
+	{
+	public:
+		TreeItem() : isOpen(1), level(0), triangleArea(RectI()), isVisible(1) { }
+		virtual ~TreeItem() { }
+
+		bool				isOpen;
+		U16					level;
+		RectI               triangleArea;
+		bool				isVisible;
+		vector<TreeItem*>	branchList;
+		TreeItem*			trunk;
+	};
+
+private:
+	TreeItem* grabItemPtr(S32 index);
 
 
-      ///
-      Vector<Item*>           mItems;
-      Vector<Item*>           mVisibleItems;
-      Vector<Item*>           mSelectedItems;
-      Vector<S32>             mSelected;     ///< Used for tracking stuff that was
-                                             ///  selected, but may not have been
-                                             ///  created at time of selection
-      S32                     mItemCount;
-      Item *                  mItemFreeList; ///< We do our own free list, as we
-                                             ///  we want to be able to recycle
-                                             ///  item ids and do some other clever
-                                             ///  things.
-      Item *                  mRoot;
-      S32                     mInstantGroup;
-      S32                     mMaxWidth;
-      S32                     mSelectedItem;
-      S32                     mDraggedToItem;
-      S32                     mTempItem;
-      S32                     mStart;
-      BitSet32                mFlags;
-
-protected:
-      TextureHandle mIconTable[MaxIcons];
-
-      // for debugging
-      bool mDebug;
-
-      S32               mTabSize;
-      S32               mTextOffset;
-      bool              mFullRowSelect;
-      S32               mItemHeight;
-      bool              mDestroyOnSleep;
-      bool              mSupportMouseDragging;
-      bool              mMultipleSelections;
-      bool              mDeleteObjectAllowed;
-      bool              mDragToItemAllowed;
-
-      S32               mOldDragY;
-      S32               mCurrentDragCell;
-      S32               mPreviousDragCell;
-      S32               mDragMidPoint;
-      bool              mMouseDragged;
-
-      StringTableEntry  mBitmapBase;
-      TextureHandle	   mTexRollover;
-      TextureHandle	   mTexSelected;
-
-      // Hack to get passed always recursively building tree EVERY TICK!
-      S32               mTicksPassed;
-      S32               mTreeRefreshInterval;
-
-      ColorI   mAltFontColor;
-      ColorI   mAltFontColorHL;
-      ColorI   mAltFontColorSE;
-
-      SimObjectPtr<SimObject> mRootObject;
-
-      void destroyChildren(Item * item, Item * parent);
-      void destroyItem(Item * item);
-      void destroyTree();
-
-      void deleteItem(Item *item);
-
-      void buildItem(Item * item, U32 tabLevel, bool bForceFullUpdate = false);
-
-      bool hitTest(const Point2I & pnt, Item* & item, BitSet32 & flags);
-
-      virtual bool onVirtualParentBuild(Item *item, bool bForceFullUpdate = false);
-      virtual bool onVirtualParentExpand(Item *item);
-      virtual bool onVirtualParentCollapse(Item *item);
-      virtual void onItemSelected( Item *item );
-
-      void addInspectorDataItem(Item *parent, SimObject *obj);
-
-   public:
-      GuiTreeViewCtrl();
-      virtual ~GuiTreeViewCtrl();
-
-      /// Used for syncing the mSelected and mSelectedItems lists.
-      void syncSelection();
-
-      void lockSelection(bool lock);
-      void hideSelection(bool hide);
-      void addSelection(S32 itemId);
-
-      /// Should use addSelection and removeSelection when calling from script
-      /// instead of setItemSelected. Use setItemSelected when you want to select
-      /// something in the treeview as it has script call backs.
-      void removeSelection(S32 itemId);
-
-      /// Sets the flag of the item with the matching itemId.
-      bool setItemSelected(S32 itemId, bool select);
-      bool setItemExpanded(S32 itemId, bool expand);
-      bool setItemValue(S32 itemId, StringTableEntry Value);
-
-      const char * getItemText(S32 itemId);
-      const char * getItemValue(S32 itemId);
-      StringTableEntry getTextToRoot(S32 itemId, const char *delimiter = "");
-
-      Item * getItem(S32 itemId);
-      Item * createItem(S32 icon);
-      bool editItem( S32 itemId, const char* newText, const char* newValue );
-
-      // insertion/removal
-      void unlinkItem(Item * item);
-      S32 insertItem(S32 parentId, const char * text, const char * value = "", const char * iconString = "", S16 normalImage = 0, S16 expandedImage = 1);
-      bool removeItem(S32 itemId);
-      void removeAllChildren(S32 itemId); // Remove all children of the given item
-
-      bool buildIconTable(const char * icons);
-
-      void setInstantGroup(SimObject * obj);
-
-      S32 getIcon(const char * iconString);
-
-      // tree items
-      const S32 getFirstRootItem() const;
-      S32 getChildItem(S32 itemId);
-      S32 getParentItem(S32 itemId);
-      S32 getNextSiblingItem(S32 itemId);
-      S32 getPrevSiblingItem(S32 itemId);
-      S32 getItemCount();
-      S32 getSelectedItem();
-      S32 getSelectedItem(S32 index); // Given an item's index in the selection list, return its itemId
-      S32 getSelectedItemsCount() {return mSelectedItems.size();} // Returns the number of selected items
-      void moveItemUp( S32 itemId );
-      void moveItemDown( S32 itemId );
-
-      // misc.
-      bool scrollVisible( Item *item );
-      bool scrollVisible( S32 itemId );
-      bool scrollVisibleByObjectId( S32 objID );
-      
-      void deleteSelection();
-      void clearSelection();
-
-      S32 findItemByName(const char *name);
-      S32 findItemByObjectId(S32 iObjId);
-
-      // GuiControl
-      bool onWake();
-      void onSleep();
-      void onPreRender();
-      bool onKeyDown( const GuiEvent &event );
-		void onTouchDown(const GuiEvent &event);
-      void onMiddleMouseDown(const GuiEvent &event);
-      void onTouchMove(const GuiEvent &event);
-      void onTouchEnter(const GuiEvent &event);
-      void onTouchLeave(const GuiEvent &event);
-      void onRightMouseDown(const GuiEvent &event);
-      void onTouchDragged(const GuiEvent &event);
-      void onTouchUp(const GuiEvent &event);
-
-      /// Returns false if the object is a child of one of the inner items.
-      bool childSearch(Item * item, SimObject *obj, bool yourBaby);
-
-      /// Find immediately available inspector items (eg ones that aren't children of other inspector items)
-      /// and then update their sets
-      void inspectorSearch(Item * item, Item * parent, SimSet * parentSet, SimSet * newParentSet);
-
-      // GuiArrayCtrl
-      void onRenderCell(Point2I offset, Point2I cell, bool, bool);
-      void onRender(Point2I offset, const RectI &updateRect);
-
-      static void initPersistFields();
-
-      void inspectObject(SimObject * obj, bool okToEdit);
-      void buildVisibleTree(bool bForceFullUpdate = false);
-
-      DECLARE_CONOBJECT(GuiTreeViewCtrl);
+public:
+	// GuiControl
+	//bool onWake();
+	//void onSleep();
+	//void onPreRender();
+	//bool onKeyDown(const GuiEvent& event);
+	//void onTouchDown(const GuiEvent& event);
+	//void onMiddleMouseDown(const GuiEvent& event);
+	//void onTouchMove(const GuiEvent& event);
+	//void onTouchEnter(const GuiEvent& event);
+	//void onTouchLeave(const GuiEvent& event);
+	//void onRightMouseDown(const GuiEvent& event);
+	//void onTouchDragged(const GuiEvent& event);
+	//void onTouchUp(const GuiEvent& event);
+
+	//bool onAdd();
+	void onPreRender();
+	void onRender(Point2I offset, const RectI& updateRect);
+	//void setControlProfile(GuiControlProfile* prof);
+	//void resize(const Point2I& newPosition, const Point2I& newExtent);
+	virtual void onRenderItem(RectI& itemRect, LBItem* item);
+
+	S32 getHitIndex(const GuiEvent& event);
+	virtual void handleItemClick(LBItem* hitItem, S32 hitIndex, const GuiEvent& event);
+	virtual void handleItemClick_ClickCallbacks(LBItem* hitItem, S32 hitIndex, const GuiEvent& event);
+
+	void inspectObject(SimObject* obj);
+	void addBranches(TreeItem* treeItem, SimObject* obj, U16 level);
+	void refreshTree();
+	StringTableEntry getObjectText(SimObject* obj);
+	void calculateHeaderExtent();
+	virtual GuiListBoxCtrl::LBItem* createItem();
+	void setBranchesVisible(TreeItem* treeItem, bool isVisible);
+
+	DECLARE_CONOBJECT(GuiTreeViewCtrl);
 };
 };
 
 
 #endif
 #endif

+ 48 - 0
engine/source/gui/guiTreeViewCtrl_ScriptBinding.h

@@ -0,0 +1,48 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2013 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+ConsoleMethodGroupBeginWithDocs(GuiTreeViewCtrl, GuiListBoxCtrl)
+
+/*! Sets the root object to view.
+	@param obj A SimSet that will be viewed as a tree.
+	@return No return value.
+*/
+ConsoleMethodWithDocs( GuiTreeViewCtrl, open, ConsoleVoid, 3, 3, (SimSet obj))
+{
+   SimSet *treeRoot = NULL;
+   SimObject* target = Sim::findObject(argv[2]);
+
+   if (target)
+      treeRoot = dynamic_cast<SimSet*>(target);
+
+   object->inspectObject(treeRoot);
+}
+
+/*! Informs the tree that the contents of the tree have changed and should be refreshed.
+	@return No return value.
+*/
+ConsoleMethodWithDocs(GuiTreeViewCtrl, refresh, ConsoleVoid, 2, 2, ())
+{
+	object->refreshTree();
+}
+
+ConsoleMethodGroupEndWithDocs(GuiTreeViewCtrl)