Blame |
Last modification |
View Log
| RSS feed
#include "TextWidget.h"
#include "Graphics.h"
#include "ScrollbarWidget.h"
#include "WidgetManager.h"
#include "Font.h"
using namespace Sexy;
TextWidget::TextWidget()
{
mFont = NULL;
mPosition = 0;
mPageSize = 0;
mStickToBottom = true;
mMaxLines = 2048;
mScrollbar = NULL;
}
SexyStringVector TextWidget::GetLines()
{
return mLogicalLines;
}
void TextWidget::SetLines(SexyStringVector theNewLines)
{
mLogicalLines = theNewLines;
}
void TextWidget::Clear()
{
mLogicalLines.clear();
mPhysicalLines.clear();
mPosition = 0.0;
mScrollbar->SetMaxValue(0.0);
MarkDirty();
}
void TextWidget::DrawColorString(Graphics* g, const SexyString& theString, int x, int y, bool useColors)
{
int aWidth = 0;
if (useColors)
g->SetColor(Color(0, 0, 0));
SexyString aCurString = _S("");
for (int i = 0; i < (int)theString.length(); i++)
{
if (theString[i] == 0x100)
{
if (aCurString.length() > 0)
g->DrawString(aCurString, x + aWidth, y);
aWidth += g->GetFont()->StringWidth(aCurString);
aCurString = _S("");
if (useColors)
g->SetColor(Color(theString[i+1], theString[i+2], theString[i+3]));
i += 3;
}
else
aCurString += theString[i];
}
if (aCurString.length() > 0)
g->DrawString(aCurString, x + aWidth, y);
}
void TextWidget::DrawColorStringHilited(Graphics* g, const SexyString& theString, int x, int y, int theStartPos, int theEndPos)
{
DrawColorString(g, theString, x, y, true);
if (theEndPos > theStartPos)
{
int aXOfs = GetColorStringWidth(theString.substr(0, theStartPos));
int aWidth = GetColorStringWidth(theString.substr(0, theEndPos)) - aXOfs;
Graphics aClipG(*g);
aClipG.ClipRect(x + aXOfs, y - g->GetFont()->GetAscent(), aWidth, g->GetFont()->GetHeight());
g->SetColor(Color(0, 0, 128));
g->FillRect(x + aXOfs, y - g->GetFont()->GetAscent(), aWidth, g->GetFont()->GetHeight());
aClipG.SetColor(Color(255, 255, 255));
DrawColorString(&aClipG, theString, x, y, false);
}
}
int TextWidget::GetStringIndex(const SexyString& theString, int thePixel)
{
int aPos = 0;
for (int i = 0; i < (int)theString.length(); i++)
{
SexyString aLoSubStr = theString.substr(0, i);
SexyString aHiSubStr = theString.substr(0, i+1);
int aLoLen = GetColorStringWidth(aLoSubStr);
int aHiLen = GetColorStringWidth(aHiSubStr);
if (thePixel >= (aLoLen+aHiLen)/2)
aPos = i+1;
}
return aPos;
}
//UNICODE
int TextWidget::GetColorStringWidth(const SexyString& theString)
{
int aWidth = 0;
SexyString aTempString;
for (int i = 0; i < (int)theString.length(); i++)
{
if (theString[i] == 0x100)
{
aWidth += mFont->StringWidth(aTempString);
aTempString = _S("");
i += 3;
}
else
aTempString += theString[i];
}
aWidth += mFont->StringWidth(aTempString);
return aWidth;
}
void TextWidget::Resize(int theX, int theY, int theWidth, int theHeight)
{
Widget::Resize(theX, theY, theWidth, theHeight);
double aPageSize = 1;
if (mHeight > mFont->GetHeight()+16)
aPageSize = (mHeight - 8.0) / mFont->GetHeight();
int aLogValue = 0;
if (mLineMap.size() > 0)
{
//IntIntMap::iterator anItr = mLineMap.find(mScrollbar->mValue);
aLogValue = mLineMap[(int) mScrollbar->mValue];
}
int aNewPhysValue = 0;
mLineMap.clear();
mPhysicalLines.clear();
for (int i = 0; i < (int)mLogicalLines.size(); i++)
{
if (i == aLogValue)
aNewPhysValue = mPhysicalLines.size();
AddToPhysicalLines(i, mLogicalLines[i]);
}
bool atBottom = mScrollbar->AtBottom();
mPageSize = aPageSize;
mScrollbar->SetMaxValue(mPhysicalLines.size());
mScrollbar->SetPageSize((int) aPageSize);
mScrollbar->SetValue(aNewPhysValue);
if ((mStickToBottom) && (atBottom))
mScrollbar->GoToBottom();
}
//UNICODE
Color TextWidget::GetLastColor(const SexyString& theString)
{
int anIdx = theString.rfind((char)0xFF);
if (anIdx < 0)
return Color(0, 0, 0);
return Color(theString[anIdx+1], theString[anIdx+2], theString[anIdx+3]);
}
//UNICODE
void TextWidget::AddToPhysicalLines(int theIdx, const SexyString& theLine)
{
SexyString aCurString = _S("");
if (GetColorStringWidth(theLine) <= mWidth - 8)
{
aCurString = theLine;
}
else
{
int aCurPos = 0;
while (aCurPos < (int)theLine.length())
{
int aNextCheckPos = aCurPos;
while ((aNextCheckPos < (int)theLine.length()) && (theLine[aNextCheckPos] == ' '))
aNextCheckPos++;
int aSpacePos = theLine.find(_S(" "), aNextCheckPos);
if (aSpacePos == -1)
aSpacePos = theLine.length();
SexyString aNewString = aCurString + theLine.substr(aCurPos, aSpacePos - aCurPos);
if (GetColorStringWidth(aNewString) > mWidth-8)
{
mPhysicalLines.push_back(aCurString);
mLineMap.push_back(theIdx);
Color aColor = GetLastColor(aCurString);
aCurString = _S(" ") + SexyChar(0xFF) + (SexyChar) aColor.mRed + (SexyChar) aColor.mGreen + (SexyChar) aColor.mBlue +
theLine.substr(aNextCheckPos, aSpacePos - aNextCheckPos);
}
else
aCurString = aNewString;
aCurPos = aSpacePos;
}
}
if ((aCurString.compare(_S("")) != 0) || (theLine.compare(_S("")) == 0))
{
mPhysicalLines.push_back(aCurString);
mLineMap.push_back(theIdx);
}
}
//UNICODE
void TextWidget::AddLine(const SexyString& theLine)
{
SexyString aLine = theLine;
if (aLine.compare(_S("")) == 0)
aLine = _S(" ");
bool atBottom = mScrollbar->AtBottom();
mLogicalLines.push_back(aLine);
if ((int)mLogicalLines.size() > mMaxLines)
{
// Remove an extra 10 lines, for safty
int aNumLinesToRemove = mLogicalLines.size() - mMaxLines + 10;
mLogicalLines.erase(mLogicalLines.begin(), mLogicalLines.begin() + aNumLinesToRemove);
int aPhysLineRemoveCount = 0;
// Remove all physical lines and linemap entries relating to deleted logical lines
while (mLineMap[aPhysLineRemoveCount] < aNumLinesToRemove)
{
aPhysLineRemoveCount++;
}
mLineMap.erase(mLineMap.begin(), mLineMap.begin() + aPhysLineRemoveCount);
mPhysicalLines.erase(mPhysicalLines.begin(), mPhysicalLines.begin() + aPhysLineRemoveCount);
// Offset the line map numbers
int i;
for (i = 0; i < (int)mLineMap.size(); i++)
{
mLineMap[i] -= aNumLinesToRemove;
}
//mLineMap.setElementAt(new Integer(((Integer) mLineMap.elementAt(i)).intValue() - aNumLinesToRemove), i);
// Move the hilited area
for (i = 0; i < 2; i++)
{
mHiliteArea[i][1] -= aNumLinesToRemove;
if (mHiliteArea[i][1] < 0)
{
mHiliteArea[i][0] = 0;
mHiliteArea[i][1] = 0;
}
}
mScrollbar->SetValue(mScrollbar->mValue - aNumLinesToRemove);
}
AddToPhysicalLines(mLogicalLines.size()-1, aLine);
mScrollbar->SetMaxValue(mPhysicalLines.size());
if (atBottom)
mScrollbar->GoToBottom();
MarkDirty();
}
bool TextWidget::SelectionReversed()
{
return ((mHiliteArea[1][1] < mHiliteArea[0][1]) ||
((mHiliteArea[1][1] == mHiliteArea[0][1]) &&
(mHiliteArea[1][0] < mHiliteArea[0][0])));
}
void TextWidget::GetSelectedIndices(int theLineIdx, int* theIndices)
{
int aXor = SelectionReversed() ? 1 : 0;
for (int aPosIdx = 0; aPosIdx < 2; aPosIdx++)
{
int aVal;
if (mHiliteArea[aPosIdx][1] < theLineIdx)
aVal = 0;
else if (mHiliteArea[aPosIdx][1] == theLineIdx)
aVal = mHiliteArea[aPosIdx][0];
else
aVal = mPhysicalLines[theLineIdx].length();
theIndices[aPosIdx ^ aXor] = aVal;
}
}
void TextWidget::Draw(Graphics* g)
{
g->SetColor(Color(255, 255, 255));
g->FillRect(0, 0, mWidth, mHeight);
Graphics aClipG(*g);
aClipG.ClipRect(4, 4, mWidth - 8, mHeight - 8);
aClipG.SetColor(Color(0, 0, 0));
aClipG.SetFont(mFont);
int aFirstLine = (int) mPosition;
int aLastLine = min((int) mPhysicalLines.size()-1, (int) mPosition + (int) mPageSize + 1);
for (int i = aFirstLine; i <= aLastLine; i++)
{
int aYPos = 4 + (int) ((i - (int) mPosition)*mFont->GetHeight()) + mFont->GetAscent();
SexyString aString = mPhysicalLines[i];
int aHilitePos[2];
GetSelectedIndices(i, aHilitePos);
DrawColorStringHilited(&aClipG, aString, 4, aYPos, aHilitePos[0], aHilitePos[1]);
}
}
void TextWidget::ScrollPosition(int theId, double thePosition)
{
mPosition = thePosition;
MarkDirty();
}
void TextWidget::GetTextIndexAt(int x, int y, int* thePosArray)
{
int aLineNum = (int) (mScrollbar->mValue + (y / (double) mFont->GetHeight()));
if (y < 0)
{
thePosArray[0] = 0;
thePosArray[1] = 0;
}
else if (aLineNum < (int)mPhysicalLines.size())
{
thePosArray[0] = GetStringIndex(mPhysicalLines[aLineNum], x);
thePosArray[1] = aLineNum;
}
else
{
if (mPhysicalLines.size() > 0)
{
thePosArray[0] = mPhysicalLines[mPhysicalLines.size()-1].length();
thePosArray[1] = mPhysicalLines.size() - 1;
}
}
}
void TextWidget::MouseDown(int x, int y, int theClickCount)
{
Widget::MouseDown(x, y, theClickCount);
GetTextIndexAt(x-4, y-4, mHiliteArea[0]);
mHiliteArea[1][0] = mHiliteArea[0][0];
mHiliteArea[1][1] = mHiliteArea[0][1];
MarkDirty();
}
void TextWidget::MouseDrag(int x, int y)
{
Widget::MouseDrag(x, y);
GetTextIndexAt(x-4, y-4, mHiliteArea[1]);
MarkDirty();
}
SexyString TextWidget::GetSelection()
{
SexyString aSelString = _S("");
int aSelIndices[2];
bool first = true;
bool reverse = SelectionReversed();
for (int aLineNum = mHiliteArea[reverse ? 1 : 0][1]; aLineNum <= mHiliteArea[reverse ? 0 : 1][1]; aLineNum++)
{
SexyString aString = mPhysicalLines[aLineNum];
GetSelectedIndices(aLineNum, aSelIndices);
if (!first)
aSelString += _S("\r\n");
for (int aStrIdx = aSelIndices[0]; aStrIdx < aSelIndices[1]; aStrIdx++)
{
SexyChar aChar = aString[aStrIdx];
if (aChar != 0x100)
aSelString += aChar;
else
aStrIdx += 3;
}
first = false;
}
return aSelString;
}
void TextWidget::KeyDown(KeyCode theKey)
{
/*if (theKey == 3)
{
// Control-C
mWidgetManager.mApplet.CopyToClipboard(GetSelection());
}
else
{
if (mEditWidget != null)
{
mWidgetManager.SetFocus(mEditWidget);
mEditWidget.KeyDown(theKey, shiftDown, controlDown);
}
}*/
}