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
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #include <typeinfo>
00060
00061 #include "guichan/basiccontainer.h"
00062 #include "guichan/keyinput.h"
00063 #include "guichan/mouseinput.h"
00064 #include "guichan/widgets/scrollarea.h"
00065 #include "guichan/widgets/textbox.h"
00066 #include "guichan/exception.h"
00067 #include "util.h"
00068
00069 namespace gcn
00070 {
00071 TextBox::TextBox()
00072 {
00073 mCaretColumn = 0;
00074 mCaretRow = 0;
00075 mEditable = true;
00076 mOpaque = true;
00077
00078 setFocusable(true);
00079
00080 addMouseListener(this);
00081 addKeyListener(this);
00082 adjustSize();
00083 setBorderSize(1);
00084 }
00085
00086 TextBox::TextBox(const std::string& text)
00087 {
00088 mCaretColumn = 0;
00089 mCaretRow = 0;
00090 mEditable = true;
00091 mOpaque = true;
00092
00093 setText(text);
00094
00095 setFocusable(true);
00096
00097 addMouseListener(this);
00098 addKeyListener(this);
00099 adjustSize();
00100 setBorderSize(1);
00101 }
00102
00103 void TextBox::setText(const std::string& text)
00104 {
00105 mCaretColumn = 0;
00106 mCaretRow = 0;
00107
00108 mTextRows.clear();
00109
00110 std::string::size_type pos, lastPos = 0;
00111 int length;
00112 do
00113 {
00114 pos = text.find("\n", lastPos);
00115
00116 if (pos != std::string::npos)
00117 {
00118 length = pos - lastPos;
00119 }
00120 else
00121 {
00122 length = text.size() - lastPos;
00123 }
00124 std::string sub = text.substr(lastPos, length);
00125 mTextRows.push_back(sub);
00126 lastPos = pos + 1;
00127
00128 } while (pos != std::string::npos);
00129
00130 adjustSize();
00131 }
00132
00133 void TextBox::draw(Graphics* graphics)
00134 {
00135 unsigned int i;
00136
00137 if (mOpaque)
00138 {
00139 graphics->setColor(getBackgroundColor());
00140 graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight()));
00141 }
00142
00143 if (hasFocus() && isEditable())
00144 {
00145 drawCaret(graphics, getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn)), mCaretRow * getFont()->getHeight());
00146 }
00147
00148 graphics->setColor(getForegroundColor());
00149 graphics->setFont(getFont());
00150
00151 for (i = 0; i < mTextRows.size(); i++)
00152 {
00153
00154 graphics->drawText(mTextRows[i], 1, i * getFont()->getHeight());
00155 }
00156 }
00157
00158 void TextBox::drawBorder(Graphics* graphics)
00159 {
00160 int width = getWidth() + getBorderSize() * 2 - 1;
00161 int height = getHeight() + getBorderSize() * 2 - 1;
00162
00163 graphics->setColor(getBackgroundColor());
00164
00165 unsigned int i;
00166 for (i = 0; i < getBorderSize(); ++i)
00167 {
00168 graphics->drawLine(i,i, width - i, i);
00169 graphics->drawLine(i,i + 1, i, height - i - 1);
00170 graphics->drawLine(width - i,i + 1, width - i, height - i);
00171 graphics->drawLine(i,height - i, width - i - 1, height - i);
00172 }
00173 }
00174
00175 void TextBox::drawCaret(Graphics* graphics, int x, int y)
00176 {
00177 graphics->setColor(getForegroundColor());
00178 graphics->drawLine(x, getFont()->getHeight() + y, x, y);
00179 }
00180
00181 void TextBox::mousePress(int x, int y, int button)
00182 {
00183 if (hasMouse() && button == MouseInput::LEFT)
00184 {
00185 mCaretRow = y / getFont()->getHeight();
00186
00187 if (mCaretRow >= (int)mTextRows.size())
00188 {
00189 mCaretRow = mTextRows.size() - 1;
00190 }
00191
00192 mCaretColumn = getFont()->getStringIndexAt(mTextRows[mCaretRow], x);
00193 }
00194 else if (hasMouse() && button == MouseInput::MIDDLE)
00195 {
00196 std::string str;
00197 if (GetClipboard(str) >= 0) {
00198 for (size_t i = 0; i < str.size(); ++i) {
00199 keyPress(Key(str[i]));
00200 }
00201 }
00202 }
00203 }
00204
00205 static int FindNext(const std::string &text, int curpos)
00206 {
00207 if (curpos < 0) return 0;
00208 while (curpos < (int)text.size()) {
00209 if ((text[curpos] & 0xC0) != 0x80) {
00210 return curpos;
00211 }
00212 ++curpos;
00213 }
00214 return text.size();
00215 }
00216
00217 bool TextBox::keyPress(const Key& key)
00218 {
00219 bool ret = false;
00220
00221 if (key.getValue() == Key::LEFT)
00222 {
00223 mCaretColumn = UTF8GetPrev(mTextRows[mCaretRow], mCaretColumn);
00224 if (mCaretColumn < 0)
00225 {
00226 --mCaretRow;
00227
00228 if (mCaretRow < 0)
00229 {
00230 mCaretRow = 0;
00231 mCaretColumn = 0;
00232 }
00233 else
00234 {
00235 mCaretColumn = mTextRows[mCaretRow].size();
00236 }
00237 }
00238 ret = true;
00239 }
00240
00241 else if (key.getValue() == Key::RIGHT)
00242 {
00243 mCaretColumn = UTF8GetNext(mTextRows[mCaretRow], mCaretColumn);
00244 if (mCaretColumn > (int)mTextRows[mCaretRow].size())
00245 {
00246 ++mCaretRow;
00247
00248 if (mCaretRow >= (int)mTextRows.size())
00249 {
00250 mCaretRow = mTextRows.size() - 1;
00251 if (mCaretRow < 0)
00252 {
00253 mCaretRow = 0;
00254 }
00255
00256 mCaretColumn = mTextRows[mCaretRow].size();
00257 }
00258 else
00259 {
00260 mCaretColumn = 0;
00261 }
00262 }
00263 ret = true;
00264 }
00265
00266 else if (key.getValue() == Key::DOWN)
00267 {
00268 setCaretRow(mCaretRow + 1);
00269 ret = true;
00270 }
00271
00272 else if (key.getValue() == Key::UP)
00273 {
00274 setCaretRow(mCaretRow - 1);
00275 ret = true;
00276 }
00277
00278 else if (key.getValue() == Key::HOME)
00279 {
00280 mCaretColumn = 0;
00281 ret = true;
00282 }
00283
00284 else if (key.getValue() == Key::END)
00285 {
00286 mCaretColumn = mTextRows[mCaretRow].size();
00287 ret = true;
00288 }
00289
00290 else if (key.getValue() == Key::ENTER && mEditable)
00291 {
00292 mTextRows.insert(mTextRows.begin() + mCaretRow + 1,
00293 mTextRows[mCaretRow].substr(mCaretColumn, mTextRows[mCaretRow].size() - mCaretColumn));
00294 mTextRows[mCaretRow].resize(mCaretColumn);
00295 ++mCaretRow;
00296 mCaretColumn = 0;
00297 ret = true;
00298 }
00299
00300 else if (key.getValue() == Key::BACKSPACE
00301 && mCaretColumn != 0
00302 && mEditable)
00303 {
00304 int newpos = UTF8GetPrev(mTextRows[mCaretRow], mCaretColumn);
00305 mTextRows[mCaretRow].erase(newpos, mCaretColumn - newpos);
00306 mCaretColumn = newpos;
00307 ret = true;
00308 }
00309
00310 else if (key.getValue() == Key::BACKSPACE
00311 && mCaretColumn == 0
00312 && mCaretRow != 0
00313 && mEditable)
00314 {
00315 mCaretColumn = mTextRows[mCaretRow - 1].size();
00316 mTextRows[mCaretRow - 1] += mTextRows[mCaretRow];
00317 mTextRows.erase(mTextRows.begin() + mCaretRow);
00318 --mCaretRow;
00319 ret = true;
00320 }
00321
00322 else if (key.getValue() == Key::DELETE
00323 && mCaretColumn < (int)mTextRows[mCaretRow].size()
00324 && mEditable)
00325 {
00326 int newpos = UTF8GetNext(mTextRows[mCaretRow], mCaretColumn);
00327 mTextRows[mCaretRow].erase(mCaretColumn, newpos - mCaretColumn);
00328 ret = true;
00329 }
00330
00331 else if (key.getValue() == Key::DELETE
00332 && mCaretColumn == (int)mTextRows[mCaretRow].size()
00333 && mCaretRow < ((int)mTextRows.size() - 1)
00334 && mEditable)
00335 {
00336 mTextRows[mCaretRow] += mTextRows[mCaretRow + 1];
00337 mTextRows.erase(mTextRows.begin() + mCaretRow + 1);
00338 ret = true;
00339 }
00340
00341 else if(key.getValue() == Key::PAGE_UP)
00342 {
00343 int w, h, rowsPerPage;
00344 getParent()->getDrawSize(w, h, this);
00345 rowsPerPage = h / getFont()->getHeight();
00346 mCaretRow -= rowsPerPage;
00347
00348 if (mCaretRow < 0)
00349 {
00350 mCaretRow = 0;
00351 }
00352 ret = true;
00353 }
00354
00355 else if(key.getValue() == Key::PAGE_DOWN)
00356 {
00357 int w, h, rowsPerPage;
00358 getParent()->getDrawSize(w, h, this);
00359 rowsPerPage = h / getFont()->getHeight();
00360 mCaretRow += rowsPerPage;
00361
00362 if (mCaretRow >= (int)mTextRows.size())
00363 {
00364 mCaretRow = mTextRows.size() - 1;
00365 }
00366 ret = true;
00367 }
00368
00369 else if(key.getValue() == Key::TAB
00370 && mEditable)
00371 {
00372 mTextRows[mCaretRow].insert(mCaretColumn,std::string(" "));
00373 mCaretColumn += 4;
00374 ret = true;
00375 }
00376
00377 else if (key.getValue() == 'v' - 'a' + 1 && mEditable)
00378 {
00379 std::string str;
00380 if (GetClipboard(str) >= 0) {
00381 for (size_t i = 0; i < str.size(); ++i) {
00382 keyPress(Key(str[i]));
00383 }
00384 ret = true;
00385 }
00386 }
00387
00388 else if (key.isCharacter()
00389 && mEditable)
00390 {
00391 mTextRows[mCaretRow].insert(mCaretColumn,key.toString());
00392 mCaretColumn = UTF8GetNext(mTextRows[mCaretRow], mCaretColumn);
00393 ret = true;
00394 }
00395
00396 adjustSize();
00397 scrollToCaret();
00398 return ret;
00399 }
00400
00401 void TextBox::adjustSize()
00402 {
00403 unsigned int i;
00404 int width = 0;
00405 for (i = 0; i < mTextRows.size(); ++i)
00406 {
00407 int w = getFont()->getWidth(mTextRows[i]);
00408 if (width < w)
00409 {
00410 width = w;
00411 }
00412 }
00413
00414 setWidth(width + 1);
00415 setHeight(getFont()->getHeight() * mTextRows.size());
00416 }
00417
00418 void TextBox::setCaretPosition(unsigned int position)
00419 {
00420 int row;
00421
00422 for (row = 0; row < (int)mTextRows.size(); row++)
00423 {
00424 if (position <= mTextRows[row].size())
00425 {
00426 mCaretRow = row;
00427 mCaretColumn = position;
00428 return;
00429 }
00430 else
00431 {
00432 position--;
00433 }
00434 }
00435
00436
00437 mCaretRow = mTextRows.size() - 1;
00438 mCaretColumn = mTextRows[mCaretRow].size();
00439 }
00440
00441 unsigned int TextBox::getCaretPosition() const
00442 {
00443 int pos = 0, row;
00444
00445 for (row = 0; row < mCaretRow; row++)
00446 {
00447 pos += mTextRows[row].size();
00448 }
00449
00450 return pos + mCaretColumn;
00451 }
00452
00453 void TextBox::setCaretRowColumn(int row, int column)
00454 {
00455 setCaretRow(row);
00456 setCaretColumn(column);
00457 }
00458
00459 void TextBox::setCaretRow(int row)
00460 {
00461 mCaretRow = row;
00462
00463 if (mCaretRow >= (int)mTextRows.size())
00464 {
00465 mCaretRow = mTextRows.size() - 1;
00466 }
00467
00468 if (mCaretRow < 0)
00469 {
00470 mCaretRow = 0;
00471 }
00472
00473 setCaretColumn(mCaretColumn);
00474 }
00475
00476 unsigned int TextBox::getCaretRow() const
00477 {
00478 return mCaretRow;
00479 }
00480
00481 void TextBox::setCaretColumn(int column)
00482 {
00483 mCaretColumn = column;
00484
00485 if (mCaretColumn > (int)mTextRows[mCaretRow].size())
00486 {
00487 mCaretColumn = mTextRows[mCaretRow].size();
00488 }
00489
00490 if (mCaretColumn < 0)
00491 {
00492 mCaretColumn = 0;
00493 }
00494
00495 mCaretColumn = FindNext(mTextRows[mCaretRow], mCaretColumn);
00496 }
00497
00498 unsigned int TextBox::getCaretColumn() const
00499 {
00500 return mCaretColumn;
00501 }
00502
00503 const std::string& TextBox::getTextRow(int row) const
00504 {
00505 return mTextRows[row];
00506 }
00507
00508 void TextBox::setTextRow(int row, const std::string& text)
00509 {
00510 mTextRows[row] = text;
00511
00512 if (mCaretRow == row)
00513 {
00514 setCaretColumn(mCaretColumn);
00515 }
00516
00517 adjustSize();
00518 }
00519
00520 unsigned int TextBox::getNumberOfRows() const
00521 {
00522 return mTextRows.size();
00523 }
00524
00525 std::string TextBox::getText() const
00526 {
00527 if (mTextRows.size() == 0)
00528 {
00529 return std::string("");
00530 }
00531
00532 int i;
00533 std::string text;
00534
00535 for (i = 0; i < (int)mTextRows.size() - 1; ++i)
00536 {
00537 text = text + mTextRows[i] + "\n";
00538 }
00539
00540 text = text + mTextRows[i];
00541
00542 return text;
00543 }
00544
00545 void TextBox::fontChanged()
00546 {
00547 adjustSize();
00548 }
00549
00550 void TextBox::scrollToCaret()
00551 {
00552 Widget *par = getParent();
00553 if (par == NULL)
00554 {
00555 return;
00556 }
00557
00558 ScrollArea* scrollArea = dynamic_cast<ScrollArea *>(par);
00559 if (scrollArea != NULL)
00560 {
00561 Rectangle scroll;
00562 scroll.x = getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn));
00563 scroll.y = getFont()->getHeight() * mCaretRow;
00564 scroll.width = 6;
00565 scroll.height = getFont()->getHeight() + 2;
00566 scrollArea->scrollToRectangle(scroll);
00567 }
00568 }
00569
00570 void TextBox::setEditable(bool editable)
00571 {
00572 mEditable = editable;
00573 }
00574
00575 bool TextBox::isEditable() const
00576 {
00577 return mEditable;
00578 }
00579
00580 void TextBox::addRow(const std::string row)
00581 {
00582 mTextRows.push_back(row);
00583 adjustSize();
00584 }
00585
00586 bool TextBox::isOpaque()
00587 {
00588 return mOpaque;
00589 }
00590
00591 void TextBox::setOpaque(bool opaque)
00592 {
00593 mOpaque = opaque;
00594 }
00595 }