瀏覽代碼

Added proper clipping and offset for the new way of calculating input caret position

Marko Pintera 12 年之前
父節點
當前提交
e42aeb07ec

+ 12 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -105,6 +105,18 @@ namespace BansheeEngine
 		virtual bool _isInBounds(const CM::Int2 position) const;
 		bool _acceptsKeyboardFocus() const { return mAcceptsKeyboardFocus; }
 
+		/**
+		 * @brief	Returns a clip rectangle relative to the element, used for offsetting
+		 * 			the input text.
+		 */
+		virtual CM::Int2 _getTextInputOffset() const { return CM::Int2(); }
+
+		/**
+		 * @brief	Returns a clip rectangle relative to the element, used for clipping
+		 * 			the input text.
+		 */
+		virtual CM::Rect _getTextInputRect() const { return CM::Rect(); }
+
 		const GUILayoutOptions& _getLayoutOptions() const { return mLayoutOptions; }
 	protected:
 		virtual void updateRenderElementsInternal();

+ 3 - 0
BansheeEngine/Include/BsGUIInputBox.h

@@ -51,6 +51,9 @@ namespace BansheeEngine
 		virtual CM::UINT32 _getOptimalWidth() const;
 		virtual CM::UINT32 _getOptimalHeight() const;
 
+		virtual CM::Int2 _getTextInputOffset() const;
+		virtual CM::Rect _getTextInputRect() const;
+
 		virtual CM::UINT32 _getRenderElementDepth(CM::UINT32 renderElementIdx) const;
 		virtual void _setFocus(bool focus);
 	private:

+ 5 - 3
BansheeEngine/Include/BsGUIInputTool.h

@@ -31,17 +31,19 @@ namespace BansheeEngine
 		GUIInputTool();
 		~GUIInputTool();
 
-		void updateText(const TEXT_SPRITE_DESC& textDesc, const CM::Int2& offset, const CM::Int2 clipOffset);
+		void updateText(const GUIElement* element, const TEXT_SPRITE_DESC& textDesc);
 	protected:
+		const GUIElement* mElement;
+
 		CM::Vector2* mQuads;
 		CM::UINT32 mNumQuads;
 
 		TEXT_SPRITE_DESC mTextDesc;
-		CM::Int2 mTextOffset;
-		CM::Int2 mClipOffset;
 
 		CM::Vector<GUIInputLineDesc>::type mLineDescs;
 
+		CM::Int2 getTextOffset() const;
+
 		CM::UINT32 getNumLines() const { return (CM::UINT32)mLineDescs.size(); }
 		const GUIInputLineDesc& getLineDesc(CM::UINT32 lineIdx) const { return mLineDescs.at(lineIdx); }
 		CM::UINT32 getLineForChar(CM::UINT32 charIdx, bool newlineCountsOnNextLine = false) const;

+ 26 - 12
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -123,13 +123,13 @@ namespace BansheeEngine
 
 		if(mCaretShown && gGUIManager().getCaretBlinkState())
 		{
-			gGUIManager().getInputCaretTool()->updateText(textDesc, getTextOffset(), mTextOffset); // TODO - These shouldn't be here. Only call this when one of these parameters changes.
+			gGUIManager().getInputCaretTool()->updateText(this, textDesc); // TODO - These shouldn't be here. Only call this when one of these parameters changes.
 			gGUIManager().getInputCaretTool()->updateSprite();
 		}
 
 		if(mSelectionShown)
 		{
-			gGUIManager().getInputSelectionTool()->updateText(textDesc, getTextOffset(), mTextOffset); // TODO - These shouldn't be here. Only call this when one of these parameters changes.
+			gGUIManager().getInputSelectionTool()->updateText(this, textDesc); // TODO - These shouldn't be here. Only call this when one of these parameters changes.
 			gGUIManager().getInputSelectionTool()->updateSprite();
 		}
 
@@ -296,6 +296,20 @@ namespace BansheeEngine
 		return 0;
 	}
 
+	CM::Int2 GUIInputBox::_getTextInputOffset() const
+	{
+		return mTextOffset;	
+	}
+
+	CM::Rect GUIInputBox::_getTextInputRect() const
+	{
+		Rect textBounds = getContentBounds();
+		textBounds.x -= mOffset.x;
+		textBounds.y -= mOffset.y;
+
+		return textBounds;
+	}
+
 	UINT32 GUIInputBox::_getRenderElementDepth(UINT32 renderElementIdx) const
 	{
 		UINT32 localRenderElementIdx;
@@ -652,7 +666,7 @@ namespace BansheeEngine
 
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		Int2 offset = getTextOffset();
-		gGUIManager().getInputCaretTool()->updateText(textDesc, offset, mTextOffset);
+		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
 		markContentAsDirty();
 	}
 
@@ -667,7 +681,7 @@ namespace BansheeEngine
 	{
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		Int2 offset = getTextOffset();
-		gGUIManager().getInputSelectionTool()->updateText(textDesc, offset, mTextOffset);
+		gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 
 		gGUIManager().getInputSelectionTool()->showSelection(anchorCaretPos);
 		mSelectionShown = true;
@@ -721,8 +735,8 @@ namespace BansheeEngine
 		mTextOffset += offset;
 
 		Int2 newOffset = getTextOffset();
-		gGUIManager().getInputCaretTool()->updateText(textDesc, newOffset, mTextOffset);
-		gGUIManager().getInputSelectionTool()->updateText(textDesc, newOffset, mTextOffset);
+		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
+		gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 
 		markContentAsDirty();
 	}
@@ -734,8 +748,8 @@ namespace BansheeEngine
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		Int2 offset = getTextOffset();
 
-		gGUIManager().getInputCaretTool()->updateText(textDesc, offset, mTextOffset);
-		gGUIManager().getInputSelectionTool()->updateText(textDesc, offset, mTextOffset);
+		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
+		gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 	}
 
 	void GUIInputBox::eraseChar(CM::UINT32 charIdx)
@@ -745,8 +759,8 @@ namespace BansheeEngine
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		Int2 offset = getTextOffset();
 
-		gGUIManager().getInputCaretTool()->updateText(textDesc, offset, mTextOffset);
-		gGUIManager().getInputSelectionTool()->updateText(textDesc, offset, mTextOffset);
+		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
+		gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 	}
 
 	void GUIInputBox::deleteSelectedText()
@@ -756,8 +770,8 @@ namespace BansheeEngine
 
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		Int2 offset = getTextOffset();
-		gGUIManager().getInputCaretTool()->updateText(textDesc, offset, mTextOffset);
-		gGUIManager().getInputSelectionTool()->updateText(textDesc, offset, mTextOffset);
+		gGUIManager().getInputCaretTool()->updateText(this, textDesc);
+		gGUIManager().getInputSelectionTool()->updateText(this, textDesc);
 
 		if(selStart > 0)
 		{

+ 21 - 16
BansheeEngine/Source/BsGUIInputCaret.cpp

@@ -1,6 +1,7 @@
 #include "BsGUIInputCaret.h"
 #include "BsGUIManager.h"
 #include "BsImageSprite.h"
+#include "BsGUIElement.h"
 #include "CmFont.h"
 
 using namespace CamelotFramework;
@@ -20,21 +21,21 @@ namespace BansheeEngine
 
 	Int2 GUIInputCaret::getSpriteOffset() const
 	{
-		return getCaretPosition(mTextOffset);
+		return getCaretPosition(getTextOffset());
 	}
 
 	Rect GUIInputCaret::getSpriteClipRect(const CM::Rect& parentClipRect) const
 	{
-		Int2 offset = getSpriteOffset();
+		Int2 clipOffset = getSpriteOffset() - mElement->_getOffset() - 
+			Int2(mElement->_getTextInputRect().x, mElement->_getTextInputRect().y);
 
-		Rect clipRect(-offset.x + mTextOffset.x - mClipOffset.x, -offset.y + mTextOffset.y - mClipOffset.y, 
-			mTextDesc.width, mTextDesc.height);
+		Rect clipRect(-clipOffset.x, -clipOffset.y, mTextDesc.width, mTextDesc.height);
 
 		Rect localParentCliprect = parentClipRect;
 
 		// Move parent rect to our space
-		localParentCliprect.x += clipRect.x;
-		localParentCliprect.y += clipRect.y;
+		localParentCliprect.x += mElement->_getTextInputOffset().x + clipRect.x;
+		localParentCliprect.y += mElement->_getTextInputOffset().y + clipRect.y;
 
 		// Clip our rectangle so its not larger then the parent
 		clipRect.clip(localParentCliprect);
@@ -96,7 +97,7 @@ namespace BansheeEngine
 			return;
 		}
 
-		Int2 caretCoords = getCaretPosition(mTextOffset);
+		Int2 caretCoords = getCaretPosition(mElement->_getTextInputOffset());
 		caretCoords.y -= getCaretHeight();
 
 		moveCaretToPos(caretCoords);
@@ -121,7 +122,7 @@ namespace BansheeEngine
 			return;
 		}
 
-		Int2 caretCoords = getCaretPosition(mTextOffset);
+		Int2 caretCoords = getCaretPosition(mElement->_getTextInputOffset());
 		caretCoords.y += getCaretHeight();
 
 		moveCaretToPos(caretCoords);
@@ -156,7 +157,8 @@ namespace BansheeEngine
 			{
 				const GUIInputLineDesc& line = getLineDesc(i);
 
-				if(pos.y >= line.getLineYStart() && pos.y < (line.getLineYStart() + (INT32)line.getLineHeight()))
+				INT32 lineStart = line.getLineYStart() + getTextOffset().y;
+				if(pos.y >= lineStart && pos.y < (lineStart + (INT32)line.getLineHeight()))
 				{
 					mCaretPos = curPos;
 					return;
@@ -166,12 +168,15 @@ namespace BansheeEngine
 				curPos += numChars;
 			}
 
-			const GUIInputLineDesc& firstLine = getLineDesc(0);
+			{
+				const GUIInputLineDesc& firstLine = getLineDesc(0);
+				INT32 lineStart = firstLine.getLineYStart() + getTextOffset().y;
 
-			if(pos.y < firstLine.getLineYStart()) // Before first line
-				mCaretPos = 0;
-			else // After last line
-				mCaretPos = curPos - 1;
+				if(pos.y < lineStart) // Before first line
+					mCaretPos = 0;
+				else // After last line
+					mCaretPos = curPos - 1;
+			}
 		}
 	}
 
@@ -232,7 +237,7 @@ namespace BansheeEngine
 				if(mCaretPos == curPos)
 				{
 					// Caret is on line start
-					return Int2(offset.x, lineDesc.getLineYStart());
+					return Int2(offset.x, lineDesc.getLineYStart() + getTextOffset().y);
 				}
 
 				curPos += lineDesc.getEndChar(false) - lineDesc.getStartChar() + 1; // + 1 for special line start position
@@ -246,7 +251,7 @@ namespace BansheeEngine
 
 			Rect charRect = getCharRect(charIdx);
 			UINT32 lineIdx = getLineForChar(charIdx);
-			UINT32 yOffset = getLineDesc(lineIdx).getLineYStart();
+			UINT32 yOffset = getLineDesc(lineIdx).getLineYStart() + getTextOffset().y;
 
 			return Int2(charRect.x + charRect.width, yOffset);
 		}

+ 15 - 13
BansheeEngine/Source/BsGUIInputSelection.cpp

@@ -1,5 +1,6 @@
 #include "BsGUIInputSelection.h"
 #include "BsImageSprite.h"
+#include "BsGUIElement.h"
 #include "BsGUIManager.h"
 
 using namespace CamelotFramework;
@@ -53,28 +54,29 @@ namespace BansheeEngine
 
 	Int2 GUIInputSelection::getSelectionSpriteOffset(UINT32 spriteIdx) const
 	{
-		return Int2(mSelectionRects[spriteIdx].x, mSelectionRects[spriteIdx].y);
+		return Int2(mSelectionRects[spriteIdx].x, mSelectionRects[spriteIdx].y) + getTextOffset();
 	}
 
 	Rect GUIInputSelection::getSelectionSpriteClipRect(UINT32 spriteIdx, const CM::Rect& parentClipRect) const
 	{
-		Rect clipRect(-mSelectionRects[spriteIdx].x + mTextOffset.x - mClipOffset.x, 
-			-mSelectionRects[spriteIdx].y + mTextOffset.y - mClipOffset.y, 
-			mTextDesc.width, mTextDesc.height);
+		return parentClipRect;
+		//Rect clipRect(-(mElement->_getTextInputOffset().x + mSelectionRects[spriteIdx].x) + mElement->_getTextInputRect().x, 
+		//	-mSelectionRects[spriteIdx].y - mElement->_getTextInputOffset().y - mElement->_getTextInputRect().y, 
+		//	mTextDesc.width, mTextDesc.height);
 
-		Rect localParentCliprect = parentClipRect;
+		//Rect localParentCliprect = parentClipRect;
 
-		// Move parent rect to our space
-		localParentCliprect.x += clipRect.x;
-		localParentCliprect.y += clipRect.y;
+		//// Move parent rect to our space
+		//localParentCliprect.x += clipRect.x;
+		//localParentCliprect.y += clipRect.y;
 
-		// Clip our rectangle so its not larger then the parent
-		clipRect.clip(localParentCliprect);
+		//// Clip our rectangle so its not larger then the parent
+		//clipRect.clip(localParentCliprect);
 
-		// Increase clip size by 1, so we can fit the caret in case it is fully at the end of the text
-		clipRect.width += 1;
+		//// Increase clip size by 1, so we can fit the caret in case it is fully at the end of the text
+		//clipRect.width += 1;
 
-		return clipRect;
+		//return clipRect;
 	}
 
 	Vector<Rect>::type GUIInputSelection::getSelectionRects() const

+ 20 - 15
BansheeEngine/Source/BsGUIInputTool.cpp

@@ -1,4 +1,5 @@
 #include "BsGUIInputTool.h"
+#include "BsGUIElement.h"
 #include "CmMath.h"
 #include "CmVector2.h"
 #include "CmFont.h"
@@ -8,17 +9,16 @@ using namespace CamelotFramework;
 namespace BansheeEngine
 {
 	GUIInputTool::GUIInputTool()
-		:mQuads(nullptr), mNumQuads(0)
+		:mQuads(nullptr), mNumQuads(0), mElement(nullptr)
 	{ }
 
 	GUIInputTool::~GUIInputTool()
 	{ }
 
-	void GUIInputTool::updateText(const TEXT_SPRITE_DESC& textDesc, const Int2& offset, const Int2 clipOffset)
+	void GUIInputTool::updateText(const GUIElement* element, const TEXT_SPRITE_DESC& textDesc)
 	{
+		mElement = element;
 		mTextDesc = textDesc;
-		mTextOffset = offset;
-		mClipOffset = clipOffset;
 
 		mLineDescs.clear();
 
@@ -44,13 +44,9 @@ namespace BansheeEngine
 			mQuads, nullptr, nullptr, mNumQuads);
 
 		UINT32 numVerts = mNumQuads * 4;
-		Vector2 vecOffset((float)mTextOffset.x, (float)mTextOffset.y);
-		for(UINT32 i = 0; i < numVerts; i++)
-			mQuads[i] = mQuads[i] + vecOffset;
 
 		// Store cached line data
 		UINT32 curCharIdx = 0;
-		UINT32 cachedLineY = 0;
 		UINT32 curLineIdx = 0;
 		Vector<Int2>::type alignmentOffsets = TextSprite::getAlignmentOffsets(lines, mTextDesc.width, 
 			mTextDesc.height, mTextDesc.horzAlign, mTextDesc.vertAlign);
@@ -63,17 +59,21 @@ namespace BansheeEngine
 			UINT32 startChar = curCharIdx;
 			UINT32 endChar = curCharIdx + line.getNumChars() + (hasNewline ? 1 : 0);
 			UINT32 lineHeight = line.getYOffset();
-			INT32 lineYStart = alignmentOffsets[curLineIdx].y + mTextOffset.y;
+			INT32 lineYStart = alignmentOffsets[curLineIdx].y;
 
 			GUIInputLineDesc lineDesc(startChar, endChar, lineHeight, lineYStart, hasNewline);
 			mLineDescs.push_back(lineDesc);
 
 			curCharIdx = lineDesc.getEndChar();
-			cachedLineY += lineDesc.getLineHeight();
 			curLineIdx++;
 		}
 	}
 
+	Int2 GUIInputTool::getTextOffset() const
+	{
+		return mElement->_getOffset() + mElement->_getTextInputOffset() + Int2(mElement->_getTextInputRect().x, mElement->_getTextInputRect().y);
+	}
+
 	CM::Rect GUIInputTool::getCharRect(UINT32 charIdx) const
 	{
 		UINT32 lineIdx = getLineForChar(charIdx);
@@ -87,16 +87,18 @@ namespace BansheeEngine
 		for(UINT32 i = 0; i < lineIdx; i++)
 			numNewlineChars += (getLineDesc(i).hasNewlineChar() ? 1 : 0);
 
+		Int2 textOffset = getTextOffset();
+
 		UINT32 quadIdx = charIdx - numNewlineChars;
 		if(quadIdx >= 0 && quadIdx < mNumQuads)
 		{
 			UINT32 vertIdx = quadIdx * 4;
 
 			Rect charRect;
-			charRect.x = Math::RoundToInt(mQuads[vertIdx + 0].x);
-			charRect.y = Math::RoundToInt(mQuads[vertIdx + 0].y);
-			charRect.width = Math::RoundToInt(mQuads[vertIdx + 3].x - charRect.x);
-			charRect.height = Math::RoundToInt(mQuads[vertIdx + 3].y - charRect.y);
+			charRect.x = Math::RoundToInt(mQuads[vertIdx + 0].x) + textOffset.x;
+			charRect.y = Math::RoundToInt(mQuads[vertIdx + 0].y) + textOffset.y;
+			charRect.width = Math::RoundToInt((mQuads[vertIdx + 3].x + textOffset.x) - charRect.x);
+			charRect.height = Math::RoundToInt((mQuads[vertIdx + 3].y + textOffset.y) - charRect.y);
 
 			return charRect;
 		}
@@ -114,7 +116,8 @@ namespace BansheeEngine
 		UINT32 lineIdx = 0;
 		for(auto& line : mLineDescs)
 		{
-			if(pos.y >= line.getLineYStart() && pos.y < (line.getLineYStart() + (INT32)line.getLineHeight()))
+			INT32 lineStart = line.getLineYStart() + getTextOffset().y;
+			if(pos.y >= lineStart && pos.y < (lineStart + (INT32)line.getLineHeight()))
 			{
 				lineStartChar = line.getStartChar();
 				lineEndChar = line.getEndChar(false);
@@ -135,12 +138,14 @@ namespace BansheeEngine
 		UINT32 nearestChar = 0;
 		bool foundChar = false;
 
+		Int2 textOffset = getTextOffset();
 		for(UINT32 i = lineStartQuad; i < lineEndQuad; i++)
 		{
 			UINT32 curVert = i * 4;
 
 			float centerX = mQuads[curVert + 0].x + mQuads[curVert + 1].x;
 			centerX *= 0.5f;
+			centerX += textOffset.x;
 
 			float dist = Math::Abs(centerX - vecPos.x);
 			if(dist < nearestDist)