📄 guimltextctrl.cc
字号:
//--------------------------------------------------------------------------
const char *GuiMLTextCtrl::getScriptValue()
{
return getTextContent();
}
#ifdef TGE_RPG
void GuiMLTextCtrl::getCursor(GuiCursor *&cursor, bool &visible, const GuiEvent &event)
{
cursor = m_arCursors[m_cursorType];
visible = true;
}
#endif
//--------------------------------------------------------------------------
void GuiMLTextCtrl::setScriptValue(const char *newText)
{
setText(newText, dStrlen(newText));
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::setText(const char* textBuffer, const U32 numChars)
{
#ifdef TGE_RPG
U32 chars;
if(numChars == -1)
chars = dStrlen(textBuffer);
else
chars = numChars;
if(chars >= mMaxBufferSize)
chars = mMaxBufferSize;
#else
U32 chars = numChars;
if(numChars >= mMaxBufferSize)
chars = mMaxBufferSize;
#endif
FrameTemp<UTF8> tmp(chars+1);
dStrncpy(tmp, textBuffer, chars);
tmp[chars] = 0;
mTextBuffer.set(tmp);
//after setting text, always set the cursor to the beginning
setCursorPosition(0);
clearSelection();
mDirty = true;
scrollToTop();
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::addText(const char* textBuffer, const U32 numChars, bool reformat)
{
#ifdef TGE_RPG
U32 charNum = numChars;
if(charNum == -1)
charNum = dStrlen(textBuffer);
U32 chars = numChars + mTextBuffer.length();
if(charNum >= mMaxBufferSize)
return;
FrameTemp<UTF8> tmp(charNum+1);
dStrncpy(tmp, textBuffer, charNum);
tmp[charNum] = 0;
#else
U32 chars = numChars + mTextBuffer.length();
if(numChars >= mMaxBufferSize)
return;
FrameTemp<UTF8> tmp(numChars+1);
dStrncpy(tmp, textBuffer, numChars);
tmp[numChars] = 0;
#endif
StringBuffer tmpBuff(tmp);
mTextBuffer.append(tmpBuff);
//after setting text, always set the cursor to the beginning
if (reformat)
{
setCursorPosition(0);
clearSelection();
mDirty = true;
#ifndef TGE_RPG
scrollToTop();
#endif
}
}
//--------------------------------------------------------------------------
bool GuiMLTextCtrl::setCursorPosition(const S32 newPosition)
{
if (newPosition < 0)
{
mCursorPosition = 0;
return true;
}
else if (newPosition >= mTextBuffer.length())
{
mCursorPosition = mTextBuffer.length();
return true;
}
else
{
mCursorPosition = newPosition;
return false;
}
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::ensureCursorOnScreen()
{
// If our parent isn't a scroll control, or we're not the only control
// in the content region, bail...
GuiControl* pParent = getParent();
GuiScrollCtrl *sc = dynamic_cast<GuiScrollCtrl*>(pParent);
if(!sc)
return;
// Ok. Now we know that our parent is a scroll control. Let's find the
// top of the cursor, and it's bottom. We can then scroll the parent control
// if appropriate...
Point2I cursorTopP, cursorBottomP;
ColorI color;
getCursorPositionAndColor(cursorTopP, cursorBottomP, color);
sc->scrollRectVisible(RectI(cursorTopP.x, cursorTopP.y, 1, cursorBottomP.y - cursorTopP.y));
}
//--------------------------------------
void GuiMLTextCtrl::getCursorPositionAndColor(Point2I &cursorTop, Point2I &cursorBottom, ColorI &color)
{
S32 x = 0;
S32 y = 0;
#ifdef TGE_RPG
S32 height = m_nLineHeightMin > 0 ? getMax(m_nLineHeightMin,(S32)mProfile->mFont->getHeight()) : mProfile->mFont->getHeight();
#else
S32 height = mProfile->mFont->getHeight();
#endif
color = mProfile->mCursorColor;
for(Line *walk = mLineList; walk; walk = walk->next)
{
if ((mCursorPosition <= walk->textStart + walk->len) || (walk->next == NULL))
{
// it's in the atoms on this line...
y = walk->y;
height = walk->height;
for(Atom *awalk = walk->atomList; awalk; awalk = awalk->next)
{
if(mCursorPosition < awalk->textStart)
{
x = awalk->xStart;
goto done;
}
if(mCursorPosition > awalk->textStart + awalk->len)
{
x = awalk->xStart + awalk->width;
continue;
}
// it's in the text block...
x = awalk->xStart;
GFont *font = awalk->style->font->fontRes;
FrameTemp<UTF8> tmp( (mCursorPosition - awalk->textStart) * 3 + 1 );
StringBuffer tmpBuff = mTextBuffer.substring(awalk->textStart, mCursorPosition - awalk->textStart);
tmpBuff.get(tmp, (mCursorPosition - awalk->textStart) * 3 + 1 );
x += font->getStrNWidth(tmp, mCursorPosition - awalk->textStart);
color = awalk->style->color;
goto done;
}
//if it's within this walk's width, but we didn't find an atom, leave the cursor at the beginning of the line...
goto done;
}
}
done:
cursorTop.set(x, y);
cursorBottom.set(x, y + height);
}
//--------------------------------------------------------------------------
// Keyboard events...
bool GuiMLTextCtrl::onKeyDown(const GuiEvent& event)
{
//only cut/copy work with this control...
if (event.modifier & SI_CTRL)
{
switch(event.keyCode)
{
//copy
case KEY_C:
{
//make sure we actually have something selected
if (mSelectionActive)
{
copyToClipboard(mSelectionStart, mSelectionEnd);
setUpdate();
}
return true;
}
}
}
// Otherwise, let the parent have the event...
return Parent::onKeyDown(event);
}
//--------------------------------------------------------------------------
// Mousing events...
#ifdef TGE_RPG
void GuiMLTextCtrl::onMouseMove(const GuiEvent& event)
{
if(!mActive)
return;
Atom *hitAtom = findHitAtom(globalToLocalCoord(event.mousePoint));
if(hitAtom && hitAtom->url)
{
m_cursorType = CT_URL;
}
else
{
m_cursorType = CT_TEXT;
}
}
#endif
void GuiMLTextCtrl::onMouseDown(const GuiEvent& event)
{
if(!mActive)
return;
Atom *hitAtom = findHitAtom(globalToLocalCoord(event.mousePoint));
if(hitAtom && !mIsEditCtrl)
{
mouseLock();
mHitURL = hitAtom->url;
if (mHitURL)
mHitURL->mouseDown = true;
}
setFirstResponder();
mouseLock();
#ifdef TGE_RPG
if (!mProfile->mCanKeyFocus)
return;
#endif
mSelectionActive = false;
mSelectionAnchor = getTextPosition(globalToLocalCoord(event.mousePoint));
mSelectionAnchorDropped = event.mousePoint;
if (mSelectionAnchor < 0)
mSelectionAnchor = 0;
else if (mSelectionAnchor >= mTextBuffer.length())
mSelectionAnchor = mTextBuffer.length();
mVertMoveAnchorValid = false;
setUpdate();
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::onMouseDragged(const GuiEvent& event)
{
if (!mActive || (Canvas->getMouseLockedControl() != this))
return;
Atom *hitAtom = findHitAtom(globalToLocalCoord(event.mousePoint));
bool down = false;
//note mHitURL can't be set unless this is (!mIsEditCtrl)
if(hitAtom && hitAtom->url == mHitURL)
down = true;
if(mHitURL && down != mHitURL->mouseDown)
mHitURL->mouseDown = down;
#ifdef TGE_RPG
if (mProfile->mCanKeyFocus && !mHitURL)
#else
if (!mHitURL)
#endif
{
S32 newSelection = 0;
newSelection = getTextPosition(globalToLocalCoord(event.mousePoint));
if (newSelection < 0)
newSelection = 0;
else if (newSelection > mTextBuffer.length())
newSelection = mTextBuffer.length();
if (newSelection == mSelectionAnchor)
{
mSelectionActive = false;
}
else if (newSelection > mSelectionAnchor)
{
mSelectionActive = true;
mSelectionStart = mSelectionAnchor;
mSelectionEnd = newSelection - 1;
}
else
{
mSelectionStart = newSelection;
mSelectionEnd = mSelectionAnchor - 1;
mSelectionActive = true;
}
setCursorPosition(newSelection);
mDirty = true;
}
setUpdate();
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::onMouseUp(const GuiEvent& event)
{
if (!mActive || (Canvas->getMouseLockedControl() != this))
return;
mouseUnlock();
//see if we've clicked on a URL
Atom *hitAtom = findHitAtom(globalToLocalCoord(event.mousePoint));
if (mHitURL && hitAtom && hitAtom->url == mHitURL && mHitURL->mouseDown)
{
mHitURL->mouseDown = false;
// Convert URL from UTF16 to UTF8.
FrameTemp<UTF8> tmp( ( mHitURL->len) * 3 + 1 );
StringBuffer tmpBuff = mTextBuffer.substring(mHitURL->textStart, mHitURL->len);
tmpBuff.get(tmp, (mHitURL->len) * 3 + 1 );
char *url = Con::getArgBuffer(mHitURL->len + 1);
dStrncpy(url, tmp, mHitURL->len);
url[mHitURL->len] = 0;
#ifdef TGE_RPG
//执行内部Cmd
if(url[0] == '@')
{
if(m_pCmdScriptFunc && m_pCmdScriptFunc[0])
Con::executef(3,m_pCmdScriptFunc, getIdString() ,url+1);
else
Con::executef(this, 2, "onCommand", url+1);
}
else
#endif
Con::executef(this, 2, "onURL", url);
mHitURL = NULL;
setUpdate();
return;
}
//else, update our selection
#ifdef TGE_RPG
else if (mProfile->mCanKeyFocus)
#else
else
#endif
{
if ((event.mousePoint - mSelectionAnchorDropped).len() < 3)
mSelectionActive = false;
setCursorPosition(getTextPosition(globalToLocalCoord(event.mousePoint)));
mVertMoveAnchorValid = false;
setUpdate();
}
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::insertChars(const char* inputChars,
const U32 numInputChars,
const U32 position)
{
AssertFatal(isSelectionActive() == false, "GuiMLTextCtrl::insertChars: don't use this function when there's a selection active!");
AssertFatal(position <= mTextBuffer.length(), "GuiMLTextCtrl::insertChars: can't insert outside of current text!");
//make sure the text will fit...
S32 numCharsToInsert = numInputChars;
if (mMaxBufferSize > 0 && mTextBuffer.length() + numInputChars + 1 > mMaxBufferSize)
numCharsToInsert = mMaxBufferSize - mTextBuffer.length() - 1;
if (numCharsToInsert <= 0)
{
// Play the "Denied" sound:
if ( numInputChars > 0 && mDeniedSound )
{
AUDIOHANDLE handle = alxCreateSource( mDeniedSound );
alxPlay( handle );
}
return;
}
FrameTemp<UTF8> inChar(numInputChars+1);
dMemcpy(inChar, inputChars, numInputChars);
inChar[numInputChars] = 0;
StringBuffer tmpInsert(inChar);
mTextBuffer.insert(position, tmpInsert);
if (mCursorPosition >= position)
{
// Cursor was at or after the inserted text, move forward...
mCursorPosition += numCharsToInsert;
}
AssertFatal(mCursorPosition <= mTextBuffer.length(), "GuiMLTextCtrl::insertChars: bad cursor position");
mDirty = true;
}
//--------------------------------------------------------------------------
void GuiMLTextCtrl::deleteChars(const U32 rangeStart,
const U32 rangeEnd)
{
AssertFatal(isSelectionActive() == false, "GuiMLTextCtrl::deleteChars: don't use this function when there's a selection active");
AssertFatal(rangeStart < mTextBuffer.length() && rangeEnd < mTextBuffer.length(),
avar("GuiMLTextCtrl::deleteChars: can't delete outside of current text (%d, %d, %d)",
rangeStart, rangeEnd, mTextBuffer.length()));
AssertFatal(rangeStart <= rangeEnd, "GuiMLTextCtrl::deleteChars: invalid delete range");
// Currently deleting text doesn't resize the text buffer, perhaps this should
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -