00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "wgui_include_config.h"
00026 #include "wg_textbox.h"
00027 #include "wg_message_server.h"
00028 #include "wg_application.h"
00029 #include "wg_view.h"
00030 #include "wg_error.h"
00031 #include "wutil_debug.h"
00032 #include "std_ex.h"
00033 #include <string>
00034
00035 namespace wGui
00036 {
00037
00038 CTextBox::CTextBox(const CRect& WindowRect, CWindow* pParent, CFontEngine* pFontEngine) :
00039 CWindow(WindowRect, pParent),
00040 m_SelStart(0),
00041 m_SelLength(0),
00042 m_DragStart(0),
00043 m_bReadOnly(false),
00044 m_bMouseDown(false),
00045 m_bLastMouseMoveInside(false),
00046 m_pVerticalScrollBar(0),
00047 m_pHorizontalScrollBar(0),
00048 m_iLineCount(0),
00049 m_iRowHeight(0),
00050 m_iMaxWidth(0),
00051 m_bDrawCursor(true),
00052 m_bScrollToCursor(false)
00053 {
00054 m_BackgroundColor = COLOR_WHITE;
00055 m_ClientRect = CRect(3, 3, m_WindowRect.Width() - 17, m_WindowRect.Height() - 17);
00056 if (pFontEngine)
00057 {
00058 m_pFontEngine = pFontEngine;
00059 }
00060 else
00061 {
00062 m_pFontEngine = CApplication::Instance()->GetDefaultFontEngine();
00063 }
00064
00065 m_pDblClickTimer = new CTimer();
00066 m_pCursorTimer = new CTimer(this);
00067 m_ClientRect.Grow(-3);
00068 m_pVerticalScrollBar = new CScrollBar(
00069 CRect(m_WindowRect.Width() - 12, 1, m_WindowRect.Width(), m_WindowRect.Height() - 12) - m_ClientRect.TopLeft(), this, CScrollBar::VERTICAL);
00070 m_pHorizontalScrollBar = new CScrollBar(
00071 CRect(1, m_WindowRect.Height() - 12, m_WindowRect.Width() - 12, m_WindowRect.Height()) - m_ClientRect.TopLeft(), this, CScrollBar::HORIZONTAL);
00072 m_ScrollBarVisibilityMap[CScrollBar::VERTICAL] = SCROLLBAR_VIS_AUTO;
00073 m_ScrollBarVisibilityMap[CScrollBar::HORIZONTAL] = SCROLLBAR_VIS_AUTO;
00074 PrepareWindowText(L"");
00075
00076 CMessageServer::Instance().RegisterMessageClient(this, CMessage::KEYBOARD_KEYDOWN);
00077 CMessageServer::Instance().RegisterMessageClient(this, CMessage::MOUSE_BUTTONUP);
00078 CMessageServer::Instance().RegisterMessageClient(this, CMessage::MOUSE_MOVE);
00079 CMessageServer::Instance().RegisterMessageClient(this, CMessage::CTRL_VALUECHANGE);
00080 CMessageServer::Instance().RegisterMessageClient(this, CMessage::CTRL_VALUECHANGING);
00081 CMessageServer::Instance().RegisterMessageClient(this, CMessage::CTRL_DOUBLELCLICK);
00082 CMessageServer::Instance().RegisterMessageClient(this, CMessage::CTRL_TIMER);
00083 CMessageServer::Instance().RegisterMessageClient(this, CMessage::CTRL_GAININGKEYFOCUS);
00084 CMessageServer::Instance().RegisterMessageClient(this, CMessage::CTRL_LOSINGKEYFOCUS);
00085 Draw();
00086 }
00087
00088
00089 CTextBox::~CTextBox(void)
00090 {
00091 for(std::vector<CRenderedString*>::iterator iter = m_vpRenderedString.begin(); iter != m_vpRenderedString.end(); ++iter)
00092 delete *iter;
00093 m_vpRenderedString.clear();
00094
00095 delete m_pCursorTimer;
00096 delete m_pDblClickTimer;
00097 }
00098
00099
00100 void CTextBox::SetReadOnly(bool bReadOnly)
00101 {
00102 m_BackgroundColor = bReadOnly ? COLOR_LIGHTGRAY : COLOR_WHITE;
00103 m_bReadOnly = bReadOnly;
00104 Draw();
00105 }
00106
00107
00108 std::wstring CTextBox::GetSelText(void) const
00109 {
00110 std::wstring sSelText = L"";
00111 if (m_SelLength != 0)
00112 {
00113 std::wstring::size_type SelStartNorm = 0;
00114 std::wstring::size_type SelLenNorm = abs(m_SelLength);
00115 if (m_SelLength < 0)
00116 {
00117 SelStartNorm = m_SelStart + m_SelLength;
00118 }
00119 else
00120 {
00121 SelStartNorm = m_SelStart;
00122 }
00123 sSelText = m_sWindowText.substr(SelStartNorm, SelLenNorm);
00124 }
00125
00126 return sSelText;
00127 }
00128
00129
00130 void CTextBox::SetSelection(std::wstring::size_type iSelStart, int iSelLength)
00131 {
00132 if (iSelStart < m_sWindowText.length())
00133 {
00134 m_SelStart = iSelStart;
00135 if (iSelStart + iSelLength <= m_sWindowText.length())
00136 m_SelLength = iSelLength;
00137 else
00138 m_SelLength = stdex::safe_static_cast<int>(m_sWindowText.length() - iSelStart);
00139 }
00140 else
00141 {
00142 m_SelStart = 0;
00143 m_SelLength = 0;
00144 }
00145 }
00146
00147
00148 void CTextBox::SetScrollBarVisibility(CScrollBar::EScrollBarType ScrollBarType, EScrollBarVisibility Visibility)
00149 {
00150 m_ScrollBarVisibilityMap[ScrollBarType] = Visibility;
00151 UpdateScrollBars();
00152 }
00153
00154
00155 void CTextBox::Draw(void) const
00156 {
00157 CWindow::Draw();
00158
00159 if (m_pSDLSurface)
00160 {
00161 CPainter Painter(m_pSDLSurface, CPainter::PAINT_REPLACE);
00162 Painter.DrawRect(m_WindowRect.SizeRect(), false, COLOR_BLACK);
00163 CPoint FontCenterPoint = m_WindowRect.Center();
00164
00165 CRGBColor FontColor = m_bReadOnly ? DEFAULT_DISABLED_LINE_COLOR : DEFAULT_LINE_COLOR;
00166 if (CApplication::Instance()->GetKeyFocus() == dynamic_cast<const CWindow*>(this) && !m_bReadOnly)
00167 {
00168
00169 std::wstring::size_type SelStartNorm = 0;
00170 std::wstring::size_type SelLenNorm = abs(m_SelLength);
00171 if (m_SelLength < 0)
00172 {
00173 SelStartNorm = m_SelStart + m_SelLength;
00174 }
00175 else
00176 {
00177 SelStartNorm = m_SelStart;
00178 }
00179 CPoint SelStartPoint(RowColFromIndex(SelStartNorm));
00180 CPoint SelEndPoint(RowColFromIndex(SelStartNorm + SelLenNorm));
00181
00182
00183 std::vector<CPoint> vOffsets;
00184 std::vector<CPoint> vBoundingDimensions;
00185 std::vector<std::vector<CRect> > vCharRects;
00186 int iIndex = 0;
00187 for (std::vector<CRenderedString*>::const_iterator iter = m_vpRenderedString.begin(); iter != m_vpRenderedString.end(); ++iter, ++iIndex)
00188 {
00189 CPoint BoundingDimensions;
00190 CPoint Offset;
00191 std::vector<CRect> CharRects;
00192 (*iter)->GetMetrics(&BoundingDimensions, &Offset, &CharRects);
00193 vBoundingDimensions.push_back(BoundingDimensions);
00194 vOffsets.push_back(Offset);
00195 vCharRects.push_back(CharRects);
00196 }
00197
00198
00199 int CursorPos = vCharRects.at(SelStartPoint.YPos()).at(SelStartPoint.XPos()).Left() +
00200 vOffsets.at(SelStartPoint.YPos()).XPos() + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10;
00201 if (m_bScrollToCursor)
00202 {
00203 if (CursorPos < m_ClientRect.Left())
00204 {
00205 m_pHorizontalScrollBar->SetValue(m_pHorizontalScrollBar->GetValue() - (m_ClientRect.Left() - CursorPos) / 10 - 1);
00206 CursorPos = vCharRects.at(SelStartPoint.YPos()).at(SelStartPoint.XPos()).Left() +
00207 vOffsets.at(SelStartPoint.YPos()).XPos() + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10;
00208 }
00209 if (CursorPos > m_ClientRect.Right())
00210 {
00211 m_pHorizontalScrollBar->SetValue(m_pHorizontalScrollBar->GetValue() + (CursorPos - m_ClientRect.Right()) / 10 + 1);
00212 CursorPos = vCharRects.at(SelStartPoint.YPos()).at(SelStartPoint.XPos()).Left() +
00213 vOffsets.at(SelStartPoint.YPos()).XPos() + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10;
00214 }
00215 if (SelStartPoint.YPos() < m_pVerticalScrollBar->GetValue())
00216 {
00217 m_pVerticalScrollBar->SetValue(SelStartPoint.YPos());
00218 }
00219 if (SelStartPoint.YPos() > stdex::safe_static_cast<int>(m_pVerticalScrollBar->GetValue() + m_ClientRect.Height() / m_iRowHeight))
00220 {
00221 m_pVerticalScrollBar->SetValue(SelStartPoint.YPos() - m_ClientRect.Height() / m_iRowHeight);
00222 }
00223 m_bScrollToCursor = false;
00224 }
00225
00226
00227 if (m_SelLength != 0 && SelEndPoint.YPos() >= m_pVerticalScrollBar->GetValue())
00228 {
00229 for (int CurLine = SelStartPoint.YPos(); CurLine <= SelEndPoint.YPos(); ++CurLine)
00230 {
00231 CPoint TopLeft = m_ClientRect.TopLeft() + CPoint(0, m_iRowHeight * (CurLine - m_pVerticalScrollBar->GetValue()));
00232 CRect SelRect(TopLeft, TopLeft + CPoint(vBoundingDimensions.at(CurLine).XPos(), m_iRowHeight - 2));
00233 if (CurLine == SelStartPoint.YPos())
00234 {
00235 SelRect.SetLeft(vCharRects.at(CurLine).at(SelStartPoint.XPos()).Left() +
00236 vOffsets.at(CurLine).XPos() + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10);
00237 }
00238 if (CurLine == SelEndPoint.YPos())
00239 {
00240 SelRect.SetRight(vCharRects.at(CurLine).at(SelEndPoint.XPos()).Left() +
00241 vOffsets.at(CurLine).XPos() + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10);
00242 }
00243 SelRect.ClipTo(m_ClientRect);
00244 Painter.DrawRect(SelRect, true, CApplication::Instance()->GetDefaultSelectionColor(), CApplication::Instance()->GetDefaultSelectionColor());
00245 }
00246 }
00247
00248
00249 if (m_SelLength == 0 && SelStartPoint.YPos() >= m_pVerticalScrollBar->GetValue() && m_bDrawCursor)
00250 {
00251 if (CursorPos >= m_ClientRect.Left() && CursorPos <= m_ClientRect.Right())
00252 {
00253 Painter.DrawVLine(m_ClientRect.Top() + m_iRowHeight * (SelStartPoint.YPos() - m_pVerticalScrollBar->GetValue()) - 1,
00254 m_ClientRect.Top() + m_iRowHeight * (SelStartPoint.YPos() - m_pVerticalScrollBar->GetValue() + 1) - 1, CursorPos, COLOR_BLACK);
00255 }
00256 }
00257 }
00258
00259
00260 CPoint LineOrigin = m_ClientRect.TopLeft() - CPoint(m_pHorizontalScrollBar->GetValue() * 10, 0);
00261 for(std::vector<CRenderedString*>::const_iterator iter = m_vpRenderedString.begin() + m_pVerticalScrollBar->GetValue();
00262 iter != m_vpRenderedString.end() && LineOrigin.YPos() < m_ClientRect.Bottom(); ++iter) {
00263 (*iter)->Draw(m_pSDLSurface, m_ClientRect, LineOrigin, FontColor);
00264 LineOrigin.SetY(LineOrigin.YPos() + m_iRowHeight);
00265 }
00266 }
00267 }
00268
00269
00270 void CTextBox::SetWindowText(const std::wstring& sText)
00271 {
00272 m_SelStart = 0;
00273 m_SelLength = 0;
00274 PrepareWindowText(sText);
00275 CWindow::SetWindowText(sText);
00276 }
00277
00278
00279 void CTextBox::SetWindowRect(const CRect& WindowRect)
00280 {
00281 CWindow::SetWindowRect(WindowRect);
00282 m_ClientRect = m_WindowRect.SizeRect();
00283 m_ClientRect.Grow(-3);
00284 UpdateScrollBars();
00285 }
00286
00287
00288 bool CTextBox::OnMouseButtonDown(CPoint Point, unsigned int Button)
00289 {
00290 bool bResult = CWindow::OnMouseButtonDown(Point, Button);
00291
00292 CPoint WindowPoint(ViewToWindow(Point));
00293 if (!bResult && m_bVisible && (m_ClientRect.HitTest(WindowPoint) == CRect::RELPOS_INSIDE))
00294 {
00295 if (Button == CMouseMessage::LEFT && !m_bReadOnly)
00296 {
00297 bool fSkipCursorPositioning = false;
00298
00299 if (!m_pDblClickTimer->IsRunning())
00300 {
00301 m_pDblClickTimer->StartTimer(500, false);
00302 }
00303 else
00304 {
00305
00306 CMessageServer::Instance().QueueMessage(new TIntMessage(CMessage::CTRL_DOUBLELCLICK, this, this, 0));
00307 fSkipCursorPositioning = true;
00308 }
00309
00310 if (CApplication::Instance()->GetKeyFocus() != this)
00311 {
00312 CApplication::Instance()->SetKeyFocus(this);
00313 }
00314
00315 if (!fSkipCursorPositioning)
00316 {
00317
00318 std::vector<CPoint> vOffsets;
00319 std::vector<std::vector<CRect> > vCharRects;
00320 int iIndex = 0;
00321
00322 for (std::vector<CRenderedString*>::iterator iter = m_vpRenderedString.begin(); iter != m_vpRenderedString.end(); ++iter, ++iIndex)
00323 {
00324 CPoint Offset;
00325 std::vector<CRect> CharRects;
00326 (*iter)->GetMetrics(0, &Offset, &CharRects);
00327 vOffsets.push_back(Offset);
00328 vCharRects.push_back(CharRects);
00329 }
00330
00331
00332 unsigned int iCurLine = (WindowPoint.YPos() - m_ClientRect.Top()) / m_iRowHeight + m_pVerticalScrollBar->GetValue();
00333 if (iCurLine >= m_iLineCount)
00334 {
00335 iCurLine = m_iLineCount - 1;
00336 }
00337
00338 int xDelta = abs(WindowPoint.XPos() - (vCharRects.at(iCurLine).at(0).Left() + vOffsets.at(iCurLine).XPos() + m_ClientRect.Left()));
00339 m_SelStart = 0;
00340 for (unsigned int i = 0; i < vCharRects.at(iCurLine).size(); ++i)
00341 {
00342 if (abs(WindowPoint.XPos() - (vCharRects.at(iCurLine).at(i).Right() + vOffsets.at(iCurLine).XPos()
00343 + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10)) < xDelta)
00344 {
00345 xDelta = abs(WindowPoint.XPos() - (vCharRects.at(iCurLine).at(i).Right() + vOffsets.at(iCurLine).XPos()
00346 + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10));
00347 m_SelStart = i + 1;
00348 }
00349 }
00350 for (unsigned int iChar = 0; iChar < iCurLine; ++iChar)
00351 {
00352 m_SelStart += vCharRects.at(iChar).size();
00353 }
00354 }
00355
00356 m_DragStart = m_SelStart;
00357 m_SelLength = 0;
00358 m_bMouseDown = true;
00359 Draw();
00360 bResult = true;
00361 }
00362 if (Button == CMouseMessage::WHEELUP)
00363 {
00364 m_pVerticalScrollBar->SetValue(m_pVerticalScrollBar->GetValue() - 1);
00365 bResult = true;
00366 }
00367 else if (Button == CMouseMessage::WHEELDOWN)
00368 {
00369 m_pVerticalScrollBar->SetValue(m_pVerticalScrollBar->GetValue() + 1);
00370 bResult = true;
00371 }
00372 }
00373
00374 return bResult;
00375 }
00376
00377
00378 bool CTextBox::HandleMessage(CMessage* pMessage)
00379 {
00380 bool bHandled = false;
00381
00382 if (pMessage)
00383 {
00384 switch(pMessage->MessageType())
00385 {
00386 case CMessage::CTRL_DOUBLELCLICK:
00387 if (pMessage->Destination() == this)
00388 {
00389
00390 m_SelStart = 0;
00391 m_SelLength = stdex::safe_static_cast<int>(m_sWindowText.length());
00392 Draw();
00393 bHandled = true;
00394 }
00395 break;
00396 case CMessage::MOUSE_BUTTONUP:
00397 m_bMouseDown = false;
00398 break;
00399 case CMessage::MOUSE_MOVE:
00400 {
00401 CMouseMessage* pMouseMessage = dynamic_cast<CMouseMessage*>(pMessage);
00402 if (pMouseMessage && m_bVisible && !m_bReadOnly)
00403 {
00404 CPoint WindowPoint(ViewToWindow(pMouseMessage->Point));
00405
00406
00407
00408
00409
00410 CView* pView = GetView();
00411 bool bHitFloating = pView && pView->GetFloatingWindow() && pView->GetFloatingWindow()->HitTest(pMouseMessage->Point);
00412 if (m_ClientRect.HitTest(WindowPoint) == CRect::RELPOS_INSIDE && !bHitFloating && !m_bLastMouseMoveInside)
00413 {
00414 m_bLastMouseMoveInside = true;
00415 CwgCursorResourceHandle IBeamHandle(WGRES_IBEAM_CURSOR);
00416 CApplication::Instance()->SetMouseCursor(&IBeamHandle);
00417 }
00418 else if ((m_ClientRect.HitTest(WindowPoint) != CRect::RELPOS_INSIDE || bHitFloating) && m_bLastMouseMoveInside)
00419 {
00420 m_bLastMouseMoveInside= false;
00421 CApplication::Instance()->SetMouseCursor();
00422 }
00423
00424 if (m_bMouseDown)
00425 {
00426
00427 std::vector<CPoint> vOffsets;
00428 std::vector<std::vector<CRect> > vCharRects;
00429 int iIndex = 0;
00430 for (std::vector<CRenderedString*>::iterator iter = m_vpRenderedString.begin(); iter != m_vpRenderedString.end(); ++iter, ++iIndex)
00431 {
00432 CPoint Offset;
00433 std::vector<CRect> CharRects;
00434 (*iter)->GetMetrics(0, &Offset, &CharRects);
00435 vOffsets.push_back(Offset);
00436 vCharRects.push_back(CharRects);
00437 }
00438
00439
00440 unsigned int iCurLine = 0;
00441 if (m_ClientRect.HitTest(WindowPoint) == CRect::RELPOS_INSIDE)
00442 {
00443 iCurLine = (WindowPoint.YPos() - m_ClientRect.Top()) / m_iRowHeight + m_pVerticalScrollBar->GetValue();
00444 if (iCurLine >= m_iLineCount)
00445 {
00446 iCurLine = m_iLineCount - 1;
00447 }
00448 }
00449 else if (m_ClientRect.HitTest(WindowPoint) == CRect::RELPOS_BELOW)
00450 {
00451 iCurLine = m_iLineCount - 1;
00452 }
00453
00454
00455 int xDelta = abs(WindowPoint.XPos() - (vCharRects.at(iCurLine).at(0).Left() + vOffsets.at(iCurLine).XPos() + m_ClientRect.Left()));
00456 std::wstring::size_type CursorPos = 0;
00457 for (unsigned int i = 0; i < vCharRects.at(iCurLine).size(); ++i)
00458 {
00459 if (abs(WindowPoint.XPos() - (vCharRects.at(iCurLine).at(i).Right() + vOffsets.at(iCurLine).XPos()
00460 + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10)) < xDelta)
00461 {
00462 xDelta = abs(WindowPoint.XPos() - (vCharRects.at(iCurLine).at(i).Right() + vOffsets.at(iCurLine).XPos()
00463 + m_ClientRect.Left() - m_pHorizontalScrollBar->GetValue() * 10));
00464 CursorPos = i + 1;
00465 }
00466 }
00467 for (unsigned int iChar = 0; iChar < iCurLine; ++iChar)
00468 {
00469 CursorPos += vCharRects.at(iChar).size();
00470 }
00471
00472
00473 if (CursorPos < m_DragStart)
00474 {
00475 m_SelLength = stdex::safe_static_cast<int>(m_DragStart) - stdex::safe_static_cast<int>(CursorPos);
00476 m_SelStart = CursorPos;
00477 }
00478 else
00479 {
00480 m_SelStart = m_DragStart;
00481 m_SelLength = stdex::safe_static_cast<int>(CursorPos) - stdex::safe_static_cast<int>(m_SelStart);
00482 }
00483 bHandled = true;
00484 Draw();
00485 }
00486 }
00487 break;
00488 }
00489 case CMessage::CTRL_TIMER:
00490 if (pMessage->Destination() == this && pMessage->Source() == m_pCursorTimer)
00491 {
00492
00493 m_bDrawCursor = !m_bDrawCursor;
00494 Draw();
00495 bHandled = true;
00496 }
00497 break;
00498 case CMessage::CTRL_GAININGKEYFOCUS:
00499 if (pMessage->Destination() == this)
00500 {
00501 m_pCursorTimer->StartTimer(750, true);
00502 m_bDrawCursor = true;
00503 Draw();
00504 bHandled = true;
00505 }
00506 break;
00507 case CMessage::CTRL_LOSINGKEYFOCUS:
00508 if (pMessage->Destination() == this)
00509 {
00510 m_pCursorTimer->StopTimer();
00511 Draw();
00512 bHandled = true;
00513 }
00514 break;
00515 case CMessage::KEYBOARD_KEYDOWN:
00516 if (m_bVisible)
00517 {
00518 CKeyboardMessage* pKeyboardMessage = dynamic_cast<CKeyboardMessage*>(pMessage);
00519 if (pKeyboardMessage && pMessage->Destination() == this && !m_bReadOnly)
00520 {
00521 std::wstring sBuffer = m_sWindowText;
00522
00523 switch(pKeyboardMessage->Key)
00524 {
00525 case SDLK_BACKSPACE:
00526 if (m_SelLength > 0)
00527 {
00528 SelDelete(&sBuffer);
00529 }
00530 else
00531 {
00532 if (m_SelStart > 0)
00533 {
00534 sBuffer.erase(--m_SelStart, 1);
00535 }
00536 }
00537 break;
00538
00539 case SDLK_DELETE:
00540 if (m_SelStart < sBuffer.length())
00541 {
00542 if (m_SelLength > 0)
00543 {
00544 SelDelete(&sBuffer);
00545 }
00546 else
00547 {
00548 sBuffer.erase(m_SelStart, 1);
00549 }
00550 }
00551 break;
00552
00553 case SDLK_LEFT:
00554 if (pKeyboardMessage->Modifiers & KMOD_SHIFT)
00555 {
00556 if (m_SelStart > 0)
00557 {
00558 if ((m_SelLength > 0) || ((m_SelStart - abs(m_SelLength)) > 0))
00559 {
00560 if (pKeyboardMessage->Modifiers & KMOD_CTRL)
00561 {
00562 std::wstring::size_type pos = sBuffer.rfind(L" ", (m_SelStart + m_SelLength) - 1);
00563 if (pos != std::wstring::npos)
00564 {
00565 m_SelLength = stdex::safe_static_cast<int>(pos) - stdex::safe_static_cast<int>(m_SelStart);
00566 }
00567 else
00568 {
00569 m_SelLength = stdex::safe_static_cast<int>(m_SelStart) * -1;
00570 }
00571 }
00572 else
00573 {
00574 m_SelLength--;
00575 }
00576 }
00577 }
00578 }
00579 else if (m_SelLength != 0)
00580 {
00581 if (m_SelLength < 0)
00582 {
00583 m_SelStart = m_SelStart + m_SelLength;
00584 }
00585 m_SelLength = 0;
00586 }
00587 else if (m_SelStart > 0)
00588 {
00589 if (pKeyboardMessage->Modifiers & KMOD_CTRL)
00590 {
00591 std::wstring::size_type pos = sBuffer.rfind(L" ", m_SelStart - 1);
00592 if (pos != std::wstring::npos)
00593 {
00594 m_SelStart = pos;
00595 }
00596 else
00597 {
00598 m_SelStart = 0;
00599 }
00600 }
00601 else
00602 {
00603 --m_SelStart;
00604 }
00605 m_SelLength = 0;
00606 }
00607 break;
00608 case SDLK_RIGHT:
00609 if (m_SelStart <= sBuffer.length())
00610 {
00611 if (pKeyboardMessage->Modifiers & KMOD_SHIFT)
00612 {
00613 if (pKeyboardMessage->Modifiers & KMOD_CTRL)
00614 {
00615 std::wstring::size_type pos = sBuffer.find(L" ", m_SelStart + m_SelLength);
00616 if (pos != std::wstring::npos)
00617 {
00618 m_SelLength = stdex::safe_static_cast<int>(pos) - stdex::safe_static_cast<int>(m_SelStart) + 1;
00619 }
00620 else
00621 {
00622 m_SelLength = stdex::safe_static_cast<int>(sBuffer.length()) - stdex::safe_static_cast<int>(m_SelStart);
00623 }
00624 }
00625 else if (m_SelStart + m_SelLength < sBuffer.length())
00626 {
00627 m_SelLength++;
00628 }
00629 }
00630 else if(m_SelLength == 0 && m_SelStart < sBuffer.length())
00631 {
00632
00633
00634
00635
00636 if (pKeyboardMessage->Modifiers & KMOD_CTRL)
00637 {
00638 std::wstring::size_type pos = sBuffer.find(L" ", m_SelStart + 1);
00639 if (pos != std::wstring::npos)
00640 {
00641 m_SelStart = pos + 1;
00642 }
00643 else
00644 {
00645 m_SelStart = sBuffer.length();
00646 }
00647 }
00648 else
00649 {
00650 ++m_SelStart;
00651 }
00652 }
00653 else
00654 {
00655 if (m_SelLength > 0)
00656 {
00657 m_SelStart = m_SelStart + m_SelLength;
00658 }
00659 m_SelLength = 0;
00660 }
00661 }
00662 break;
00663 case SDLK_DOWN:
00664 if (m_SelStart <= sBuffer.length())
00665 {
00666 if (pKeyboardMessage->Modifiers & KMOD_SHIFT)
00667 {
00668 CPoint CursorPoint(RowColFromIndex(m_SelStart + m_SelLength));
00669 if (CursorPoint.YPos() == stdex::safe_static_cast<int>(m_iLineCount - 1))
00670 {
00671 m_SelLength = stdex::safe_static_cast<int>(m_sWindowText.size() - m_SelStart);
00672 }
00673 else
00674 {
00675 m_SelLength = stdex::safe_static_cast<int>(IndexFromRowCol(CursorPoint.YPos() + 1, CursorPoint.XPos()))
00676 - stdex::safe_static_cast<int>(m_SelStart);
00677 }
00678 }
00679 else if(m_SelLength == 0)
00680 {
00681 CPoint CursorPoint(RowColFromIndex(m_SelStart));
00682 if (CursorPoint.YPos() == stdex::safe_static_cast<int>(m_iLineCount - 1))
00683 {
00684 m_SelStart = m_sWindowText.size();
00685 }
00686 else
00687 {
00688 m_SelStart = IndexFromRowCol(CursorPoint.YPos() + 1, CursorPoint.XPos());
00689 }
00690 }
00691 else
00692 {
00693 if (m_SelLength > 0)
00694 {
00695 m_SelStart = m_SelStart + m_SelLength;
00696 }
00697 m_SelLength = 0;
00698 }
00699 }
00700 break;
00701 case SDLK_UP:
00702 if (m_SelStart <= sBuffer.length())
00703 {
00704 if (pKeyboardMessage->Modifiers & KMOD_SHIFT)
00705 {
00706 CPoint CursorPoint(RowColFromIndex(m_SelStart + m_SelLength));
00707 if (CursorPoint.YPos() == 0)
00708 {
00709 m_SelLength = -stdex::safe_static_cast<int>(m_SelStart);
00710 }
00711 else
00712 {
00713 m_SelLength = stdex::safe_static_cast<int>(IndexFromRowCol(CursorPoint.YPos() - 1, CursorPoint.XPos()))
00714 - stdex::safe_static_cast<int>(m_SelStart);
00715 }
00716 }
00717 else if(m_SelLength == 0 )
00718 {
00719 CPoint CursorPoint(RowColFromIndex(m_SelStart));
00720 if (CursorPoint.YPos() == 0)
00721 {
00722 m_SelStart = 0;
00723 }
00724 else
00725 {
00726 m_SelStart = IndexFromRowCol(CursorPoint.YPos() - 1, CursorPoint.XPos());
00727 }
00728 }
00729 else
00730 {
00731 if (m_SelLength < 0)
00732 {
00733 m_SelStart = m_SelStart + m_SelLength;
00734 }
00735 m_SelLength = 0;
00736 }
00737 }
00738 break;
00739 case SDLK_END:
00740 {
00741 std::wstring::size_type endPos = sBuffer.length();
00742
00743
00744
00745 if ((pKeyboardMessage->Modifiers & KMOD_CTRL) == 0)
00746 {
00747 std::wstring::size_type lineEndPos = sBuffer.find(L"\n", m_SelStart + m_SelLength + 1);
00748 if (lineEndPos != std::wstring::npos)
00749 {
00750 endPos = lineEndPos;
00751 }
00752 }
00753
00754 if (pKeyboardMessage->Modifiers & KMOD_SHIFT)
00755 {
00756 m_SelLength = stdex::safe_static_cast<int>(endPos) - stdex::safe_static_cast<int>(m_SelStart);
00757 }
00758 else
00759 {
00760 m_SelStart = endPos;
00761 }
00762 }
00763 break;
00764 case SDLK_HOME:
00765 {
00766
00767
00768 std::wstring::size_type endPos = 0;
00769 if ((pKeyboardMessage->Modifiers & KMOD_CTRL) == 0)
00770 {
00771 std::wstring::size_type lineEndPos = sBuffer.rfind(L"\n", m_SelStart + m_SelLength - 1);
00772 if (lineEndPos != std::wstring::npos)
00773 {
00774 endPos = lineEndPos + 1;
00775 }
00776 }
00777 if (pKeyboardMessage->Modifiers & KMOD_SHIFT)
00778 {
00779 m_SelLength = stdex::safe_static_cast<long int>(endPos);
00780 }
00781 else
00782 {
00783 m_SelLength = 0;
00784 m_SelStart = endPos;
00785 }
00786 }
00787 break;
00788 case SDLK_RETURN:
00789 SelDelete(&sBuffer);
00790 sBuffer.insert(m_SelStart++, 1, L'\n');
00791 break;
00792 case SDLK_ESCAPE:
00793
00794 break;
00795 default:
00796 if (pKeyboardMessage->Unicode)
00797 {
00798 SelDelete(&sBuffer);
00799 sBuffer.insert(m_SelStart++, 1, stdex::safe_static_cast<wchar_t>(pKeyboardMessage->Unicode));
00800 }
00801 break;
00802 }
00803
00804 if (m_sWindowText != sBuffer)
00805 {
00806 CMessageServer::Instance().QueueMessage(new TStringMessage(CMessage::CTRL_VALUECHANGE, m_pParentWindow, this, sBuffer));
00807 m_sWindowText = sBuffer;
00808 PrepareWindowText(sBuffer);
00809 }
00810 m_bDrawCursor = true;
00811 m_bScrollToCursor = true;
00812 Draw();
00813 }
00814 break;
00815 }
00816 case CMessage::CTRL_VALUECHANGE:
00817 case CMessage::CTRL_VALUECHANGING:
00818 {
00819 if (pMessage->Source() == m_pVerticalScrollBar || pMessage->Source() == m_pHorizontalScrollBar)
00820 {
00821 Draw();
00822 bHandled = true;
00823 }
00824 break;
00825 }
00826 default :
00827 bHandled = CWindow::HandleMessage(pMessage);
00828 break;
00829 }
00830 }
00831
00832 return bHandled;
00833 }
00834
00835
00836 void CTextBox::SelDelete(std::wstring* psString)
00837 {
00838
00839 if (m_SelLength != 0)
00840 {
00841 std::wstring::size_type SelStartNorm = 0;
00842 std::wstring::size_type SelLenNorm = abs(m_SelLength);
00843 if (m_SelLength < 0)
00844 {
00845 SelStartNorm = m_SelStart + m_SelLength;
00846 }
00847 else
00848 {
00849 SelStartNorm = m_SelStart;
00850 }
00851 psString->erase(SelStartNorm, SelLenNorm);
00852
00853 m_SelStart = SelStartNorm;
00854 m_SelLength = 0;
00855 }
00856 }
00857
00858
00859 void CTextBox::PrepareWindowText(const std::wstring& sText)
00860 {
00861 for(std::vector<CRenderedString*>::iterator iter = m_vpRenderedString.begin(); iter != m_vpRenderedString.end(); ++iter)
00862 delete *iter;
00863 m_vpRenderedString.clear();
00864
00865 m_iLineCount = 0;
00866 std::wstring::size_type start = 0;
00867 std::wstring::size_type loc = 0;
00868 m_iMaxWidth = 0;
00869 while (loc != std::wstring::npos)
00870 {
00871 loc = sText.find(L"\n", start);
00872 m_vpRenderedString.push_back(new CRenderedString(
00873 m_pFontEngine, sText.substr(start, loc - start), CRenderedString::VALIGN_TOP, CRenderedString::HALIGN_LEFT));
00874 CPoint BoundingDimensions;
00875 m_vpRenderedString.back()->GetMetrics(&BoundingDimensions, 0, 0);
00876 if (BoundingDimensions.XPos() > stdex::safe_static_cast<int>(m_iMaxWidth))
00877 {
00878 m_iMaxWidth = BoundingDimensions.XPos();
00879 }
00880 start = loc + 1;
00881 ++m_iLineCount;
00882 }
00883 m_iRowHeight = m_vpRenderedString.at(0)->GetMaxFontHeight() + 2;
00884
00885 UpdateScrollBars();
00886 }
00887
00888
00889 void CTextBox::UpdateScrollBars(void)
00890 {
00891 m_ClientRect = CRect(3, 3, m_WindowRect.Width() - 5, m_WindowRect.Height() - 5);
00892 bool bVertVisible = m_ScrollBarVisibilityMap[CScrollBar::VERTICAL] == SCROLLBAR_VIS_ALWAYS ||
00893 (m_ScrollBarVisibilityMap[CScrollBar::VERTICAL] == SCROLLBAR_VIS_AUTO && m_iLineCount > (m_ClientRect.Height() - 12) / m_iRowHeight);
00894 bool bHorzVisible = m_ScrollBarVisibilityMap[CScrollBar::HORIZONTAL] == SCROLLBAR_VIS_ALWAYS ||
00895 (m_ScrollBarVisibilityMap[CScrollBar::HORIZONTAL] == SCROLLBAR_VIS_AUTO && stdex::safe_static_cast<int>(m_iMaxWidth) > (m_ClientRect.Width() - 12));
00896 int iMaxHorzLimit = (stdex::safe_static_cast<int>(m_iMaxWidth) - (m_ClientRect.Width() - 12)) / 10;
00897 if (iMaxHorzLimit < 0)
00898 {
00899 iMaxHorzLimit = 0;
00900 }
00901
00902 m_pVerticalScrollBar->SetVisible(bVertVisible);
00903 m_pHorizontalScrollBar->SetVisible(bHorzVisible);
00904 int iLastLine = m_iLineCount - 1;
00905 if (iLastLine < 0)
00906 {
00907 iLastLine = 0;
00908 }
00909 if (bVertVisible)
00910 {
00911 m_ClientRect.SetRight(m_WindowRect.Width() - 17);
00912 }
00913 if (bHorzVisible)
00914 {
00915 m_ClientRect.SetBottom(m_WindowRect.Height() - 17);
00916 }
00917
00918 m_pVerticalScrollBar->SetMaxLimit(iLastLine);
00919 if (m_pVerticalScrollBar->GetValue() > iLastLine)
00920 {
00921 m_pVerticalScrollBar->SetValue(iLastLine);
00922 }
00923 m_pVerticalScrollBar->SetWindowRect(CRect(m_ClientRect.Width() + 2, 1 - m_ClientRect.Top(), m_ClientRect.Width() + 14, m_ClientRect.Height()));
00924 m_pHorizontalScrollBar->SetMaxLimit(iMaxHorzLimit);
00925 if (m_pHorizontalScrollBar->GetValue() > iMaxHorzLimit)
00926 {
00927 m_pHorizontalScrollBar->SetValue(iMaxHorzLimit);
00928 }
00929 m_pHorizontalScrollBar->SetWindowRect(CRect(1 - m_ClientRect.Left(), m_ClientRect.Height() + 2, m_ClientRect.Width(), m_ClientRect.Height() + 14));
00930 }
00931
00932
00933 CPoint CTextBox::RowColFromIndex(std::wstring::size_type Index) const
00934 {
00935 int iRow = 0;
00936 int iCol = stdex::safe_static_cast<int>(Index);
00937 std::wstring::size_type loc = m_sWindowText.find(L"\n");
00938 std::wstring::size_type start = 0;
00939 while (loc != std::wstring::npos && loc < Index)
00940 {
00941 ++iRow;
00942 iCol -= (stdex::safe_static_cast<int>(loc - start) + 1);
00943 start = loc + 1;
00944 loc = m_sWindowText.find(L"\n", start);
00945 }
00946 return CPoint(iCol, iRow);
00947 }
00948
00949
00950 std::wstring::size_type CTextBox::IndexFromRowCol(std::wstring::size_type Row, std::wstring::size_type Col) const
00951 {
00952 std::wstring::size_type Index = 0;
00953 for (std::wstring::size_type iRow = 0; iRow < Row && iRow < m_vpRenderedString.size(); ++iRow)
00954 Index += m_vpRenderedString.at(iRow)->GetLength() + 1;
00955 if (Col > m_vpRenderedString.at(Row)->GetLength())
00956 Col = m_vpRenderedString.at(Row)->GetLength();
00957 return Index + Col;
00958 }
00959
00960 }