Bladeren bron

Update To GuiTextEditCtrl

This is a major update to the GuiTextEditCtrl. It allows the control to support multiline editing by turning on text wrap - removing the need for the GuiMLTextEditCtrl. It also changes the control to use std::string instead of the custom TextBuffer. Behavior has also been modernized. For example, double clicking a word highlights the word instead of all. Text boxes also now change on hover using the HL state. Two new values were added to the GuiControlProfile to handle the colors when text is selected. The only loss of functionality is that UTF16 strings are not supported, although this could be added at a later point.
Peter Robinson 4 jaren geleden
bovenliggende
commit
37c7bb1e3e

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

@@ -1005,18 +1005,20 @@ function BaseTheme::makeTextEditProfile(%this)
 		borderDefault = %labelBorder;
 	};
 
-	//border for text boxes never use the HL state.
 	%textBorderV = new GuiBorderProfile()
 	{
 		padding = 2;
+		paddingHL = 2;
 		paddingSL = 2;
 		paddingNA = 2;
 
 		border = %this.borderSize;
+		borderHL = %this.borderSize;
 		borderSL = %this.borderSize;
 		borderNA = %this.borderSize;
 
 		borderColor = %this.color3;
+		borderColorHL = %this.adjustValue(%this.color5, 10);
 		borderColorSL = %this.color5;
 		borderColorNA = %this.setAlpha(%this.color3, 100);
 	};
@@ -1024,14 +1026,17 @@ function BaseTheme::makeTextEditProfile(%this)
 	%textBorderH = new GuiBorderProfile()
 	{
 		padding = 10;
+		paddingHL = 10;
 		paddingSL = 10;
 		paddingNA = 10;
 
 		border = %this.borderSize;
+		borderHL = %this.borderSize;
 		borderSL = %this.borderSize;
 		borderNA = %this.borderSize;
 
 		borderColor = %this.color3;
+		borderColorHL = %this.adjustValue(%this.color5, 10);
 		borderColorSL = %this.color5;
 		borderColorNA = %this.setAlpha(%this.color3, 100);
 	};
@@ -1039,9 +1044,10 @@ function BaseTheme::makeTextEditProfile(%this)
 	%this.textEditProfile = new GuiControlProfile()
 	{
 		fillColor = %this.color4;
-		fillColorHL = %this.color5;//used for selected text
+		fillColorHL = %this.adjustValue(%this.color4, 10);
 		fillColorSL = %this.color4;
 		fillColorNA = %this.setAlpha(%this.color4, 80);
+		fillColorTextSL = %this.color5;
 
 		fontType = %this.font[3];
 		fontDirectory = %this.fontDirectory;
@@ -1050,14 +1056,16 @@ function BaseTheme::makeTextEditProfile(%this)
 		fontColorHL = %this.adjustValue(%this.color1, 10);
 		fontColorSL = %this.color1;
 		fontColorNA = %this.setAlpha(%this.color1, 100);
+		fontColorTextSL = %this.color1;
 		align = left;
-		cursorColor = %this.color1;
+		vAlign = middle;
+		cursorColor = %this.color2;
 
 		borderDefault = %textBorderV;
 		borderRight = %textBorderH;
 		borderLeft = %textBorderH;
 
-		tab = false;
+		tab = true;
 		canKeyFocus = true;
 		returnTab = true;
 		useInput = true;

+ 3 - 2
editor/EditorCore/Themes/TorqueSuit/TorqueSuitTheme.cs

@@ -292,7 +292,6 @@ function TorqueSuitTheme::makeTextEditProfile(%this)
 		borderDefault = %labelBorder;
 	};
 
-	//border for text boxes never use the HL state.
 	%textBorderV = new GuiBorderProfile()
 	{
 		padding = 3;
@@ -350,9 +349,10 @@ function TorqueSuitTheme::makeTextEditProfile(%this)
 	%this.textEditProfile = new GuiControlProfile()
 	{
 		fillColor = %this.color1;
-		fillColorHL = %this.adjustValue(%this.color1, 20);//used for selected text
+		fillColorHL = %this.adjustValue(%this.color1, 10);
 		fillColorSL = %this.color1;
 		fillColorNA = %this.setAlpha(%this.color1, 80);
+		fillColorTextSL = %this.adjustValue(%this.color5, -30);
 
 		fontType = %this.font[3];
 		fontDirectory = %this.fontDirectory;
@@ -361,6 +361,7 @@ function TorqueSuitTheme::makeTextEditProfile(%this)
 		fontColorHL = %this.adjustValue(%this.color4, 10);
 		fontColorSL = %this.color4;
 		fontColorNA = %this.setAlpha(%this.color4, 100);
+		fontColorTextSL = %this.color1;
 		align = left;
 		cursorColor = %this.color5;
 

+ 0 - 4
engine/compilers/VisualStudio 2019/Torque 2D.vcxproj

@@ -638,8 +638,6 @@
     <ClCompile Include="..\..\source\gui\guiInputCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiListBoxCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiMessageVectorCtrl.cc" />
-    <ClCompile Include="..\..\source\gui\guiMLTextCtrl.cc" />
-    <ClCompile Include="..\..\source\gui\guiMLTextEditCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiMouseEventCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiProgressCtrl.cc" />
     <ClCompile Include="..\..\source\gui\guiSliderCtrl.cc" />
@@ -1138,8 +1136,6 @@
     <ClInclude Include="..\..\source\gui\guiListBoxCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiListBoxCtrl_ScriptBinding.h" />
     <ClInclude Include="..\..\source\gui\guiMessageVectorCtrl.h" />
-    <ClInclude Include="..\..\source\gui\guiMLTextCtrl.h" />
-    <ClInclude Include="..\..\source\gui\guiMLTextEditCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiMouseEventCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiProgressCtrl.h" />
     <ClInclude Include="..\..\source\gui\guiProgressCtrl_ScriptBinding.h" />

+ 0 - 12
engine/compilers/VisualStudio 2019/Torque 2D.vcxproj.filters

@@ -756,12 +756,6 @@
     <ClCompile Include="..\..\source\gui\guiMessageVectorCtrl.cc">
       <Filter>gui</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\source\gui\guiMLTextCtrl.cc">
-      <Filter>gui</Filter>
-    </ClCompile>
-    <ClCompile Include="..\..\source\gui\guiMLTextEditCtrl.cc">
-      <Filter>gui</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\source\gui\guiMouseEventCtrl.cc">
       <Filter>gui</Filter>
     </ClCompile>
@@ -1962,12 +1956,6 @@
     <ClInclude Include="..\..\source\gui\guiMessageVectorCtrl.h">
       <Filter>gui</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\source\gui\guiMLTextCtrl.h">
-      <Filter>gui</Filter>
-    </ClInclude>
-    <ClInclude Include="..\..\source\gui\guiMLTextEditCtrl.h">
-      <Filter>gui</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\source\gui\guiMouseEventCtrl.h">
       <Filter>gui</Filter>
     </ClInclude>

+ 45 - 0
engine/source/2d/core/Utility.h

@@ -39,6 +39,10 @@
 #include "math/mMath.h"
 #endif
 
+#include <algorithm> 
+#include <cctype>
+#include <locale>
+
 //-----------------------------------------------------------------------------
 // Miscellaneous Defines.
 //-----------------------------------------------------------------------------
@@ -83,6 +87,47 @@ U32 mGetStringElementCount( const char *string );
 U32 mConvertStringToMask( const char* string );
 const char* mConvertMaskToString( const U32 mask );
 
+//------------------------------------------------------------------------------
+// Modern C++17 string trim functions
+
+// trim from start (in place)
+static inline void ltrim(std::string& s) {
+    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
+        return !std::isspace(ch);
+    }));
+}
+
+// trim from end (in place)
+static inline void rtrim(std::string& s) {
+    s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
+        return !std::isspace(ch);
+    }).base(), s.end());
+}
+
+// trim from both ends (in place)
+static inline void trim(std::string& s) {
+    ltrim(s);
+    rtrim(s);
+}
+
+// trim from start (copying)
+static inline std::string ltrim_copy(std::string s) {
+    ltrim(s);
+    return s;
+}
+
+// trim from end (copying)
+static inline std::string rtrim_copy(std::string s) {
+    rtrim(s);
+    return s;
+}
+
+// trim from both ends (copying)
+static inline std::string trim_copy(std::string s) {
+    trim(s);
+    return s;
+}
+
 } // Namespace Utility.
 
 #endif // _UTILITY_H_

+ 124 - 46
engine/source/gui/guiConsoleEditCtrl.cc

@@ -27,6 +27,23 @@
 #include "gui/guiConsoleEditCtrl.h"
 #include "memory/frameAllocator.h"
 
+GuiConsoleEditHistory::GuiConsoleEditHistory() 
+{ 
+    historyList = vector<string>();
+}
+
+const string& GuiConsoleEditHistory::getPrevHistory()
+{
+    index = static_cast<U32>(getMax(static_cast<S32>(index - 1), 0));
+    return historyList.size() == 0 ? workingText : historyList[index];
+}
+const string& GuiConsoleEditHistory::getNextHistory()
+{
+    index = getMin(index + 1, historyList.size());
+    return historyList.size() == index ? workingText : historyList[index];
+}
+
+
 IMPLEMENT_CONOBJECT(GuiConsoleEditCtrl);
 
 GuiConsoleEditCtrl::GuiConsoleEditCtrl()
@@ -34,8 +51,8 @@ GuiConsoleEditCtrl::GuiConsoleEditCtrl()
    mSinkAllKeyEvents = true;
    mSiblingScroller = NULL;
    mUseSiblingScroller = true;
-   mHistorySize = 40;
    mReturnCausesTab = false;
+   mHistory = GuiConsoleEditHistory();
 }
 
 void GuiConsoleEditCtrl::initPersistFields()
@@ -47,56 +64,117 @@ void GuiConsoleEditCtrl::initPersistFields()
    endGroup("GuiConsoleEditCtrl");
 }
 
-bool GuiConsoleEditCtrl::onKeyDown(const GuiEvent &event)
+bool GuiConsoleEditCtrl::onKeyDown(const GuiEvent& event)
 {
-   setUpdate();
-
-   if (event.keyCode == KEY_TAB) 
-   {
-      // Get a buffer that can hold the completed text...
-      FrameTemp<UTF8> tmpBuff(GuiTextEditCtrl::MAX_STRING_LENGTH);
-      // And copy the text to be completed into it.
-      mTextBuffer.getCopy8(tmpBuff, GuiTextEditCtrl::MAX_STRING_LENGTH);
-
-      // perform the completion
-      bool forward = event.modifier & SI_SHIFT;
-      mCursorPos = Con::tabComplete(tmpBuff, mCursorPos, GuiTextEditCtrl::MAX_STRING_LENGTH, forward);
-
-      // place results in our buffer.
-      mTextBuffer.set(tmpBuff);
-      return true;
-   }
-   else if ((event.keyCode == KEY_PAGE_UP) || (event.keyCode == KEY_PAGE_DOWN)) 
-   {
-      // See if there's some other widget that can scroll the console history.
-      if (mUseSiblingScroller) 
-      {
-         if (mSiblingScroller) 
-         {
-            return mSiblingScroller->onKeyDown(event);
-         }
-         else 
-         {
-            // Let's see if we can find it...
-            SimGroup* pGroup = getGroup();
-            if (pGroup) 
+    setUpdate();
+
+    if (event.keyCode == KEY_TAB)
+    {
+        // Get a buffer that can hold the completed text...
+        FrameTemp<UTF8> tmpBuff(GuiTextEditCtrl::MAX_STRING_LENGTH);
+        // And copy the text to be completed into it.
+        StringBuffer strBuff(mTextBuffer.c_str());
+        strBuff.getCopy8(tmpBuff, GuiTextEditCtrl::MAX_STRING_LENGTH);
+
+        // perform the completion
+        bool forward = event.modifier & SI_SHIFT;
+        //mCursorPos = Con::tabComplete(tmpBuff, mCursorPos, GuiTextEditCtrl::MAX_STRING_LENGTH, forward);
+
+        // place results in our buffer.
+        mTextBuffer.assign(tmpBuff);
+        return true;
+    }
+    else if ((event.keyCode == KEY_PAGE_UP) || (event.keyCode == KEY_PAGE_DOWN))
+    {
+        // See if there's some other widget that can scroll the console history.
+        if (mUseSiblingScroller)
+        {
+            if (mSiblingScroller)
             {
-               // Find the first scroll control in the same group as us.
-               for (SimSetIterator itr(pGroup); *itr; ++itr) 
-               {
-                  if ((mSiblingScroller = dynamic_cast<GuiScrollCtrl*>(*itr))) 
-                  {
-                     return mSiblingScroller->onKeyDown(event);
-                  }
-               }
+                return mSiblingScroller->onKeyDown(event);
             }
+            else
+            {
+                // Let's see if we can find it...
+                SimGroup* pGroup = getGroup();
+                if (pGroup)
+                {
+                    // Find the first scroll control in the same group as us.
+                    for (SimSetIterator itr(pGroup); *itr; ++itr)
+                    {
+                        if ((mSiblingScroller = dynamic_cast<GuiScrollCtrl*>(*itr)))
+                        {
+                            return mSiblingScroller->onKeyDown(event);
+                        }
+                    }
+                }
 
-            // No luck... so don't try, next time.
-            mUseSiblingScroller = false;
-         }
-      }
-   }
+                // No luck... so don't try, next time.
+                mUseSiblingScroller = false;
+            }
+        }
+    }
 
    return Parent::onKeyDown(event);
 }
 
+bool GuiConsoleEditCtrl::handleEnterKey()
+{
+    mHistory.updateHistory(mTextBuffer);
+    
+    return Parent::handleEnterKey();
+}
+
+bool GuiConsoleEditCtrl::handleArrowKey(GuiDirection direction)
+{
+    if (!mTextWrap && (direction == GuiDirection::Up || direction == GuiDirection::Down))
+    {
+        string historyText = (direction == GuiDirection::Up ? mHistory.getPrevHistory() : mHistory.getNextHistory());
+        setText(historyText);
+        mSelector.setTextLength(historyText.length());
+        mSelector.setCursorPosition(historyText.length());
+        return true;
+    }
+    else
+    {
+        return Parent::handleArrowKey(direction);
+    }
+}
+
+bool GuiConsoleEditCtrl::handleCharacterInput(const GuiEvent& event)
+{
+    string before = mTextBuffer;
+    bool result = Parent::handleCharacterInput(event);
+
+    if (before != mTextBuffer)
+    {
+        mHistory.setWorkingText(mTextBuffer);
+    }
+    return result;
+}
+
+bool GuiConsoleEditCtrl::handleBackSpace()
+{
+    string before = mTextBuffer;
+    bool result = Parent::handleBackSpace();
+
+    if (before != mTextBuffer)
+    {
+        mHistory.setWorkingText(mTextBuffer);
+    }
+    return result;
+}
+
+bool GuiConsoleEditCtrl::handleDelete()
+{
+    string before = mTextBuffer;
+    bool result = Parent::handleDelete();
+
+    if (before != mTextBuffer)
+    {
+        mHistory.setWorkingText(mTextBuffer);
+    }
+    return result;
+}
+
+

+ 23 - 0
engine/source/gui/guiConsoleEditCtrl.h

@@ -33,14 +33,37 @@
 #include "gui/containers/guiScrollCtrl.h"
 #endif
 
+class GuiConsoleEditHistory
+{
+private:
+	vector<string> historyList;
+	string workingText;
+	U32 index;
+
+public:
+	GuiConsoleEditHistory();
+	inline void clearHistory() { historyList.clear(); workingText.clear(); index = 0; }
+	inline void updateHistory(const string& text) { historyList.push_back(text); index = historyList.size(); workingText.clear(); }
+	inline void setWorkingText(const string& text) { workingText = text; index = historyList.size(); }
+	const string& getPrevHistory();
+	const string& getNextHistory();
+
+};
+
 class GuiConsoleEditCtrl : public GuiTextEditCtrl
 {
 private:
    typedef GuiTextEditCtrl Parent;
+   GuiConsoleEditHistory mHistory;
 
 protected:
    bool mUseSiblingScroller;
    GuiScrollCtrl* mSiblingScroller;
+   virtual bool handleCharacterInput(const GuiEvent& event);
+   virtual bool handleEnterKey();
+   virtual bool handleArrowKey(GuiDirection direction);
+   virtual bool handleBackSpace();
+   virtual bool handleDelete();
 
 public:
    GuiConsoleEditCtrl();

+ 140 - 107
engine/source/gui/guiControl.cc

@@ -34,6 +34,7 @@
 #include "gui/editor/guiEditCtrl.h"
 #include "string/unicode.h"
 #include "collection/vector.h"
+#include "2d/core/Utility.h"
 
 #include <sstream>
 #include <iostream>
@@ -1687,129 +1688,161 @@ void GuiControl::getScrollLineSizes(U32 *rowHeight, U32 *columnWidth)
     *rowHeight = 30;
 }
 
-void GuiControl::renderText(Point2I &offset, Point2I &extent, const char *text, GuiControlProfile *profile, TextRotationOptions rot)
+void GuiControl::renderText(const Point2I& offset, const Point2I& extent, const char* text, GuiControlProfile* profile, TextRotationOptions rot)
 {
-	RectI old = dglGetClipRect();
-	RectI clipRect = RectI(offset, extent);
-	if (clipRect.intersect(old))
-	{
-		dglSetClipRect(clipRect);
+    RectI old = dglGetClipRect();
+    RectI clipRect = RectI(offset, extent);
+    if (clipRect.intersect(old))
+    {
+        dglSetClipRect(clipRect);
 
-	   GFont *font = profile->mFont;
-	   S32 textWidth = 0;
-	   const S32 textHeight = font->getHeight();
-	   S32 totalWidth = extent.x;
-	   S32 totalHeight = extent.y;
+        const S32 textHeight = profile->mFont->getHeight();
+        S32 totalWidth = (rot == tRotateNone) ? extent.x : extent.y;
+        S32 totalHeight = (rot == tRotateNone) ? extent.y : extent.x;
 
-	   if (rot != tRotateNone)
-	   {
-		   totalWidth = extent.y;
-		   totalHeight = extent.x;
-	   }
+        S32 startOffsetY = 0;
 
-	   Point2I startOffset = Point2I(0,0);
+        vector<string> lineList = getLineList(text, profile, totalWidth);
 
-	   vector<string> lineList = vector<string>();
+        //first align vertical
+        S32 blockHeight = textHeight * lineList.size();
+        if (blockHeight < totalHeight)
+        {
+            startOffsetY = getTextVerticalOffset(blockHeight, totalHeight, profile->mVAlignment);
+        }
+        else if (!mTextWrap)
+        {
+            startOffsetY = getTextVerticalOffset(blockHeight, totalHeight, GuiControlProfile::VertAlignmentType::MiddleVAlign);
+        }
+        else
+        {
+            startOffsetY = getTextVerticalOffset(blockHeight, totalHeight, GuiControlProfile::VertAlignmentType::TopVAlign);
+        }
 
-	   if (!mTextWrap)
-	   {
-		   lineList.push_back(text);
-	   }
-	   else
-	   {
-			vector<string> paragraphList = vector<string>();
-			istringstream f(text);
-			string s;
-			while(getline(f, s)) {
-				paragraphList.push_back(s);
-			}
-
-			for (string &paragraph : paragraphList)
-			{
-				vector<string> wordList = vector<string>();
-				istringstream f2(paragraph);
-				string s2;
-				while (getline(f2, s2, ' ')) {
-					wordList.push_back(s2);
-				}
-
-				//now process the word list
-				string line;
-				line.clear();
-				for (string &word : wordList)
-				{
-					if (font->getStrWidth(word.c_str()) >= totalWidth)
-					{
-						if (line.size() > 0)
-						{
-							lineList.push_back(string(line));
-							line.clear();
-						}
-						lineList.push_back(word);
-						continue;
-					}
-
-					string prevLine = string(line);
-					line += (line.size() > 0) ? " " + word : word;
-					if (font->getStrWidth(line.c_str()) >= totalWidth)
-					{
-						lineList.push_back(prevLine);
-						line = word;
-					}
-				}
-				lineList.push_back(string(line));
-			}
-	   }
+        renderLineList(offset, extent, startOffsetY, lineList, profile, rot);
+        dglSetClipRect(old);
+    }
+}
+
+void GuiControl::renderLineList(const Point2I& offset, const Point2I& extent, const S32 startOffsetY, const vector<string> lineList, GuiControlProfile* profile, const TextRotationOptions rot)
+{
+    const S32 textHeight = profile->mFont->getHeight();
+    S32 totalWidth = (rot == tRotateNone) ? extent.x : extent.y;
 
-	   //first align vertical
-	   S32 blockHeight = textHeight * lineList.size();
-		if (blockHeight < totalHeight)
+	//Now print each line
+    U32 ibeamPos = 0;
+    U32 lineNumber = 0;
+    S32 offsetX = 0;
+    S32 offsetY = startOffsetY;
+	for(string line : lineList)
+	{
+		// align the horizontal
+        string trimmedLine = Utility::trim_copy(line);
+		U32 textWidth = profile->mFont->getStrWidth(trimmedLine.c_str());
+		if(textWidth < totalWidth)
+		{
+            offsetX = getTextHorizontalOffset(textWidth, totalWidth, profile->mAlignment);
+		}
+
+		Point2I start = Point2I(0, 0);
+		F32 rotation;
+		if (rot == tRotateNone)
+		{
+            start.x += offsetX;
+            start.y += offsetY;
+			rotation = 0.0f;
+		}
+		else if (rot == tRotateLeft)
 		{
-			startOffset.y = getTextVerticalOffset(blockHeight, totalHeight, profile->mVAlignment);
+			start.x = offsetY;
+			start.y = extent.y + offsetX;
+			rotation = 90.0f;
 		}
-		else
+		else if (rot == tRotateRight)
 		{
-			startOffset.y = getTextVerticalOffset(blockHeight, totalHeight, GuiControlProfile::VertAlignmentType::MiddleVAlign);
+			start.x = extent.x - offsetY;
+			start.y = offsetX;
+			rotation = -90.0f;
 		}
 
-	   //Now print each line
-	   for(string &line : lineList)
-	   {
-		   // align the horizontal
-		   textWidth = font->getStrWidth(line.c_str());
-		   if(textWidth < totalWidth)
-		   {
-				startOffset.x = getTextHorizontalOffset(textWidth, totalWidth, profile->mAlignment);
-		   }
-
-			Point2I start = Point2I(0, 0);
-			F32 rotation;
-			if (rot == tRotateNone)
-			{
-				start += startOffset;
-				rotation = 0.0f;
-			}
-			else if (rot == tRotateLeft)
-			{
-				start.x = startOffset.y;
-				start.y = extent.y + startOffset.x;
-				rotation = 90.0f;
-			}
-			else if (rot == tRotateRight)
-			{
-				start.x = extent.x - startOffset.y;
-				start.y = startOffset.x;
-				rotation = -90.0f;
-			}
-
-			dglDrawText( font, start + offset + profile->mTextOffset, line.c_str(), profile->mFontColors, 9, rotation );
+        renderTextLine(start + offset + profile->mTextOffset, trimmedLine, profile, rotation, ibeamPos, lineNumber);
 			
-			startOffset.y += textHeight;
-		}
-		dglSetClipRect(old);
+		offsetY += textHeight;
+        ibeamPos += line.length();
+        lineNumber++;
 	}
 }
 
+vector<string> GuiControl::getLineList(const char* text, GuiControlProfile* profile, S32 totalWidth)
+{
+    GFont* font = profile->mFont;
+    vector<string> lineList = vector<string>();
+
+    if (!mTextWrap)
+    {
+        lineList.push_back(text);
+    }
+    else
+    {
+        vector<string> paragraphList = vector<string>();
+        istringstream f(text);
+        string s;
+        while (getline(f, s)) {
+            paragraphList.push_back(s);
+        }
+
+        for (string& paragraph : paragraphList)
+        {
+            vector<string> wordList = vector<string>();
+            istringstream f2(paragraph);
+            string s2;
+            while (getline(f2, s2, ' ')) {
+                wordList.push_back(s2);
+            }
+
+            //now process the word list
+            string line;
+            bool newLine = true;
+            line.clear();
+            for (string& word : wordList)
+            {
+                if (font->getStrWidth(word.c_str()) >= totalWidth)
+                {
+                    if (line.size() > 0)
+                    {
+                        lineList.push_back(string(line + " "));
+                        line.clear();
+                    }
+                    lineList.push_back(word + " ");
+                    newLine = true;
+                    continue;
+                }
+
+                string prevLine = string(line);
+                line += (!newLine) ? " " + word : word;
+                newLine = false;
+                if (font->getStrWidth(line.c_str()) >= totalWidth && word.length() != 0)
+                {
+                    lineList.push_back(prevLine + " ");
+                    line = word;
+                }
+            }
+            if (paragraph.back() == ' ')
+            {
+                line += " ";
+            }
+            lineList.push_back(string(line));
+        }
+    }
+
+    return lineList;
+}
+
+void GuiControl::renderTextLine(const Point2I& startPoint, const string line, GuiControlProfile* profile, F32 rotationInDegrees, [[maybe_unused]] U32 ibeamPosAtLineStart, [[maybe_unused]] U32 lineNumber)
+{
+    dglDrawText(profile->mFont, startPoint, line.c_str(), profile->mFontColors, 9, rotationInDegrees);
+}
+
 S32 GuiControl::getTextHorizontalOffset(S32 textWidth, S32 totalWidth, GuiControlProfile::AlignmentType align)
 {
 	if (align == GuiControlProfile::RightAlign)

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

@@ -725,7 +725,10 @@ public:
     /// Renders justified text using the profile.
     ///
     /// @note This should move into the graphics library at some point
-    void renderText(Point2I &offset, Point2I &extent, const char *text, GuiControlProfile *profile, TextRotationOptions rot = tRotateNone);
+    void renderText(const Point2I &offset, const Point2I &extent, const char *text, GuiControlProfile *profile, TextRotationOptions rot = tRotateNone);
+    virtual void renderLineList(const Point2I& offset, const Point2I& extent, const S32 startOffsetY, const vector<string> lineList, GuiControlProfile* profile, const TextRotationOptions rot = tRotateNone);
+    virtual vector<string> getLineList(const char* text, GuiControlProfile* profile, S32 totalWidth);
+    virtual void renderTextLine(const Point2I& startPoint, const string line, GuiControlProfile* profile, F32 rotationInDegrees, U32 ibeamPosAtLineStart, U32 lineNumber);
 
 	/// Returns a new rect based on the margins.
 	RectI applyMargins(Point2I &offset, Point2I &extent, GuiControlState currentState, GuiControlProfile *profile);

File diff suppressed because it is too large
+ 569 - 308
engine/source/gui/guiTextEditCtrl.cc


+ 123 - 37
engine/source/gui/guiTextEditCtrl.h

@@ -27,17 +27,87 @@
 #include "gui/guiTypes.h"
 #endif
 
+class GuiTextEditSelection
+{
+private:
+	U32	mBlockAnchor;
+	U32 mBlockStart;
+	U32 mBlockEnd;
+	U32 mCursorPos;
+	bool mCursorAtEOL;
+	bool mIsFirstResponder;
+	RectI mGlobalUnadjustedCursorRect;
+	bool mCursorRendered;
+	U32 mTextLength;
+
+	U32      mNumFramesElapsed;
+	U32      mTimeLastCursorFlipped;
+	bool     mCursorOn;
+
+public:
+	GuiTextEditSelection();
+	GuiTextEditSelection(const GuiTextEditSelection& selector);
+	inline U32 getSelStart() const { return mBlockStart; }
+	inline U32 getSelEnd() const { return mBlockEnd; }
+	inline U32 getCursorPos() const { return mCursorPos; }
+	inline void setCursorPosition(const U32 newPos) { mBlockAnchor = mCursorPos = mClamp(newPos, 0, mTextLength); clearSelection(); }
+	inline void setTextLength(const U32 length) { mTextLength = length; if (mCursorPos > length) mCursorPos = length; }
+	inline const bool isCursorRendered() const { return mCursorRendered; }
+	inline Point2I getCursorCenter() const { return mGlobalUnadjustedCursorRect.centre(); }
+	inline RectI getCursorRect() const { return mGlobalUnadjustedCursorRect; }
+	inline void setCursorRect(RectI rect) { mGlobalUnadjustedCursorRect = rect; mCursorRendered = true; }
+	inline void setCursorAtEOL(const bool isEOL) { mCursorAtEOL = isEOL; }
+	inline void setFirstResponder(const bool isFirstResponder) { mIsFirstResponder = isFirstResponder; mCursorRendered = mCursorRendered && isFirstResponder; }
+	inline void clearSelection() { mBlockStart = mBlockEnd = 0; }
+	void selectTo(const U32 target);
+	inline bool hasSelection() { return mBlockEnd > mBlockStart; }
+	void onPreRender(const U32 time);
+	bool renderIbeam(const Point2I& startPoint, const Point2I& extent, const string line, const U32 start, const U32 end, GuiControlProfile* profile);
+	inline string getSelection(const string& fullText) { return hasSelection() ? fullText.substr(mBlockStart, mBlockEnd - mBlockStart) : string(); }
+	void eraseSelection(string& fullText);
+	void stepCursorForward();
+	void stepCursorBackward();
+	void resetCursorBlink();
+	void selectWholeWord(const string& text);
+};
+
+class GuiTextEditTextBlock
+{
+private:
+	RectI mGlobalBounds;
+	S32 mTextOffsetX;
+	S32 mTextScrollX;
+	U32 mLineStartIbeamValue;
+	string mText;
+
+public:
+	GuiTextEditTextBlock();
+	inline const U32 getStartValue() const { return mLineStartIbeamValue; }
+	inline RectI getGlobalBounds() const { return mGlobalBounds; }
+	inline Point2I getGlobalTextStart() { return Point2I(mGlobalBounds.point.x + mTextOffsetX - mTextScrollX, mGlobalBounds.point.y); }
+	void render(const RectI& bounds, string line, U32 ibeamStartValue, GuiControlProfile* profile, GuiControlState currentState, GuiTextEditSelection& selector);
+	U32 renderTextSection(const Point2I& startPoint, const U32 subStrStart, const U32 subStrLen, GuiControlProfile* profile, const GuiControlState currentState, bool isSelectedText = false);
+	void performScrollJumpX(const S32 targetX, const S32 areaStart, const S32 areaEnd);
+	U32 calculateIbeamPositionInLine(const S32 targetX, GuiControlProfile* profile);
+	inline bool calculateCursorAtEOL(const U32 cursorPos) { return cursorPos == mText.length(); }
+	inline void resetScroll() { mTextScrollX = 0; }
+	void processScrollVelocity(const S32 delta, const S32 extentX, GuiControlProfile* profile);
+	void processTextAlignment(const string line, GuiControlProfile* profile);
+};
+
 class GuiTextEditCtrl : public GuiControl
 {
 private:
    typedef GuiControl Parent;
+   typedef vector<GuiTextEditTextBlock> TextBlockList;
 
    static U32 smNumAwake;
 
 protected:
 
 	S32 mMaxStrLen; 
-   StringBuffer mTextBuffer;
+   string mTextBuffer;
+   TextBlockList mTextBlockList;
 
    StringTableEntry mEscapeCommand;
 
@@ -56,52 +126,55 @@ protected:
    InputMode mInputMode;
    bool mReturnCausesTab;
 
-   // for animating the cursor
-   S32      mNumFramesElapsed;
-   U32      mTimeLastCursorFlipped;
-   bool     mCursorOn;
-
    //Edit Cursor
    GuiCursor*  mEditCursor;
 
    bool     mInsertOn;
-   S32      mMouseDragStart;
-   Point2I  mTextOffset;
-   bool     mTextOffsetReset;
-   bool     mDragHit;
-   S32      mScrollDir;
+   bool		mMouseOver;
+
+   GuiTextEditSelection mSelector;
+
+   S32 mTextOffsetY;
+   F32 mScrollVelocity;
+   const U32 SCROLL_EDGE_SIZE = 20;
+   const F32 SCROLL_VELOCITY_PER_SEC = 200.0f;
+   U32 mTimeLastScrollProcess;
+   bool mSuspendVerticalScrollJump;
 
    //undo members
-   StringBuffer mUndoText;
-   S32      mUndoBlockStart;
-   S32      mUndoBlockEnd;
-   S32      mUndoCursorPos;
+   string mUndoText;
+   GuiTextEditSelection mUndoSelector;
    void saveUndoState();
 
-   S32      mBlockStart;
-   S32      mBlockEnd;
-   S32      mCursorPos;
-   S32      setCursorPos(const Point2I &offset);
-   
-   bool                 mHistoryDirty;
-   S32                  mHistoryLast;
-   S32                  mHistoryIndex;
-   S32                  mHistorySize;
-
    bool                 mPasswordText;
    StringTableEntry     mPasswordMask;
 
    /// If set, any non-ESC key is handled here or not at all
    bool    mSinkAllKeyEvents;   
-   UTF16   **mHistoryBuf;
-   void updateHistory(StringBuffer *txt, bool moveIndex);
+
+   const RectI getGlobalInnerRect();
+   S32 calculateIbeamPosition(const Point2I &offset);
+   S32 calculateIbeamPosition(const Point2I& globalMousePoint, const RectI& globalInnerRect);
+   S32 calculateIbeamPositionInLine(string line, const S32 startX, const S32 targetX);
+   S32 getLineAdjustedIbeamPosition(S32 heightAdjustment);
+
+   virtual bool handleKeyDownWithShift(const GuiEvent& event);
+   virtual bool handleKeyDownWithCtrl(const GuiEvent& event);
+   virtual bool handleKeyDownWithAlt(const GuiEvent& event);
+   virtual bool handleKeyDownWithNoModifier(const GuiEvent& event);
+   virtual bool handleCharacterInput(const GuiEvent& event);
+   virtual bool handleEnterKey();
+   virtual bool handleArrowKey(GuiDirection direction);
+   virtual bool handleShiftArrowKey(GuiDirection direction);
+   virtual bool handleBackSpace();
+   virtual bool handleDelete();
+   void modifySelectBlock(const U32 target);
 
    S32 textBufferWidth(StringBuffer buffer);
    StringBuffer truncate(StringBuffer buffer, StringBuffer terminationString, S32 width);
 
 public:
    GuiTextEditCtrl();
-   ~GuiTextEditCtrl();
    DECLARE_CONOBJECT(GuiTextEditCtrl);
    static void initPersistFields();
 
@@ -110,17 +183,17 @@ public:
    bool onWake();
    void onSleep();
 
-   /// Get the contents of the control.
-   ///
-   /// dest should be of size GuiTextEditCtrl::MAX_STRING_LENGTH+1.
-   virtual void getText(char *dest);
+   virtual const char* getText();
+   virtual void getCursor(GuiCursor*& cursor, bool& showCursor, const GuiEvent& lastGuiEvent);
 
    virtual void setText(const UTF8* txt);
    virtual void setText(const UTF16* txt);
+   inline virtual void setText(const string txt) { setText(txt.c_str()); }
+   void enforceMaxLength();
    virtual void setTextID(S32 id);
    virtual void setTextID(const char *id);
-   S32   getCursorPos()   { return( mCursorPos ); }
-   void  reallySetCursorPos( const S32 newPos );
+   inline U32   getIbeamPosition()   { return mSelector.getCursorPos(); }
+   inline void  setIbeamPosition(const U32 newPos) { mSelector.setCursorPosition(newPos); }
    
    void selectAllText();
    bool validate();
@@ -130,7 +203,11 @@ public:
    bool onKeyDown(const GuiEvent &event);
    void onTouchDown(const GuiEvent &event);
    void onTouchDragged(const GuiEvent &event);
-   void onTouchUp(const GuiEvent &event);
+   void onTouchUp(const GuiEvent& event);
+   void onTouchEnter(const GuiEvent& event);
+   void onTouchLeave(const GuiEvent& event);
+   bool onMouseWheelUp(const GuiEvent& event);
+   bool onMouseWheelDown(const GuiEvent& event);
    
    void onCopy(bool andCut);
    void onPaste();
@@ -146,7 +223,10 @@ public:
 
    void onPreRender();
    void onRender(Point2I offset, const RectI &updateRect);
-   virtual void drawText( const RectI &drawRect, GuiControlState currentState );
+   virtual void renderLineList(const Point2I& offset, const Point2I& extent, const S32 startOffsetY, const vector<string> lineList, GuiControlProfile* profile, const TextRotationOptions rot = tRotateNone);
+
+   GuiControlState getCurrentState();
+   const ColorI& getCurrentFontColor();
 	
 	bool inputModeValidate(const U16 key, S32 cursorPos);
 	void keyDenied();
@@ -187,12 +267,18 @@ public:
 	static InputMode getInputModeEnum(const char* label);
 	static const char* getInputModeDescription(const InputMode mode);
 
+	string applyPasswordMasking();
+	
+	void adjustScrollVelocity(const Point2I& globalMousePoint, const RectI& globalInnerRect);
+	
+	void performScrollJumpY();
+	void processScrollVelocity();
+
 	enum Constants { MAX_STRING_LENGTH = 1024 };
 
 private:
 	bool tabNext();
 	bool tabPrev();
-	void handleBackSpace();
 };
 
 #endif //_GUI_TEXTEDIT_CTRL_H

+ 2 - 17
engine/source/gui/guiTextEditCtrl_ScriptBinding.h

@@ -22,27 +22,12 @@
 
 ConsoleMethodGroupBeginWithDocs(GuiTextEditCtrl, GuiControl)
 
-
-/*! Get the contents of the textedit control.
-	@return The current text in the textedit box.
-*/
-ConsoleMethodWithDocs(GuiTextEditCtrl, getText, ConsoleString, 2, 2, "()")
-{
-	if (!object->hasText())
-		return StringTable->EmptyString;
-
-	char *retBuffer = Con::getReturnBuffer(GuiTextEditCtrl::MAX_STRING_LENGTH);
-	object->getText(retBuffer);
-
-	return retBuffer;
-}
-
 /*! Gets the current position of the text cursor in the control.
 	@return The current position of the text cursor in the control, where 0 is at the beginning of the line, 1 is after the first letter, and so on.
 */
 ConsoleMethodWithDocs(GuiTextEditCtrl, getCursorPos, ConsoleInt, 2, 2, "()")
 {
-	return(object->getCursorPos());
+	return(object->getIbeamPosition());
 }
 
 /*! Sets the current position of the text cursor in the control.
@@ -51,7 +36,7 @@ ConsoleMethodWithDocs(GuiTextEditCtrl, getCursorPos, ConsoleInt, 2, 2, "()")
 */
 ConsoleMethodWithDocs(GuiTextEditCtrl, setCursorPos, ConsoleVoid, 3, 3, "( newPos )")
 {
-	object->reallySetCursorPos(dAtoi(argv[2]));
+	object->setIbeamPosition(dAtoi(argv[2]));
 }
 
 /*! Selects all the text in the control.

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

@@ -52,11 +52,6 @@ void GuiTextEditSliderCtrl::initPersistFields()
    addField("increment", TypeF32,     Offset(mIncAmount,     GuiTextEditSliderCtrl));
 }
 
-void GuiTextEditSliderCtrl::getText(char *dest)
-{
-   Parent::getText(dest);
-}
-
 void GuiTextEditSliderCtrl::setText(const char *txt)
 {
    mValue = dAtof(txt);
@@ -86,9 +81,7 @@ void GuiTextEditSliderCtrl::setValue()
 
 void GuiTextEditSliderCtrl::onTouchDown(const GuiEvent &event)
 {
-   char txt[20];
-   Parent::getText(txt);
-   mValue = dAtof(txt);
+   mValue = dAtof(mText);
 
    mMouseDownTime = Sim::getCurrentTime();
    GuiControl *parent = getParent();
@@ -312,33 +305,4 @@ void GuiTextEditSliderCtrl::onRender(Point2I offset, const RectI &updateRect)
 #endif
 }
 
-void GuiTextEditSliderCtrl::onPreRender()
-{
-   if (isFirstResponder())
-   {
-      U32 timeElapsed = Platform::getVirtualMilliseconds() - mTimeLastCursorFlipped;
-      mNumFramesElapsed++;
-      if ((timeElapsed > 500) && (mNumFramesElapsed > 3))
-      {
-         mCursorOn = !mCursorOn;
-         mTimeLastCursorFlipped = Sim::getCurrentTime();
-         mNumFramesElapsed = 0;
-         setUpdate();
-      }
-
-      //update the cursor if the text is scrolling
-      if (mDragHit)
-      {
-         if ((mScrollDir < 0) && (mCursorPos > 0))
-         {
-            mCursorPos--;
-         }
-         else if ((mScrollDir > 0) && (mCursorPos < (S32)dStrlen(mText)))
-         {
-            mCursorPos++;
-         }
-      }
-   }
-}
-
 

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

@@ -73,8 +73,6 @@ public:
    void onTouchDragged(const GuiEvent &event);
    void onTouchUp(const GuiEvent &event);
 
-
-   void onPreRender();
    void onRender(Point2I offset, const RectI &updateRect);
 
 

+ 34 - 22
engine/source/gui/guiTypes.cc

@@ -81,7 +81,7 @@ void GuiCursor::render(const Point2I &pos)
 
    // Render the cursor centered according to dimensions of texture
    S32 texWidth = mTextureHandle.getWidth();
-   S32 texHeight = mTextureHandle.getWidth();
+   S32 texHeight = mTextureHandle.getHeight();
 
    Point2I renderPos = pos;
    renderPos.x -= (S32)( texWidth  * mRenderOffset.x );
@@ -298,6 +298,9 @@ GuiControlProfile::GuiControlProfile(void) :
    mFontColorHL(mFontColors[ColorHL]),
    mFontColorNA(mFontColors[ColorNA]),
    mFontColorSL(mFontColors[ColorSL]),
+   mFontColorLink(mFontColors[ColorLink]),
+   mFontColorLinkHL(mFontColors[ColorLinkHL]),
+   mFontColorTextSL(mFontColors[ColorTextSL]),
    mImageAssetID( StringTable->EmptyString )
 {
 	mRefCount = 0;
@@ -343,6 +346,7 @@ GuiControlProfile::GuiControlProfile(void) :
 	mFillColorHL.set(0, 0, 0, 0);
 	mFillColorSL.set(0, 0, 0, 0);
 	mFillColorNA.set(0, 0, 0, 0);
+	mFillColorTextSL.set(100, 100, 100, 255);
    mCategory = StringTable->EmptyString;
 
    GuiControlProfile *def = dynamic_cast<GuiControlProfile*>(Sim::findObject("GuiDefaultProfile"));
@@ -353,7 +357,9 @@ GuiControlProfile::GuiControlProfile(void) :
 
       mFillColor = def->mFillColor;
       mFillColorHL = def->mFillColorHL;
+	  mFillColorSL = def->mFillColorSL;
       mFillColorNA = def->mFillColorNA;
+	  mFillColorTextSL = def->mFillColorTextSL;
 
       mBorderDefault = def->mBorderDefault;
       mLeftProfileName = def->mLeftProfileName;
@@ -399,29 +405,35 @@ void GuiControlProfile::initPersistFields()
       addField("mouseOverSelected", TypeBool,   Offset(mMouseOverSelected, GuiControlProfile));
    endGroup("Behavior");
 
-   addField("fillColor",     TypeColorI,     Offset(mFillColor, GuiControlProfile));
-   addField("fillColorHL",   TypeColorI,     Offset(mFillColorHL, GuiControlProfile));
-   addField("fillColorSL",   TypeColorI,     Offset(mFillColorSL, GuiControlProfile));
-   addField("fillColorNA",   TypeColorI,     Offset(mFillColorNA, GuiControlProfile));
-
-   addField("borderDefault", TypeGuiBorderProfile, Offset(mBorderDefault, GuiControlProfile));
-   addField("borderLeft",    TypeString, Offset(mLeftProfileName, GuiControlProfile));
-   addField("borderRight",   TypeString, Offset(mRightProfileName, GuiControlProfile));
-   addField("borderTop",     TypeString, Offset(mTopProfileName, GuiControlProfile));
-   addField("borderBottom",  TypeString, Offset(mBottomProfileName, GuiControlProfile));
+   addGroup("FillColor");
+	   addField("fillColor",     TypeColorI,     Offset(mFillColor, GuiControlProfile));
+	   addField("fillColorHL",   TypeColorI,     Offset(mFillColorHL, GuiControlProfile));
+	   addField("fillColorSL",   TypeColorI,     Offset(mFillColorSL, GuiControlProfile));
+	   addField("fillColorNA",   TypeColorI,     Offset(mFillColorNA, GuiControlProfile));
+	   addField("fillColorTextSL", TypeColorI,   Offset(mFillColorTextSL, GuiControlProfile));
+   endGroup("FillColor");
+
+   addGroup("Border");
+	   addField("borderDefault", TypeGuiBorderProfile, Offset(mBorderDefault, GuiControlProfile));
+	   addField("borderLeft",    TypeString, Offset(mLeftProfileName, GuiControlProfile));
+	   addField("borderRight",   TypeString, Offset(mRightProfileName, GuiControlProfile));
+	   addField("borderTop",     TypeString, Offset(mTopProfileName, GuiControlProfile));
+	   addField("borderBottom",  TypeString, Offset(mBottomProfileName, GuiControlProfile));
+   endGroup("Border");
 
    addGroup("Font");
-   addField("fontType",      TypeString,     Offset(mFontType, GuiControlProfile));
-   addField("fontSize",      TypeS32,        Offset(mFontSize, GuiControlProfile));
-   addField("fontDirectory", TypeString,	 Offset(mFontDirectory, GuiControlProfile));
-   addField("fontCharset",   TypeEnum,       Offset(mFontCharset, GuiControlProfile), 1, &gCharsetTable);
-   addField("fontColors",    TypeColorI,     Offset(mFontColors, GuiControlProfile), 10);
-   addField("fontColor",     TypeColorI,     Offset(mFontColors[BaseColor], GuiControlProfile));
-   addField("fontColorHL",   TypeColorI,     Offset(mFontColors[ColorHL], GuiControlProfile));
-   addField("fontColorNA",   TypeColorI,     Offset(mFontColors[ColorNA], GuiControlProfile));
-   addField("fontColorSL",   TypeColorI,     Offset(mFontColors[ColorSL], GuiControlProfile));
-   addField("fontColorLink", TypeColorI,     Offset(mFontColors[ColorUser0], GuiControlProfile));
-   addField("fontColorLinkHL", TypeColorI,     Offset(mFontColors[ColorUser1], GuiControlProfile));
+	   addField("fontType",      TypeString,     Offset(mFontType, GuiControlProfile));
+	   addField("fontSize",      TypeS32,        Offset(mFontSize, GuiControlProfile));
+	   addField("fontDirectory", TypeString,	 Offset(mFontDirectory, GuiControlProfile));
+	   addField("fontCharset",   TypeEnum,       Offset(mFontCharset, GuiControlProfile), 1, &gCharsetTable);
+	   addField("fontColors",    TypeColorI,     Offset(mFontColors, GuiControlProfile), 10);
+	   addField("fontColor",     TypeColorI,     Offset(mFontColors[BaseColor], GuiControlProfile));
+	   addField("fontColorHL",   TypeColorI,     Offset(mFontColors[ColorHL], GuiControlProfile));
+	   addField("fontColorNA",   TypeColorI,     Offset(mFontColors[ColorNA], GuiControlProfile));
+	   addField("fontColorSL",   TypeColorI,     Offset(mFontColors[ColorSL], GuiControlProfile));
+	   addField("fontColorLink", TypeColorI,     Offset(mFontColors[ColorLink], GuiControlProfile));
+	   addField("fontColorLinkHL", TypeColorI, Offset(mFontColors[ColorLinkHL], GuiControlProfile));
+	   addField("fontColorTextSL", TypeColorI, Offset(mFontColors[ColorTextSL], GuiControlProfile));
    endGroup("Font");
 
    addField("align", TypeEnum, Offset(mAlignment, GuiControlProfile), 1, &gAlignTable);

+ 7 - 3
engine/source/gui/guiTypes.h

@@ -173,6 +173,7 @@ public:
    ColorI mFillColorHL; //The highlight fill color used when the cursor enters the control.
    ColorI mFillColorSL;	//Color used when the control is selected.
    ColorI mFillColorNA; //Used if the object is not active or disabled.
+   ColorI mFillColorTextSL; //Background color used when text is selected.
 
    GuiBorderProfile* mBorderDefault;					//The default border settings.
    // top profile
@@ -197,18 +198,21 @@ public:
       ColorHL,
       ColorNA,
       ColorSL,
+      ColorLink,
+      ColorLinkHL,
+      ColorTextSL,
       ColorUser0,
       ColorUser1,
       ColorUser2,
-      ColorUser3,
-      ColorUser4,
-      ColorUser5,
    };
    ColorI  mFontColors[10];                        ///< Array of font colors used for drawText with escape characters for changing color mid-string
    ColorI& mFontColor;                             ///< Main font color
    ColorI& mFontColorHL;                           ///< Highlited font color
    ColorI& mFontColorNA;                           ///< Font color when object is not active/disabled
    ColorI& mFontColorSL;                          ///< Font color when object/text is selected
+   ColorI& mFontColorLink;
+   ColorI& mFontColorLinkHL;
+   ColorI& mFontColorTextSL;
    FontCharset mFontCharset;                       ///< Font character set
 
    Resource<GFont>   mFont;                        ///< Font resource

+ 14 - 4
toybox/Sandbox/1/gui/guiProfiles.cs

@@ -114,6 +114,13 @@ new GuiCursor(MoveCursor)
    bitmapName = "./Images/move";
 };
 
+new GuiCursor(EditCursor)
+{
+   hotSpot = "0 0";
+   renderOffset = "0.5 0.5";
+   bitmapName = "./Images/ibeam";
+};
+
 if (!isObject(GuiDefaultBorderProfile)) new GuiBorderProfile (GuiDefaultBorderProfile)
 {
 	// Default margin
@@ -470,11 +477,12 @@ if (!isObject(GuiCheckBoxProfile)) new GuiControlProfile (GuiCheckBoxProfile : G
 if (!isObject(GuiTextEditProfile)) new GuiControlProfile (GuiTextEditProfile : GuiDefaultProfile)
 {
     fillColor = "232 240 248 255";
-    fillColorHL = "251 170 0 255";
+    fillColorHL = "242 250 255 255";
     fillColorNA = "127 127 127 52";
+	fillColorTextSL = "251 170 0 255";
     bitmap = "^Sandbox/gui/images/smallButtonContainer.png";
     fontColor = "27 59 95 255";
-    fontColorHL = "232 240 248 255";
+    fontColorHL = "27 59 95 255";
     fontColorNA = "0 0 0 52";
     fontColorSL = "0 0 0 255";
     textOffset = "5 2";
@@ -676,16 +684,18 @@ if (!isObject(GuiSliderNoTextProfile)) new GuiControlProfile (GuiSliderNoTextPro
 if (!isObject(GuiSpinnerProfile)) new GuiControlProfile (GuiSpinnerProfile : GuiDefaultProfile)
 {
     fillColor = $color3;
-    fillColorHL = $color5;
+    fillColorHL = $color3;
 	fillColorSL = $color3;
     fillColorNA = SetColorAlpha(%this.color3, 100);
+	fillColorTextSL = $color5;
     numbersOnly = true;
 
 	fontSize = $platformFontSize + 2;
     fontColor = $color1;
-    fontColorHL = $color4;
+    fontColorHL = $color1;
 	fontColorSL = $color1;
     fontColorNA = SetColorAlpha($color1, 100);
+	fontColorTextSL = $color4;
 
 	borderTop = "GuiDarkBorderProfile";
 	borderBottom = "GuiBrightBorderProfile";

BIN
toybox/Sandbox/1/gui/images/ibeam.png


Some files were not shown because too many files changed in this diff