瀏覽代碼

Fixed Some Tab Issues

This fixes a number of issues with tabbing through the controls on the inspector. This adds a way to display when a check box and a drop down is the first responder. It also sets visibility of hidden direct children of an expand control to false when the expand control is collapsed and further makes it so non-visible controls cannot be tabbed to. It also fixes the focus code so that textboxes can lose focus when a click happens outside of the text box. When a textbox gains focus through tabbing, it now selects the contents of the box.
Peter Robinson 2 年之前
父節點
當前提交
de0219d9fd

+ 6 - 4
editor/EditorCore/Themes/BaseTheme/BaseTheme.cs

@@ -830,6 +830,7 @@ function BaseTheme::makeCheckboxProfile(%this)
 		fontColorNA = %this.setAlpha(%this.color4, 100);
 		align = left;
 		vAlign = middle;
+		cursorColor = %this.color5;
 
 		borderLeft = %borderLight;
 		borderRight = %borderDark;
@@ -1175,10 +1176,10 @@ function BaseTheme::makeTextEditProfile(%this)
 
 	%textBorderH = new GuiBorderProfile()
 	{
-		padding = 10;
-		paddingHL = 10;
-		paddingSL = 10;
-		paddingNA = 10;
+		padding = 5;
+		paddingHL = 5;
+		paddingSL = 5;
+		paddingNA = 5;
 
 		border = %this.borderSize;
 		borderHL = %this.borderSize;
@@ -1637,6 +1638,7 @@ function BaseTheme::makeDropDownProfile(%this)
 		fontColorNA = %this.setAlpha(%this.color1, 100);
 		align = left;
 		vAlign = middle;
+		cursorColor = %this.color5;
 
 		borderLeft = %borderLightH;
 		borderRight = %borderDarkH;

+ 1 - 1
editor/EditorCore/Themes/TorqueSuit/TorqueSuitTheme.cs

@@ -373,7 +373,7 @@ function TorqueSuitTheme::makeTextEditProfile(%this)
 		borderRight = %textBorderRight;
 		borderLeft = %textBorderLeft;
 
-		tab = false;
+		tab = true;
 		canKeyFocus = true;
 		returnTab = true;
 	};

+ 2 - 0
engine/source/gui/buttons/guiButtonCtrl.cc

@@ -208,6 +208,7 @@ bool GuiButtonCtrl::onKeyDown(const GuiEvent &event)
 			AUDIOHANDLE handle = alxCreateSource(mProfile->mSoundButtonDown);
 			alxPlay(handle);
 		}
+		mDepressed = true;
 		return true;
 	}
 	//otherwise, pass the event to it's parent
@@ -224,6 +225,7 @@ bool GuiButtonCtrl::onKeyUp(const GuiEvent &event)
 		(event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE) &&
 		event.modifier == 0)
 	{
+		mDepressed = false;
 		onAction();
 		return true;
 	}

+ 6 - 1
engine/source/gui/buttons/guiCheckBoxCtrl.cc

@@ -73,7 +73,7 @@ void GuiCheckBoxCtrl::onRender(Point2I offset, const RectI &updateRect)
 	{
 		currentState = mStateOn ? GuiControlState::SelectedStateOn : GuiControlState::SelectedState;
 	}
-	else if (mMouseOver)
+	else if (mMouseOver || isFirstResponder())
 	{
 		currentState = mStateOn ? GuiControlState::HighlightStateOn : GuiControlState::HighlightState;
 	}
@@ -119,6 +119,11 @@ void GuiCheckBoxCtrl::onRender(Point2I offset, const RectI &updateRect)
 void GuiCheckBoxCtrl::renderInnerControl(RectI &boxRect, const GuiControlState currentState)
 {
 	renderUniversalRect(boxRect, mProfile, currentState);
+
+	if(isFirstResponder())
+	{
+		dglDrawRect(boxRect, mProfile->mCursorColor);
+	}
 }
 
 void GuiCheckBoxCtrl::onAction()

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

@@ -162,7 +162,7 @@ GuiControlState GuiDropDownCtrl::getCurrentState()
 		return GuiControlState::DisabledState;
 	else if (mDepressed || mIsOpen)
 		return GuiControlState::SelectedState;
-	else if (mMouseOver)
+	else if (mMouseOver || isFirstResponder())
 		return GuiControlState::HighlightState;
 	else
 		return GuiControlState::NormalState;
@@ -206,6 +206,11 @@ void GuiDropDownCtrl::onRender(Point2I offset, const RectI& updateRect)
 		}
 		renderText(contentRect.point, contentRect.extent, mListBox->getItemText(index), mProfile);
 	}
+
+	if (isFirstResponder())
+	{
+		dglDrawRect(ctrlRect, mProfile->mCursorColor);
+	}
 }
 
 bool GuiDropDownCtrl::onKeyDown(const GuiEvent &event)

+ 86 - 0
engine/source/gui/containers/guiExpandCtrl.cc

@@ -37,6 +37,8 @@ GuiExpandCtrl::GuiExpandCtrl()
    mEasingFunction = EasingFunction::Linear;
    mAnimationLength = 500;
    mCalcGuard = false;
+
+   setField("profile", "GuiDefaultProfile");
 }
 
 void GuiExpandCtrl::initPersistFields()
@@ -47,6 +49,13 @@ void GuiExpandCtrl::initPersistFields()
   addField("easeTimeExpand", TypeS32, Offset(mAnimationLength, GuiExpandCtrl));
 }
 
+void GuiExpandCtrl::addObject(SimObject* obj)
+{
+	Parent::addObject(obj);
+
+	toggleHiddenChildren();
+}
+
 void GuiExpandCtrl::parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent)
 {
 	Point2I newPosition = getPosition();
@@ -114,6 +123,7 @@ void GuiExpandCtrl::parentResized(const Point2I &oldParentExtent, const Point2I
 	else
 	{
 		mBounds.extent = mCollapsedExtent;
+		toggleHiddenChildren();
 	}
 	setUpdate();
 }
@@ -122,6 +132,7 @@ void GuiExpandCtrl::childResized(GuiControl* child)
 {
 	calcExpandedExtent();
 	Parent::childResized(child);
+	toggleHiddenChildren();
 }
 
 void GuiExpandCtrl::setCollapsedExtent(const Point2I &extent)
@@ -161,6 +172,15 @@ void GuiExpandCtrl::setExpanded(bool isExpanded)
 	mAnimationProgress = 1 - mAnimationProgress;
 	mExpanded = isExpanded;
 	setProcessTicks(true);
+
+	if (mExpanded)
+	{
+		startExpand();
+	}
+	else
+	{
+		startCollapse();
+	}
 }
 
 bool GuiExpandCtrl::processExpansion()
@@ -205,6 +225,14 @@ bool GuiExpandCtrl::processExpansion()
 	if (mAnimationProgress >= 1.0f)
 	{
 		mAnimationProgress = 1.0f;
+		if (!mExpanded)
+		{
+			collapseComplete();
+		}
+		else
+		{
+			expandComplete();
+		}
 		return false;
 	}
 	return true;
@@ -221,4 +249,62 @@ void GuiExpandCtrl::processTick()
 	{
 		setProcessTicks(false);
 	}
+}
+
+void GuiExpandCtrl::startExpand()
+{
+	if (isMethod("onStartExpand"))
+	{
+		Con::executef(this, 2, "onStartExpand");
+	}
+
+	toggleHiddenChildren();
+}
+
+void GuiExpandCtrl::startCollapse()
+{
+	if (isMethod("onStartCollapse"))
+	{
+		Con::executef(this, 2, "onStartCollapse");
+	}
+}
+
+void GuiExpandCtrl::expandComplete()
+{
+	if (isMethod("onExpandComplete"))
+	{
+		Con::executef(this, 2, "onExpandComplete");
+	}
+}
+
+void GuiExpandCtrl::collapseComplete()
+{
+	if (isMethod("onCollapseComplete"))
+	{
+		Con::executef(this, 2, "onCollapseComplete");
+	}
+
+	toggleHiddenChildren();
+}
+
+void GuiExpandCtrl::toggleHiddenChildren()
+{
+	RectI innerRect = getInnerRect();
+	innerRect.point = Point2I::Zero;
+
+	for (iterator i = begin(); i != end(); i++)
+	{
+		GuiControl* ctrl = static_cast<GuiControl*>(*i);
+		
+		RectI childBounds = ctrl->getBounds();
+		RectI parentBounds = RectI(innerRect);
+		if (!mExpanded && !parentBounds.intersect(childBounds))
+		{
+			ctrl->mVisible = false;
+		}
+		else
+		{
+			ctrl->mVisible = true;
+		}
+	}
 }

+ 12 - 6
engine/source/gui/containers/guiExpandCtrl.h

@@ -60,14 +60,20 @@ protected:
 public:
 	GuiExpandCtrl();
 
-   virtual void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
-   virtual void childResized(GuiControl* child);
+	virtual void addObject(SimObject* obj);
+	virtual void parentResized(const Point2I &oldParentExtent, const Point2I &newParentExtent);
+	virtual void childResized(GuiControl* child);
 
-   inline bool getExpanded() { return mExpanded; };
-   void setExpanded(bool isExpanded);
+	inline bool getExpanded() { return mExpanded; };
+	void setExpanded(bool isExpanded);
+	void startExpand();
+	void startCollapse();
+	void expandComplete();
+	void collapseComplete();
+	void toggleHiddenChildren();
 
-   static void initPersistFields();
-   DECLARE_CONOBJECT(GuiExpandCtrl);
+	static void initPersistFields();
+	DECLARE_CONOBJECT(GuiExpandCtrl);
 
 protected:
 	virtual void processTick();

+ 4 - 9
engine/source/gui/containers/guiWindowCtrl.cc

@@ -251,7 +251,7 @@ void GuiWindowCtrl::onTouchDown(const GuiEvent &event)
    curHitRegion = findHitRegion(localPoint);
    mDepressed = true;
 
-   //select this window - move it to the front, and set the first responder
+   //select this window - move it to the front
    selectWindow();
 
    //if we clicked within the title bar
@@ -669,30 +669,25 @@ bool GuiWindowCtrl::onKeyDown(const GuiEvent &event)
    return Parent::onKeyDown(event);
 }
 
-void GuiWindowCtrl::onFocus()
+void GuiWindowCtrl::onFocus(bool foundFirstResponder)
 {
 	//bubble the focus up
 	GuiControl *parent = getParent();
 	if (parent)
 	{
 		parent->pushObjectToBack(this);
-		parent->onFocus();
+		parent->onFocus(foundFirstResponder);
 	}
-
-	setFirstResponder(mFirstResponder);
 }
 
 void GuiWindowCtrl::selectWindow(void)
 {
-   //first make sure this window is the front most of its siblings
+   //make sure this window is the front most of its siblings
    GuiControl *parent = getParent();
    if (parent)
    {
       parent->pushObjectToBack(this);
    }
-
-   //also set the first responder to be the one within this window
-   setFirstResponder(mFirstResponder);
 }
 
 void GuiWindowCtrl::ResizeComplete()

+ 1 - 1
engine/source/gui/containers/guiWindowCtrl.h

@@ -132,7 +132,7 @@ class GuiWindowCtrl : public GuiControl
       void onTouchUp(const GuiEvent &event);
 	  void onTouchLeave(const GuiEvent &event);
 
-	  virtual void onFocus();
+	  virtual void onFocus(bool foundFirstResponder);
 
       //only cycle tabs through the current window, so overwrite the method
       GuiControl* findNextTabable(GuiControl *curResponder, bool firstCall = true);

+ 1 - 3
engine/source/gui/editor/guiInspector.cc

@@ -237,9 +237,7 @@ void GuiInspector::inspectPostApply()
 
 	if (mTarget)
 	{
-		SimObjectPtr<SimObject> oldTarget = mTarget;
-		mTarget = NULL;
-		inspectObject(oldTarget);
+		inspectObject(mTarget);
 	}
 }
 

+ 11 - 2
engine/source/gui/guiCanvas.cc

@@ -629,7 +629,7 @@ void GuiCanvas::rootMouseDown(const GuiEvent &event)
              GuiControl* controlHit = ctrl->findHitControl(event.mousePoint);
 
              //Regardless of what the control does, it has the user's focus.
-             controlHit->onFocus();
+             controlHit->onFocus(false);
 
              if (controlHit->mUseInput)
              {
@@ -733,7 +733,7 @@ void GuiCanvas::rootScreenTouchDown(const GuiEvent &event)
                 }
 
                 //Regardless of what the control does, it has the user's focus.
-                controlHit->onFocus();
+                controlHit->onFocus(false);
 
                 if (controlHit->mUseInput)
                 {
@@ -1521,6 +1521,15 @@ void GuiCanvas::resetUpdateRegions()
    mCurUpdateRect = mOldUpdateRects[0];
 }
 
+void GuiCanvas::onFocus(bool foundFirstResponder)
+{
+	if (!foundFirstResponder && mFirstResponder)
+	{
+		mFirstResponder->onLoseFirstResponder();
+		mFirstResponder = NULL;
+	}
+}
+
 void GuiCanvas::setFirstResponder( GuiControl* newResponder )
 {
     GuiControl* oldResponder = mFirstResponder;

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

@@ -397,6 +397,8 @@ public:
    /// @param   modifier   Shift, ctrl, etc.
    virtual void addAcceleratorKey(GuiControl *ctrl, U32 index, U32 keyCode, U32 modifier);
 
+   virtual void onFocus(bool foundFirstResponder);
+
    /// Sets the first responder.
    /// @param   firstResponder    Control to designate as first responder
    virtual void setFirstResponder(GuiControl *firstResponder);

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

@@ -183,6 +183,8 @@ void GuiConsoleEditCtrl::onLoseFirstResponder()
 
     if (isMethod("onLoseFirstResponder"))
         Con::executef(this, 2, "onLoseFirstResponder");
+	if (isMethod("onBlur"))
+		Con::executef(this, 2, "onBlur");
 
     mSelector.setFirstResponder(false);
     mTextOffsetY = 0;

+ 46 - 27
engine/source/gui/guiControl.cc

@@ -1657,16 +1657,19 @@ void GuiControl::onMiddleMouseDragged(const GuiEvent &event)
 GuiControl* GuiControl::findFirstTabable()
 {
    GuiControl *tabCtrl = NULL;
-   iterator i;
-   for (i = begin(); i != end(); i++)
+   if(mVisible && mAwake)
    {
-      GuiControl *ctrl = static_cast<GuiControl *>(*i);
-      tabCtrl = ctrl->findFirstTabable();
-      if (tabCtrl)
-      {
-         mFirstResponder = tabCtrl;
-         return tabCtrl;
-      }
+	   iterator i;
+	   for (i = begin(); i != end(); i++)
+	   {
+		  GuiControl *ctrl = static_cast<GuiControl *>(*i);
+		  tabCtrl = ctrl->findFirstTabable();
+		  if (tabCtrl)
+		  {
+			 mFirstResponder = tabCtrl;
+			 return tabCtrl;
+		  }
+	   }
    }
 
    //nothing was found, therefore, see if this ctrl is tabable
@@ -1683,11 +1686,14 @@ GuiControl* GuiControl::findLastTabable(bool firstCall)
    if (mProfile->mTabable)
       smPrevResponder = this;
 
-   iterator i;
-   for (i = begin(); i != end(); i++)
-   {
-      GuiControl *ctrl = static_cast<GuiControl *>(*i);
-      ctrl->findLastTabable(false);
+	if(mVisible && mAwake)
+	{
+	   iterator i;
+	   for (i = begin(); i != end(); i++)
+	   {
+		  GuiControl *ctrl = static_cast<GuiControl *>(*i);
+		  ctrl->findLastTabable(false);
+	   }
    }
 
    //after the entire tree has been traversed, return the last responder found
@@ -1711,12 +1717,16 @@ GuiControl *GuiControl::findNextTabable(GuiControl *curResponder, bool firstCall
 
    //loop through, checking each child to see if it is the one that follows the firstResponder
    GuiControl *tabCtrl = NULL;
-   iterator i;
-   for (i = begin(); i != end(); i++)
+
+   if (mVisible && mAwake)
    {
-      GuiControl *ctrl = static_cast<GuiControl *>(*i);
-      tabCtrl = ctrl->findNextTabable(curResponder, false);
-      if (tabCtrl) break;
+	   iterator i;
+	   for (i = begin(); i != end(); i++)
+	   {
+		  GuiControl *ctrl = static_cast<GuiControl *>(*i);
+		  tabCtrl = ctrl->findNextTabable(curResponder, false);
+		  if (tabCtrl) break;
+	   }
    }
    mFirstResponder = tabCtrl;
    return tabCtrl;
@@ -1737,12 +1747,16 @@ GuiControl *GuiControl::findPrevTabable(GuiControl *curResponder, bool firstCall
 
    //loop through, checking each child to see if it is the one that follows the firstResponder
    GuiControl *tabCtrl = NULL;
-   iterator i;
-   for (i = begin(); i != end(); i++)
+
+   if (mVisible && mAwake)
    {
-      GuiControl *ctrl = static_cast<GuiControl *>(*i);
-      tabCtrl = ctrl->findPrevTabable(curResponder, false);
-      if (tabCtrl) break;
+	   iterator i;
+	   for (i = begin(); i != end(); i++)
+	   {
+		  GuiControl *ctrl = static_cast<GuiControl *>(*i);
+		  tabCtrl = ctrl->findPrevTabable(curResponder, false);
+		  if (tabCtrl) break;
+	   }
    }
    mFirstResponder = tabCtrl;
    return tabCtrl;
@@ -1781,12 +1795,17 @@ bool GuiControl::ControlIsChild(GuiControl *child)
    return false;
 }
 
-void GuiControl::onFocus()
+void GuiControl::onFocus(bool foundFirstResponder)
 {
+	if (!foundFirstResponder && isFirstResponder())
+	{
+		foundFirstResponder = true;
+	}
+
 	//bubble the focus up
 	GuiControl *parent = getParent();
 	if (parent)
-		parent->onFocus();
+		parent->onFocus(foundFirstResponder);
 }
 
 bool GuiControl::isFirstResponder()
@@ -1810,7 +1829,7 @@ void GuiControl::setFirstResponder()
     if ( mAwake && mVisible )
     {
 		GuiControl *parent = getParent();
-		if (mProfile->mCanKeyFocus == true && parent != NULL )
+		if (mProfile->mCanKeyFocus && parent )
 		{
 			parent->setFirstResponder(this);
 

+ 3 - 2
engine/source/gui/guiControl.h

@@ -598,8 +598,9 @@ public:
     /// @}
 
 	//Called just before onTouch down for the hit control. The focus should then bubble up through the 
-	//controls allowing windows to move to the front.
-	virtual void onFocus();
+	//controls allowing windows to move to the front. If the focus arrives at the canvas and the first responder
+	//wasn't found, then the first responder loses the focus.
+	virtual void onFocus(bool foundFirstResponder);
     
     /// @name Editor Mouse Events
     ///

+ 23 - 12
engine/source/gui/guiTextEditCtrl.cc

@@ -647,16 +647,16 @@ void GuiTextEditCtrl::onTouchDown( const GuiEvent &event )
     if (!mVisible || !mAwake)
         return;
 
+   mouseLock();
+   setFirstResponder();
+   mSelector.resetCursorBlink();
+
     mSelector.setTextLength(mTextBuffer.length());
-   if(event.mouseClickCount > 2)
-   {
-        selectAllText();
-   } 
-   else if(event.mouseClickCount > 1)
+   if(event.mouseClickCount == 2)
    {
        mSelector.selectWholeWord(mTextBuffer);
    }
-   else 
+   else if (event.mouseClickCount < 2)
    {
        S32 newCursorPos = calculateIbeamPosition(event.mousePoint);
        if (event.modifier & SI_SHIFT)
@@ -668,10 +668,6 @@ void GuiTextEditCtrl::onTouchDown( const GuiEvent &event )
            mSelector.setCursorPosition(newCursorPos);
        }
    }
-
-   mouseLock();
-   setFirstResponder();
-   mSelector.resetCursorBlink();
     if( isMethod("onTouchDown") )
     {
         char buf[3][32];
@@ -946,6 +942,11 @@ bool GuiTextEditCtrl::tabPrev()
 
 void GuiTextEditCtrl::setFirstResponder()
 {
+	selectAllText();
+	if(mTextBuffer.length() == 0)
+	{
+		mSelector.selectTo(mTextBuffer.length());
+	}
     mSelector.setFirstResponder(true);
    Parent::setFirstResponder();
    
@@ -968,6 +969,8 @@ void GuiTextEditCtrl::onLoseFirstResponder()
 
    if( isMethod( "onLoseFirstResponder" ) )
       Con::executef( this, 2, "onLoseFirstResponder", valid);
+   if (isMethod("onBlur"))
+	   Con::executef(this, 2, "onBlur", valid);
 
     mSelector.setFirstResponder(false);
     mTextOffsetY = 0;
@@ -1635,12 +1638,20 @@ bool GuiTextEditCtrl::handleShiftArrowKey(GuiDirection direction)
     else if (direction == GuiDirection::Up)
     {
         S32 newCursorPos = getLineAdjustedIbeamPosition(-mProfile->getFont(mFontSizeAdjust)->getHeight());
-        modifySelectBlock(newCursorPos);
+		if (newCursorPos == mSelector.getCursorPos())
+		{
+			newCursorPos = 0;
+		}
+		modifySelectBlock(newCursorPos);
     }
     else if (direction == GuiDirection::Down)
     {
         S32 newCursorPos = getLineAdjustedIbeamPosition(mProfile->getFont(mFontSizeAdjust)->getHeight());
-        modifySelectBlock(newCursorPos);
+		if (newCursorPos == mSelector.getCursorPos())
+		{
+			newCursorPos = mTextBuffer.length();
+		}
+		modifySelectBlock(newCursorPos);
     }
     setUpdate();
     mSelector.resetCursorBlink();