Browse Source

Attempting to get selection working again

Marko Pintera 12 years ago
parent
commit
4e2dae9cc5

+ 3 - 0
BansheeEngine/Include/BsGUIInputCaret.h

@@ -33,6 +33,9 @@ namespace BansheeEngine
 		CM::Int2 getCaretPosition(const CM::Int2& offset) const;
 		CM::UINT32 getCaretHeight() const;
 
+		bool isCaretAtNewline() const;
+		CM::UINT32 getMaxCaretPos() const;
+		CM::UINT32 getCaretPos() const { return mCaretPos; }
 	private:
 		CM::UINT32 mCaretPos;
 		TextSprite* mTextSprite; // TODO - Try to get rid of this and implement its methods internally?

+ 70 - 11
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -361,9 +361,17 @@ namespace BansheeEngine
 						mText.erase(mText.begin() + mSelectionStart, mText.begin() + mSelectionEnd);
 						mInputCaret->updateText(getTextDesc());
 
-						mInputCaret->moveCaretToChar(mSelectionStart, CARET_BEFORE);
-						scrollTextToCaret();
+						if(mSelectionStart > 0)
+						{
+							UINT32 newCaretPos = mSelectionStart - 1;
+							mInputCaret->moveCaretToChar(newCaretPos, CARET_AFTER);
+						}
+						else
+						{
+							mInputCaret->moveCaretToChar(0, CARET_BEFORE);
+						}
 
+						scrollTextToCaret();
 						clearSelection();
 					}
 					else
@@ -394,9 +402,18 @@ namespace BansheeEngine
 					{
 						mText.erase(mText.begin() + mSelectionStart, mText.begin() + mSelectionEnd);
 						mInputCaret->updateText(getTextDesc());
-						mInputCaret->moveCaretToChar(mSelectionStart, CARET_BEFORE);
-						scrollTextToCaret();
 
+						if(mSelectionStart > 0)
+						{
+							UINT32 newCaretPos = mSelectionStart - 1;
+							mInputCaret->moveCaretToChar(newCaretPos, CARET_AFTER);
+						}
+						else
+						{
+							mInputCaret->moveCaretToChar(0, CARET_BEFORE);
+						}
+
+						scrollTextToCaret();
 						clearSelection();
 					}
 					else
@@ -422,10 +439,21 @@ namespace BansheeEngine
 					if(!mSelectionShown)
 						showSelection(mInputCaret->getCharIdxAtCaretPos());
 
+					bool isAtNewline = false;
+
+					do 
+					{
+						isAtNewline = mInputCaret->isCaretAtNewline();
+						mInputCaret->moveCaretLeft();
+
+					} while (isAtNewline && mInputCaret->getCaretPos() > 0);
+
+					scrollTextToCaret();
+
 					if(mSelectionAnchor == mSelectionEnd)
-						mSelectionStart = (UINT32)std::max(0, (INT32)mSelectionStart - 1);
+						mSelectionStart = std::max(0U, mInputCaret->getCharIdxAtCaretPos());
 					else
-						mSelectionEnd = (UINT32)std::max(0, (INT32)mSelectionEnd - 1);
+						mSelectionEnd = std::max(0U, mInputCaret->getCharIdxAtCaretPos());
 
 					markAsDirty();
 					return true;
@@ -448,11 +476,21 @@ namespace BansheeEngine
 					if(!mSelectionShown)
 						showSelection(mInputCaret->getCharIdxAtCaretPos());
 
+					mInputCaret->moveCaretRight();
+
+					UINT32 maxCaretPos = mInputCaret->getMaxCaretPos();
+					while (mInputCaret->isCaretAtNewline() && mInputCaret->getCaretPos() <= maxCaretPos)
+					{
+						mInputCaret->moveCaretRight();
+					} 
+
+					scrollTextToCaret();
+
 					if(mSelectionAnchor == mSelectionStart)
-						mSelectionEnd = std::min((UINT32)mText.size(), mSelectionEnd + 1);
+						mSelectionEnd = std::max(0U, mInputCaret->getCharIdxAtCaretPos());
 					else
-						mSelectionStart = std::min((UINT32)mText.size(), mSelectionStart + 1);
-
+						mSelectionStart = std::max(0U, mInputCaret->getCharIdxAtCaretPos());
+						
 					markAsDirty();
 					return true;
 				}
@@ -659,14 +697,22 @@ namespace BansheeEngine
 			return selectionRects;
 
 		UINT32 startLine = mTextSprite->getLineForChar(mSelectionStart);
-		UINT32 endLine = mTextSprite->getLineForChar(mSelectionEnd - 1);
+
+		UINT32 endLine = startLine;
+		if(mSelectionEnd > 0)
+			endLine = mTextSprite->getLineForChar(mSelectionEnd - 1);
 
 		{
 			const SpriteLineDesc& lineDesc = mTextSprite->getLineDesc(startLine);
 			Rect startChar = mTextSprite->getCharRect(mSelectionStart);
 			UINT32 endCharIdx = mSelectionEnd - 1;
-			if(endCharIdx >= lineDesc.endChar)
+			if(endCharIdx >= lineDesc.endChar && endCharIdx > 0)
+			{
 				endCharIdx = lineDesc.endChar - 1;
+
+				if(startLine != (mTextSprite->getNumLines() - 1) && endCharIdx > 0) // Ignore newline char
+					endCharIdx -= 1;
+			}
 			
 			Rect endChar = mTextSprite->getCharRect(endCharIdx);
 
@@ -685,6 +731,10 @@ namespace BansheeEngine
 			if(lineDesc.startChar == lineDesc.endChar)
 				continue;
 
+			UINT32 endCharIdx = lineDesc.endChar;
+			if(endCharIdx > 0) // Ignore newline char
+				endCharIdx -= 1;
+
 			Rect startChar = mTextSprite->getCharRect(lineDesc.startChar);
 			Rect endChar = mTextSprite->getCharRect(lineDesc.endChar);
 
@@ -703,6 +753,15 @@ namespace BansheeEngine
 
 			if(lineDesc.startChar != lineDesc.endChar)
 			{
+				UINT32 endCharIdx = mSelectionEnd - 1;
+				if(endCharIdx > 0) // Ignore newline char
+				{
+					endCharIdx -= 1;
+
+					if(endLine != (mTextSprite->getNumLines() - 1) && endCharIdx > 0) // Ignore newline char
+						endCharIdx -= 1;
+				}
+
 				Rect startChar = mTextSprite->getCharRect(lineDesc.startChar);
 				Rect endChar = mTextSprite->getCharRect(mSelectionEnd - 1);
 

+ 47 - 0
BansheeEngine/Source/BsGUIInputCaret.cpp

@@ -283,4 +283,51 @@ namespace BansheeEngine
 
 		return 0;
 	}
+
+	bool GUIInputCaret::isCaretAtNewline() const
+	{
+		if(mTextDesc.text.size() == 0)
+			return true;
+
+		UINT32 numLines = mTextSprite->getNumLines();
+		UINT32 curPos = 0;
+		for(UINT32 i = 0; i < numLines; i++)
+		{
+			const SpriteLineDesc& lineDesc = mTextSprite->getLineDesc(i);
+
+			if(curPos == mCaretPos)
+				return true;
+
+			if(i == 0)
+				curPos++; // Beginning of the line has a special caret position, primarily so we can
+						  // still place a caret on an empty line
+
+			UINT32 numChars = lineDesc.endChar - lineDesc.startChar - 1;
+			curPos += numChars;
+		}
+
+		return false;
+	}
+
+	UINT32 GUIInputCaret::getMaxCaretPos() const
+	{
+		if(mTextDesc.text.size() == 0)
+			return 0;
+
+		UINT32 numLines = mTextSprite->getNumLines();
+		UINT32 maxPos = 0;
+		for(UINT32 i = 0; i < numLines; i++)
+		{
+			const SpriteLineDesc& lineDesc = mTextSprite->getLineDesc(i);
+
+			if(i == 0)
+				maxPos++; // Beginning of the line has a special caret position, primarily so we can
+						  // still place a caret on an empty line
+
+			UINT32 numChars = lineDesc.endChar - lineDesc.startChar;
+			maxPos += numChars;
+		}
+
+		return maxPos - 1;
+	}
 }

+ 1 - 1
BansheeEngine/Source/BsTextSprite.cpp

@@ -159,7 +159,7 @@ namespace BansheeEngine
 
 		// If char is newline we don't have any geometry to return
 		const SpriteLineDesc& lineDesc = getLineDesc(lineIdx);
-		if(lineIdx != (getNumLines() - 1) && lineDesc.endChar == (charIdx - 1))
+		if(lineIdx != (getNumLines() - 1) && (lineDesc.endChar - 1) == charIdx)
 			return Rect();
 
 		UINT32 numNewlineChars = lineIdx;

+ 6 - 1
TODO.txt

@@ -24,7 +24,12 @@ IMMEDIATE:
 
 TextBox needed elements:
  - Drag mouse to update selection
- - Text scroll. Typing outside of textbox should scroll the text so caret is visible.
+ - Input caret positioning ignores kerning which means the caret is sometimes 
+   in the middle of another char. Try typing "fa" and moving caret in front of "f".
+     - I really need to update InputCaret so it holds its own sprite data
+ - Add a way to move selection up/down
+ - Update selection move right so it correctly moves to next line. Currently I fixed some issues but there are still problems.
+ - There's an issue when selecting an empty line.
  - Get DebugCamera to ignore input if GUI has already processed it
  - Cut/Copy/Paste
  - LATER