ソースを参照

GuiEditor Foundation

This starts the process of moving the GuiEditor toy into the tools. It includes the GuiControl list and dragging controls onto the screen. More to come.

This also includes a few C++ bug fixes. Most notably, it fixes a bug that caused the GuiProfiles to have an incorrect reference count. Typically this error was on the side of having too many references (causing resources to be held onto for too long). Sometimes the ref count would error in the other direction and cause a fatal assert to fire. This has been fixed.
Peter Robinson 2 年 前
コミット
6131465e14

+ 44 - 1
editor/EditorCore/Themes/BaseTheme/BaseTheme.cs

@@ -101,6 +101,41 @@ function BaseTheme::makeCursors(%this)
 	    bitmapName = "^EditorCore/Themes/BaseTheme/images/cursors/defaultCursor.png";
 	};
 
+	%this.leftRightCursor = new GuiCursor()
+	{
+	   hotSpot = "0.5 0";
+	   renderOffset = "0.5 0.4";
+	   bitmapName = "^EditorCore/Themes/BaseTheme/images/cursors/leftRight.png";
+	};
+
+	%this.upDownCursor = new GuiCursor()
+	{
+	   hotSpot = "1 1";
+	   renderOffset = "0.5 0.4";
+	   bitmapName = "^EditorCore/Themes/BaseTheme/images/cursors/upDown.png";
+	};
+
+	%this.NWSECursor = new GuiCursor()
+	{
+	   hotSpot = "1 1";
+	   renderOffset = "0.5 0.5";
+	   bitmapName = "^EditorCore/Themes/BaseTheme/images/cursors/NWSE.png";
+	};
+
+	%this.NESWCursor = new GuiCursor()
+	{
+	   hotSpot = "1 1";
+	   renderOffset = "0.5 0.5";
+	   bitmapName = "^EditorCore/Themes/BaseTheme/images/cursors/NESW.png";
+	};
+
+	%this.moveCursor = new GuiCursor()
+	{
+	   hotSpot = "1 1";
+	   renderOffset = "0.5 0.5";
+	   bitmapName = "^EditorCore/Themes/BaseTheme/images/cursors/move.png";
+	};
+
 	%this.editCursor = new GuiCursor()
 	{
 	   hotSpot = "0 0";
@@ -1744,6 +1779,14 @@ function BaseTheme::makeWindowProfile(%this)
 		paddingNA = 1;
 	};
 
+	%windowContentTopBorder = new GuiBorderProfile()
+	{
+		padding = 1;
+		paddingHL = 1;
+		paddingSL = 1;
+		paddingNA = 1;
+	};
+
 	%this.windowContentProfile = new GuiControlProfile()
 	{
 		fillColor = %this.color1;
@@ -1751,7 +1794,7 @@ function BaseTheme::makeWindowProfile(%this)
 
 		borderLeft = %windowContentBorder;
 		borderRight = %windowContentBorder;
-		borderTop = %this.emptyBorder;
+		borderTop = %windowContentTopBorder;
 		borderBottom = %windowContentBorder;
 	};
 

BIN
editor/EditorCore/Themes/BaseTheme/images/cursors/NESW.png


BIN
editor/EditorCore/Themes/BaseTheme/images/cursors/NWSE.png


BIN
editor/EditorCore/Themes/BaseTheme/images/cursors/leftRight.png


BIN
editor/EditorCore/Themes/BaseTheme/images/cursors/move.png


BIN
editor/EditorCore/Themes/BaseTheme/images/cursors/upDown.png


+ 7 - 0
editor/EditorCore/Themes/ThemeManager.cs

@@ -161,6 +161,13 @@ function ThemeManager::setProfile(%this, %gui, %profileName, %profileTag)
 	{
 		%gui.editCursor = %this.activeTheme.editCursor;
 	}
+
+	if(%profileName $= "windowProfile")
+	{
+		%gui.leftRightCursor = %this.activeTheme.leftRightCursor;
+		%gui.upDownCursor = %this.activeTheme.upDownCursor;
+		%gui.NWSECursor = %this.activeTheme.NWSECursor;
+	}
 }
 
 function ThemeManager::setImage(%this, %sprite, %imageName, %frame)

+ 115 - 0
editor/GuiEditor/GuiEditor.cs

@@ -0,0 +1,115 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+function GuiEditor::create( %this )
+{
+	exec("./scripts/GuiEditorBrain.cs");
+	exec("./scripts/GuiEditorControlList.cs");
+	exec("./scripts/GuiEditorControlListBox.cs");
+
+	%this.guiPage = EditorCore.RegisterEditor("Gui Editor", %this);
+
+    %this.content = new GuiSpriteCtrl() {
+		HorizSizing = "width";
+        VertSizing = "height";
+        Position = "0 0";
+        Extent = %this.guiPage.getExtent();
+		imageColor = "255 255 255 255";
+        bitmap = "./images/gridTiny2";
+		singleFrameBitmap = "1";
+		tileImage = "1";
+		positionOffset = "0 0";
+		imageSize = "128 128";
+		fullSize = "0";
+		constrainProportions = "1";
+        isContainer = true;
+	};
+    ThemeManager.setProfile(%this.content, "emptyProfile");
+    %this.guiPage.add(%this.content);
+
+    %this.brain = new GuiEditCtrl(GuiEditorBrain)
+    {
+        Profile = "GuiTextEditProfile";
+        //Class = "GuiEditorBrain";
+		HorizSizing = "width";
+        VertSizing = "height";
+        Position = "0 0";
+        Extent = %this.guiPage.getExtent();
+    };
+    %this.guiPage.add(%this.brain);
+
+    %this.ctrlListWindow = new GuiWindowCtrl()
+    {
+        Class = "GuiEditorControlList";
+        HorizSizing = "right";
+        VertSizing = "bottom";
+        Position = "0 0";
+        Extent = "250 380";
+        MinExtent = "100 100";
+        text = "Control List";
+        canMove = true;
+        canClose = false;
+        canMinimize = true;
+        canMaximize = false;
+        resizeWidth = false;
+        resizeHeight = true;
+    };
+    ThemeManager.setProfile(%this.ctrlListWindow, "windowProfile");
+    ThemeManager.setProfile(%this.ctrlListWindow, "windowContentProfile", "ContentProfile");
+    ThemeManager.setProfile(%this.ctrlListWindow, "windowButtonProfile", "CloseButtonProfile");
+    ThemeManager.setProfile(%this.ctrlListWindow, "windowButtonProfile", "MinButtonProfile");
+    ThemeManager.setProfile(%this.ctrlListWindow, "windowButtonProfile", "MaxButtonProfile");
+    %this.guiPage.add(%this.ctrlListWindow);
+
+    %this.onNewGui();
+
+    EditorCore.FinishRegistration(%this.guiPage);
+}
+
+//-----------------------------------------------------------------------------
+
+function GuiEditor::destroy( %this )
+{
+}
+
+function GuiEditor::open(%this)
+{
+}
+
+function GuiEditor::close(%this)
+{
+}
+
+function GuiEditor::onNewGui(%this)
+{
+    %this.blankGui = new GuiControl()
+    {
+        HorizSizing = "width";
+        VertSizing = "height";
+        Position = "0 0";
+        Extent = %this.guiPage.getExtent();
+        Profile = GuiDefaultProfile;
+    };
+    %this.content.add(%this.blankGui);
+    %this.brain.setRoot(%this.blankGui);
+    %this.brain.root = %this.blankGui;
+}

BIN
editor/GuiEditor/images/gridTiny2.PNG


+ 8 - 0
editor/GuiEditor/module.taml

@@ -0,0 +1,8 @@
+<ModuleDefinition
+	ModuleId="GuiEditor"
+	VersionId="1"
+	Dependencies="EditorCore=1"
+	Description="Allows for the creation and editing of GUI files."
+	ScriptFile="GuiEditor.cs"
+	CreateFunction="create"
+	DestroyFunction="destroy" />

+ 47 - 0
editor/GuiEditor/scripts/GuiEditorBrain.cs

@@ -0,0 +1,47 @@
+
+function GuiEditorBrain::onAdd(%this)
+{
+    %this.setFirstResponder();
+    %this.setSnapToGrid("8");
+}
+
+function GuiEditorBrain::onControlDragged(%this, %payload, %position)
+{
+    echo("GuiEditorBrain::onControlDragged - Enter");
+	%pos = VectorSub(%position, %this.getGlobalPosition());
+	%x = getWord(%pos, 0);
+	%y = getWord(%pos, 1);
+	%target = GuiEditor.content.findHitControl(%x, %y);
+
+	while(! %target.isContainer )
+	{
+		%target = %target.getParent();
+	}
+
+	if(%target != %this.getCurrentAddset())
+	{
+		%this.setCurrentAddSet(%target);
+	}
+	//GuiEditorCtrlProperties.update(%ctrl);
+    echo("GuiEditorBrain::onControlDragged - Leave");
+}
+
+function GuiEditorBrain::onControlDropped(%this, %payload, %position)
+{
+    echo("GuiEditorBrain::onControlDropped - Enter");
+   %pos = %payload.getGlobalPosition();
+   %x = getWord(%pos, 0);
+   %y = getWord(%pos, 1);
+
+   if(%x > %this.root.extent.x || %y > %this.root.extent.y)
+   {
+      messageBox("Error", "Cannot add a control outside the root gui element!");
+      return;
+   }
+
+   %this.addNewCtrl(%payload);
+
+   %payload.setPositionGlobal(%x, %y);
+   %this.setFirstResponder();
+    echo("GuiEditorBrain::onControlDropped - Leave");
+}

+ 62 - 0
editor/GuiEditor/scripts/GuiEditorControlList.cs

@@ -0,0 +1,62 @@
+//GuiEditorControlList.cs
+
+function GuiEditorControlList::onAdd(%this)
+{
+    %this.scroller = new GuiScrollCtrl()
+	{
+		HorizSizing="width";
+		VertSizing="height";
+		Position="0 0";
+		Extent="242 355";
+		hScrollBar="alwaysOff";
+		vScrollBar="alwaysOn";
+		constantThumbHeight="0";
+		showArrowButtons="1";
+		scrollBarThickness="14";
+	};
+	ThemeManager.setProfile(%this.scroller, "emptyProfile");
+	ThemeManager.setProfile(%this.scroller, "thumbProfile", "ThumbProfile");
+	ThemeManager.setProfile(%this.scroller, "trackProfile", "TrackProfile");
+	ThemeManager.setProfile(%this.scroller, "scrollArrowProfile", "ArrowProfile");
+	%this.add(%this.scroller);
+
+    %this.listBox = new GuiListBoxCtrl()
+    {
+		class = "GuiEditorControlListBox";
+        HorizSizing="width";
+		VertSizing="height";
+		Position="0 0";
+        AllowMultipleSelections = "0";
+        fitParentWidth = "1";
+    };
+	ThemeManager.setProfile(%this.listBox, "listBoxProfile");
+    %this.scroller.add(%this.listBox);
+
+    %this.populate();
+}
+
+function GuiEditorControlList::onRemove(%this)
+{
+    if(isObject(%this.scroller))
+    {
+        %this.scroller.delete();
+    }
+}
+
+function GuiEditorControlList::populate(%this)
+{
+    %controls = enumerateConsoleClasses("GuiControl");
+	%this.listBox.clearItems();
+	for(%i = 0; %i < getFieldCount(%controls); %i++)
+	{
+		%field = getField(%controls, %i);
+
+        if(%field !$= "GuiCanvas" && (%field $= "SceneWindow" || getSubStr(%field, 0, 3) $= "Gui") && 
+            getSubStr(%field, 0, 10) !$= "GuiConsole" && getSubStr(%field, 0, 7) !$= "GuiEdit" && 
+            getSubStr(%field, 0, 12) !$= "GuiInspector" && %field !$= "GuiMessageVectorCtrl" &&
+            %field !$= "GuiParticleGraphInspector" && %field !$= "GuiGraphCtrl" && %field !$= "GuiSceneObjectCtrl")
+        {
+		    %this.listBox.addItem(%field);
+        }
+	}
+}

+ 45 - 0
editor/GuiEditor/scripts/GuiEditorControlListBox.cs

@@ -0,0 +1,45 @@
+
+function GuiEditorControlListBox::onTouchDragged(%this, %index, %text)
+{
+	echo("test start");
+	%position = %this.getGlobalPosition();
+	echo(%position);
+	%cursorpos = Canvas.getCursorPos();
+	echo(%cursorpos);
+
+	%class = %this.getItemText(%this.getSelectedItem());
+	%payload = eval("return new " @ %class @ "();");
+	echo("payload is " @ %payload.getId());
+	if(!isObject(%payload))
+		return;
+
+	%xOffset = getWord(%payload.extent, 0) / 2;
+	%yOffset = getWord(%payload.extent, 1) / 2;
+	echo(%xOffset SPC %yOffset);
+
+	// position where the drag will start, to prevent visible jumping.
+	%xPos = getWord(%cursorpos, 0) - %xOffset;
+	%yPos = getWord(%cursorpos, 1) - %yOffset;
+	echo(%xPos SPC %yPos);
+
+	%dragCtrl = new GuiDragAndDropCtrl() {
+		canSaveDynamicFields = "0";
+		Profile = "GuiDragAndDropProfile";
+		HorizSizing = "right";
+		VertSizing = "bottom";
+		Position = %xPos SPC %yPos;
+		extent = %payload.extent;
+		MinExtent = "32 32";
+		canSave = "1";
+		Visible = "1";
+		hovertime = "1000";
+		Text = %text;
+		deleteOnMouseUp = true;
+	};
+
+	%dragCtrl.add(%payload);
+	GuiEditor.guiPage.add(%dragCtrl);
+
+	%dragCtrl.startDragging(%xOffset, %yOffset);
+	echo("test end");
+}

+ 1 - 0
editor/main.cs

@@ -31,6 +31,7 @@ EditorManager.scanModules( "./" );
 EditorManager.LoadExplicit("EditorConsole");
 Editormanager.LoadExplicit("ProjectManager");
 EditorManager.LoadExplicit("AssetAdmin");
+EditorManager.LoadExplicit("GuiEditor");
 
 if(!isObject(AppCore))
 {

+ 6 - 6
engine/source/2d/gui/SceneWindow.cc

@@ -214,12 +214,12 @@ void SceneWindow::initPersistFields()
     addField("BackgroundColor", TypeColorF, Offset(mBackgroundColor, SceneWindow), &writeBackgroundColor, "" );
 
 	//Standard scroll bar settings
-	addProtectedField("constantThumbHeight", TypeBool, Offset(mUseConstantHeightThumb, GuiScrollCtrl), &setConstantThumbFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
-	addProtectedField("scrollBarThickness", TypeS32, Offset(mScrollBarThickness, GuiScrollCtrl), &setScrollBarThicknessFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
-	addProtectedField("showArrowButtons", TypeBool, Offset(mShowArrowButtons, GuiScrollCtrl), &setShowArrowButtonsFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
-	addProtectedField("thumbProfile", TypeGuiProfile, Offset(mThumbProfile, GuiScrollCtrl), &setThumbProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
-	addProtectedField("trackProfile", TypeGuiProfile, Offset(mTrackProfile, GuiScrollCtrl), &setTrackProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
-	addProtectedField("arrowProfile", TypeGuiProfile, Offset(mArrowProfile, GuiScrollCtrl), &setArrowProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("constantThumbHeight", TypeBool, Offset(mUseConstantHeightThumb, SceneWindow), &setConstantThumbFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("scrollBarThickness", TypeS32, Offset(mScrollBarThickness, SceneWindow), &setScrollBarThicknessFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("showArrowButtons", TypeBool, Offset(mShowArrowButtons, SceneWindow), &setShowArrowButtonsFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("thumbProfile", TypeGuiProfile, Offset(mThumbProfile, SceneWindow), &setThumbProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("trackProfile", TypeGuiProfile, Offset(mTrackProfile, SceneWindow), &setTrackProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
+	addProtectedField("arrowProfile", TypeGuiProfile, Offset(mArrowProfile, SceneWindow), &setArrowProfileFn, &defaultProtectedGetFn, &writeScrollSettingFn, "");
 }
 
 bool SceneWindow::onWake()

+ 44 - 3
engine/source/gui/guiControl.cc

@@ -355,19 +355,20 @@ void GuiControl::inspectPreApply()
       smEditorHandle->controlInspectPreApply(this);
    
    // The canvas never sleeps
+   // This forced sleep will allow us to unload and reload things in the editor.
+   mPreviouslyAwake = mAwake;
    if(mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
    {
       onSleep(); // release all our resources.
-      mAwake = true;
    }
 }
 
 void GuiControl::inspectPostApply()
 {
    // Shhhhhhh, you don't want to wake the canvas!
-   if(mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
+   // If this control was awake before we should revive it.
+   if(mPreviouslyAwake && !mAwake && dynamic_cast<GuiCanvas*>(this) == NULL )
    {
-      mAwake = false;
       onWake();
    }
    
@@ -2210,6 +2211,46 @@ const char *GuiControl::getText()
 	return mText;
 }
 
+void GuiControl::setDataField(StringTableEntry slotName, const char* array, const char* value)
+{
+	this->findField(slotName);
+	const AbstractClassRep::Field* fld = this->findField(slotName);
+	if(fld)
+	{
+		if (fld->type == AbstractClassRep::DepricatedFieldType ||
+			fld->type == AbstractClassRep::StartGroupFieldType ||
+			fld->type == AbstractClassRep::EndGroupFieldType)
+			return;
+
+		ConsoleBaseType* cbt = ConsoleBaseType::getType(fld->type);
+		bool isProfile = strcmp(cbt->getTypeName(), "TypeGuiProfile") == 0;
+
+		if(isProfile && mAwake)
+		{
+			//Decrease the ref count on the old profile
+			void* dptr = (void*)(((const char*)this) + fld->offset);
+			GuiControlProfile** obj = (GuiControlProfile**)dptr;
+			if((*obj))
+				(*obj)->decRefCount();
+		}
+
+		SimObject::setDataField(slotName, array, value);
+
+		if (isProfile && mAwake)
+		{
+			//Increase the ref count on the new profile
+			void* dptr = (void*)(((const char*)this) + fld->offset);
+			GuiControlProfile** obj = (GuiControlProfile**)dptr;
+			if ((*obj))
+				(*obj)->incRefCount();
+		}
+	}
+	else 
+	{
+		SimObject::setDataField(slotName, array, value);
+	}
+}
+
 AlignmentType GuiControl::getAlignmentType()
 {
     return getAlignmentType(mProfile);

+ 4 - 0
engine/source/gui/guiControl.h

@@ -773,6 +773,7 @@ public:
     S32 getOuterWidth(S32 innerExtent, GuiControlState currentState, GuiControlProfile* profile);
     S32 getOuterHeight(S32 innerExtent, GuiControlState currentState, GuiControlProfile* profile);
 
+
     virtual void inspectPostApply();
     virtual void inspectPreApply();
 
@@ -788,7 +789,10 @@ public:
     void relPosBattery(Point2F& battery, S32 pos, S32 ext, S32 parentExt);
     void resetStoredRelPos() { mUseRelPosH = false; mUseRelPosV = false; }
 
+	virtual void setDataField(StringTableEntry slotName, const char* array, const char* value);
+
 protected:
+	bool mPreviouslyAwake;
 	virtual void interpolateTick(F32 delta) {};
 	virtual void processTick() {};
 	virtual void advanceTime(F32 timeDelta) {};

+ 139 - 133
engine/source/gui/guiListBoxCtrl.cc

@@ -59,7 +59,7 @@ void GuiListBoxCtrl::initPersistFields()
 bool GuiListBoxCtrl::onWake()
 {
    if( !Parent::onWake() )
-      return false;
+	  return false;
 
    updateSize();
 
@@ -77,7 +77,7 @@ void GuiListBoxCtrl::clearItems()
 {
    // Free item list allocated memory
    while( mItems.size() )
-      deleteItem( 0 );
+	  deleteItem( 0 );
 
    // Free our vector lists
    mItems.clear();
@@ -87,11 +87,11 @@ void GuiListBoxCtrl::clearItems()
 void GuiListBoxCtrl::clearSelection()
 {
    if( !mSelectedItems.size() )
-      return;
+	  return;
 
    VectorPtr<LBItem*>::iterator i = mSelectedItems.begin();
    for( ; i != mSelectedItems.end(); i++ )
-      (*i)->isSelected = false;
+	  (*i)->isSelected = false;
 
    mSelectedItems.clear();
 }
@@ -101,8 +101,8 @@ void GuiListBoxCtrl::removeSelection( S32 index )
    // Range Check
    if( index >= mItems.size() || index < 0 )
    {
-      Con::warnf("GuiListBoxCtrl::removeSelection - index out of range!" );
-      return;
+	  Con::warnf("GuiListBoxCtrl::removeSelection - index out of range!" );
+	  return;
    }
 
    removeSelection( mItems[index], index );
@@ -110,20 +110,20 @@ void GuiListBoxCtrl::removeSelection( S32 index )
 void GuiListBoxCtrl::removeSelection( LBItem *item, S32 index )
 {
    if( !mSelectedItems.size() )
-      return;
+	  return;
 
    if( !item )
-      return;
+	  return;
 
    for( S32 i = 0 ; i < mSelectedItems.size(); i++ )
    {
-      if( mSelectedItems[i] == item )
-      {
-         mSelectedItems.erase( &mSelectedItems[i] );
-         item->isSelected = false;
-         Con::executef(caller, 3, "onUnSelect", Con::getIntArg( index ), item->itemText, item->ID);
-         return;
-      }
+	  if( mSelectedItems[i] == item )
+	  {
+		 mSelectedItems.erase( &mSelectedItems[i] );
+		 item->isSelected = false;
+		 Con::executef(caller, 3, "onUnSelect", Con::getIntArg( index ), item->itemText, item->ID);
+		 return;
+	  }
    }
 }
 
@@ -132,8 +132,8 @@ void GuiListBoxCtrl::addSelection( S32 index )
    // Range Check
    if( index >= mItems.size() || index < 0 )
    {
-      Con::warnf("GuiListBoxCtrl::addSelection- index out of range!" );
-      return;
+	  Con::warnf("GuiListBoxCtrl::addSelection- index out of range!" );
+	  return;
    }
 
    addSelection( mItems[index], index );
@@ -142,25 +142,25 @@ void GuiListBoxCtrl::addSelection( LBItem *item, S32 index )
 {
    if( !mMultipleSelections )
    {
-      if( !mSelectedItems.empty() )
-      {
-         LBItem* selItem = mSelectedItems.front();
-         if( selItem != item )
-            clearSelection();
-         else
-            return;
-      }
+	  if( !mSelectedItems.empty() )
+	  {
+		 LBItem* selItem = mSelectedItems.front();
+		 if( selItem != item )
+			clearSelection();
+		 else
+			return;
+	  }
    }
    else
    {
-      if( !mSelectedItems.empty() )
-      {
-         for( S32 i = 0; i < mSelectedItems.size(); i++ )
-         {
-            if( mSelectedItems[ i ] == item )
-               return;
-         }
-      }
+	  if( !mSelectedItems.empty() )
+	  {
+		 for( S32 i = 0; i < mSelectedItems.size(); i++ )
+		 {
+			if( mSelectedItems[ i ] == item )
+			   return;
+		 }
+	  }
    }
 
    item->isSelected = true;
@@ -176,12 +176,12 @@ void GuiListBoxCtrl::addSelection( LBItem *item, S32 index )
 S32 GuiListBoxCtrl::getItemIndex( LBItem *item )
 {
    if( mItems.empty() )
-      return -1;
+	  return -1;
 
    // Lookup the index of an item in our list, by the pointer to the item
    for( S32 i = 0; i < mItems.size(); i++ )
-      if( mItems[i] == item )
-         return i;
+	  if( mItems[i] == item )
+		 return i;
 
    return -1;
 }
@@ -199,11 +199,11 @@ S32 GuiListBoxCtrl::getSelCount()
 S32 GuiListBoxCtrl::getSelectedItem()
 {
    if( mSelectedItems.empty() || mItems.empty() )
-      return -1;
+	  return -1;
 
    for( S32 i = 0 ; i < mItems.size(); i++ )
-      if( mItems[i]->isSelected )
-         return i;
+	  if( mItems[i]->isSelected )
+		 return i;
 
    return -1;
 }
@@ -215,11 +215,11 @@ void GuiListBoxCtrl::getSelectedItems( Vector<S32> &Items )
    
    // If there are no selected items, return an empty vector
    if( mSelectedItems.empty() )
-      return;
+	  return;
    
    for( S32 i = 0; i < mItems.size(); i++ )
-      if( mItems[i]->isSelected )
-         Items.push_back( i );
+	  if( mItems[i]->isSelected )
+		 Items.push_back( i );
 }
 
 S32 GuiListBoxCtrl::findItemText( StringTableEntry text, bool caseSensitive )
@@ -227,22 +227,22 @@ S32 GuiListBoxCtrl::findItemText( StringTableEntry text, bool caseSensitive )
    // Check Proper Arguments
    if( !text || !text[0] || text == StringTable->EmptyString )
    {
-      Con::warnf("GuiListBoxCtrl::findItemText - No Text Specified!");
-      return -1;
+	  Con::warnf("GuiListBoxCtrl::findItemText - No Text Specified!");
+	  return -1;
    }
 
    // Check Items Exist.
    if( mItems.empty() )
-      return -1;
+	  return -1;
 
    // Lookup the index of an item in our list, by the pointer to the item
    for( S32 i = 0; i < mItems.size(); i++ )
    {
-      // Case Sensitive Compare?
-      if( caseSensitive && ( dStrcmp( mItems[i]->itemText, text ) == 0 ) )
-         return i;
-      else if (!caseSensitive && ( dStricmp( mItems[i]->itemText, text ) == 0 ))
-         return i;
+	  // Case Sensitive Compare?
+	  if( caseSensitive && ( dStrcmp( mItems[i]->itemText, text ) == 0 ) )
+		 return i;
+	  else if (!caseSensitive && ( dStricmp( mItems[i]->itemText, text ) == 0 ))
+		 return i;
    }
 
    // Not Found!
@@ -266,15 +266,15 @@ void GuiListBoxCtrl::setCurSel( S32 index )
    // Range Check
    if( index >= mItems.size() )
    {
-      Con::warnf("GuiListBoxCtrl::setCurSel - index out of range!" );
-      return;
+	  Con::warnf("GuiListBoxCtrl::setCurSel - index out of range!" );
+	  return;
    }
 
    // If index -1 is specified, we clear the selection
    if( index == -1 )
    {
-      mSelectedItems.clear();
-      return;
+	  mSelectedItems.clear();
+	  return;
    }
 
    // Add the selection
@@ -285,20 +285,20 @@ void GuiListBoxCtrl::setCurSelRange( S32 start, S32 stop )
 {
    // Verify Selection Range
    if( start < 0 )
-      start = 0;
+	  start = 0;
    else if( start > mItems.size() )
-      start = mItems.size();
+	  start = mItems.size();
 
    if( stop < 0 )
-      stop = 0;
+	  stop = 0;
    else if( stop > mItems.size() )
-      stop = mItems.size();
+	  stop = mItems.size();
 
    S32 iterStart = ( start < stop ) ? start : stop;
    S32 iterStop  = ( start < stop ) ? stop : start;
 
    for( ; iterStart <= iterStop; iterStart++ )
-      addSelection( mItems[iterStart], iterStart );
+	  addSelection( mItems[iterStart], iterStart );
 }
 
 S32 GuiListBoxCtrl::addItem( StringTableEntry text, void *itemData )
@@ -324,8 +324,8 @@ void GuiListBoxCtrl::setItemColor( S32 index, ColorF color )
 {
    if ((index >= mItems.size()) || index < 0)
    {
-      Con::warnf("GuiListBoxCtrl::setItemColor - invalid index");
-      return;
+	  Con::warnf("GuiListBoxCtrl::setItemColor - invalid index");
+	  return;
    }
 
    LBItem* item = mItems[index];
@@ -462,20 +462,20 @@ S32 GuiListBoxCtrl::insertItem( S32 index, StringTableEntry text, void *itemData
 {
    // If the index is greater than our list size, insert it at the end
    if( index >= mItems.size() )
-      index = mItems.size();
+	  index = mItems.size();
 
    // Sanity checking
    if( !text )
    {
-      Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL string" );
-      return -1;
+	  Con::warnf("GuiListBoxCtrl::insertItem - cannot add NULL string" );
+	  return -1;
    }
 
    LBItem *newItem = new LBItem;
    if( !newItem )
    {
-      Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
-      return -1;
+	  Con::warnf("GuiListBoxCtrl::insertItem - error allocating item memory!" );
+	  return -1;
    }
 
    // Assign item data
@@ -521,29 +521,29 @@ void  GuiListBoxCtrl::deleteItem( S32 index )
    // Range Check
    if( index >= mItems.size() || index < 0 )
    {
-      Con::warnf("GuiListBoxCtrl::deleteItem - index out of range!" );
-      return;
+	  Con::warnf("GuiListBoxCtrl::deleteItem - index out of range!" );
+	  return;
    }
 
    // Grab our item
    LBItem* item = mItems[ index ];
    if( !item )
    {
-      Con::warnf("GuiListBoxCtrl::deleteItem - Bad Item Data!" );
-      return;
+	  Con::warnf("GuiListBoxCtrl::deleteItem - Bad Item Data!" );
+	  return;
    }
 
    // Remove it from the selected list.
    if( item->isSelected )
    {
-      for( VectorPtr<LBItem*>::iterator i = mSelectedItems.begin(); i != mSelectedItems.end(); i++ )
-      {
-         if( item == *i )
-         {
-            mSelectedItems.erase_fast( i );
-            break;
-         }
-      }
+	  for( VectorPtr<LBItem*>::iterator i = mSelectedItems.begin(); i != mSelectedItems.end(); i++ )
+	  {
+		 if( item == *i )
+		 {
+			mSelectedItems.erase_fast( i );
+			break;
+		 }
+	  }
    }
 
    // Remove it from the list
@@ -558,8 +558,8 @@ StringTableEntry GuiListBoxCtrl::getItemText( S32 index )
    // Range Checking
    if( index > mItems.size() || index < 0 )
    {
-      Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
-      return StringTable->EmptyString;
+	  Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
+	  return StringTable->EmptyString;
    }
    
    return mItems[ index ]->itemText;   
@@ -570,14 +570,14 @@ void GuiListBoxCtrl::setItemText( S32 index, StringTableEntry text )
    // Sanity Checking
    if( !text )
    {
-      Con::warnf("GuiListBoxCtrl::setItemText - Invalid Text Specified!" );
-      return;
+	  Con::warnf("GuiListBoxCtrl::setItemText - Invalid Text Specified!" );
+	  return;
    }
    // Range Checking
    if( index > mItems.size() || index < 0 )
    {
-      Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
-      return;
+	  Con::warnf( "GuiListBoxCtrl::getItemText - index out of range!" );
+	  return;
    }
 
    mItems[ index ]->itemText = StringTable->insert( text );
@@ -588,22 +588,22 @@ void GuiListBoxCtrl::setItemText( S32 index, StringTableEntry text )
 void GuiListBoxCtrl::updateSize()
 {
    if( !mProfile || !mProfile->getFont(mFontSizeAdjust))
-      return;
+	  return;
 
    GFont *font = mProfile->getFont(mFontSizeAdjust);
    Point2I contentSize = Point2I(10, font->getHeight() + 2);
 
    if (!mFitParentWidth)
    {
-      // Find the maximum width cell:
-      S32 maxWidth = 1;
-      for ( U32 i = 0; i < (U32)mItems.size(); i++ )
-      {
-         S32 width = font->getStrWidth( mItems[i]->itemText );
-         if( width > maxWidth )
-            maxWidth = width;
-      }
-      contentSize.x = maxWidth + 6;
+	  // Find the maximum width cell:
+	  S32 maxWidth = 1;
+	  for ( U32 i = 0; i < (U32)mItems.size(); i++ )
+	  {
+		 S32 width = font->getStrWidth( mItems[i]->itemText );
+		 if( width > maxWidth )
+			maxWidth = width;
+	  }
+	  contentSize.x = maxWidth + 6;
    }
 
    mItemSize = this->getOuterExtent(contentSize, NormalState, mProfile);
@@ -687,7 +687,7 @@ void GuiListBoxCtrl::onRenderItem( RectI &itemRect, LBItem *item )
    if (item->hasColor)
    {
 	   RectI drawArea = RectI(contentRect.point.x, contentRect.point.y, contentRect.extent.y, contentRect.extent.y);
-      ColorI color = item->color;
+	  ColorI color = item->color;
 	   renderColorBullet(drawArea, color, 5);
 
 	   contentRect.point.x += contentRect.extent.y;
@@ -708,13 +708,11 @@ void GuiListBoxCtrl::ScrollToIndex(const S32 targetIndex)
 #pragma region InputEvents
 void GuiListBoxCtrl::onTouchDragged(const GuiEvent &event)
 {
-	if (!mActive)
+	if (!mActive || !mVisible)
 	{
 		return;
 	}
 
-   Parent::onTouchDragged(event);
-
    Point2I localPoint = globalToLocalCoord(event.mousePoint);
    S32 itemHit = (localPoint.y < 0) ? -1 : (S32)mFloor((F32)localPoint.y / (F32)mItemSize.y);
 
@@ -725,13 +723,21 @@ void GuiListBoxCtrl::onTouchDragged(const GuiEvent &event)
    if (hitItem == NULL || !hitItem->isActive)
 	   return;
 
-   if(caller->isMethod("onTouchDragged"))
-      Con::executef(caller, 3, "onTouchDragged", Con::getIntArg(itemHit), hitItem->itemText, hitItem->ID);
+	if(caller->isMethod("onTouchDragged"))
+	{
+		Con::executef(caller, 3, "onTouchDragged", Con::getIntArg(itemHit), hitItem->itemText, hitItem->ID);
+	}
+	else
+	{
+		GuiControl* parent = getParent();
+		if (parent)
+			parent->onTouchDragged(event);
+	}
 }
 
 void GuiListBoxCtrl::onTouchDown( const GuiEvent &event )
 {
-	if (!mActive)
+	if (!mActive || !mVisible)
 	{
 		return;
 	}
@@ -742,23 +748,23 @@ void GuiListBoxCtrl::onTouchDown( const GuiEvent &event )
    S32 itemHit = ( localPoint.y < 0 ) ? -1 : (S32)mFloor( (F32)localPoint.y / (F32)mItemSize.y );
 
    if ( itemHit >= mItems.size() || itemHit == -1 )
-      return;
+	  return;
 
    LBItem *hitItem = mItems[ itemHit ];
    if ( hitItem == NULL || !hitItem->isActive)
-      return;
+	  return;
 
    // If we're not a multiple selection listbox, we simply select/unselect an item
    if( !mMultipleSelections )
    {
-      // No current selection?  Just select the cell and move on
-      S32 selItem = getSelectedItem();
+	  // No current selection?  Just select the cell and move on
+	  S32 selItem = getSelectedItem();
 
-      if ( selItem != itemHit && selItem != -1 )
-         clearSelection();
+	  if ( selItem != itemHit && selItem != -1 )
+		 clearSelection();
 
-      // Set the current selection
-      setCurSel( itemHit );
+	  // Set the current selection
+	  setCurSel( itemHit );
 
 		if( itemHit == selItem && event.mouseClickCount == 2)
 		{
@@ -770,42 +776,42 @@ void GuiListBoxCtrl::onTouchDown( const GuiEvent &event )
 			Con::executef(caller, 3, "onClick", Con::getIntArg(itemHit), hitItem->itemText, hitItem->ID);
 		}
 
-      // Store the clicked item
-      mLastClickItem = hitItem;
+	  // Store the clicked item
+	  mLastClickItem = hitItem;
 
-      return;
+	  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 );
+	  // 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 );
+	  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( getSelCount() != 0 )
+	  {
+		 S32 selItem = getSelectedItem();
+		 if( selItem != -1 && mItems[selItem] != hitItem )
+			clearSelection();
+	  }
+	  addSelection( hitItem, itemHit );
    }
 
    if( hitItem == mLastClickItem && event.mouseClickCount == 2)

+ 2 - 10
engine/source/gui/guiTypes.cc

@@ -769,12 +769,7 @@ void GuiControlProfile::incRefCount(F32 fontAdjust)
 
 void GuiControlProfile::decRefCount()
 {
-   // Not sure why this was being tripped when
-   // switching profiles in guieditor, but...
-   // following the way this works, it seems that a profile
-   // is being removed before it is added =/
-
-   AssertFatal(mRefCount, avar("GuiControlProfile::%s::decRefCount: zero ref count", this->getName()));
+	AssertFatal(mRefCount, avar("GuiControlProfile::%s::decRefCount: zero ref count", this->getName()));
    if(!mRefCount)
 	  return;
    --mRefCount;
@@ -923,11 +918,8 @@ ConsoleSetType( TypeGuiProfile )
    if((*obj) == profile)
 	  return;
 
-   if(*obj)
-	  (*obj)->decRefCount();
-
    *obj = profile;
-   (*obj)->incRefCount();
+   //Note: reference counts are change in guiControl only if the guiControl is awake.
 }
 
 ConsoleGetType( TypeGuiProfile )

+ 1 - 1
engine/source/sim/simObject.h

@@ -413,7 +413,7 @@ public:
     /// @param   slotName    Field to access.
     /// @param   array       String containing index into array; if NULL, it is ignored.
     /// @param   value       Value to store.
-    void setDataField(StringTableEntry slotName, const char *array, const char *value);
+    virtual void setDataField(StringTableEntry slotName, const char *array, const char *value);
 
     const char *getPrefixedDataField(StringTableEntry fieldName, const char *array);
 

+ 2 - 2
library/AppCore/gui/guiProfiles.cs

@@ -112,14 +112,14 @@ function AppCore::createGuiProfiles(%this)
 	%this.SafeCreateNamedObject("LeftRightCursor", new GuiCursor()
 	{
 	   hotSpot = "0.5 0";
-	   renderOffset = "0.5 0";
+	   renderOffset = "0.5 0.4";
 	   bitmapName = "^AppCore/gui/images/cursors/leftRight";
 	});
 
 	%this.SafeCreateNamedObject("UpDownCursor", new GuiCursor()
 	{
 	   hotSpot = "1 1";
-	   renderOffset = "0 1";
+	   renderOffset = "0.5 0.5";
 	   bitmapName = "^AppCore/gui/images/cursors/upDown";
 	});