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 "guichan/keyinput.h"
00060 #include "guichan/mouseinput.h"
00061 #include "guichan/widgets/textfield.h"
00062 #include "guichan/exception.h"
00063 #include "util.h"
00064
00065 namespace gcn
00066 {
00067 TextField::TextField()
00068 {
00069 mCaretPosition = 0;
00070 mXScroll = 0;
00071 mSelectStart = 0;
00072 mSelectEndOffset = 0;
00073
00074 setFocusable(true);
00075
00076 addMouseListener(this);
00077 addKeyListener(this);
00078 adjustHeight();
00079 setBorderSize(1);
00080 }
00081
00082 TextField::TextField(const std::string& text)
00083 {
00084 mCaretPosition = 0;
00085 mXScroll = 0;
00086 mSelectStart = 0;
00087 mSelectEndOffset = 0;
00088
00089 mText = text;
00090 adjustSize();
00091 setBorderSize(1);
00092
00093 setFocusable(true);
00094
00095 addMouseListener(this);
00096 addKeyListener(this);
00097 }
00098
00099 void TextField::setText(const std::string& text)
00100 {
00101 if ((int)text.size() < mCaretPosition )
00102 {
00103 mCaretPosition = text.size();
00104 }
00105
00106 mText = text;
00107 }
00108
00109 void TextField::draw(Graphics* graphics)
00110 {
00111 Font *font;
00112 int x, y;
00113 Color faceColor = getBackgroundColor();
00114 graphics->setColor(faceColor);
00115 graphics->fillRectangle(Rectangle(0, 0, getWidth(), getHeight()));
00116
00117 if (hasFocus())
00118 {
00119 drawCaret(graphics, getFont()->getWidth(mText.substr(0, mCaretPosition)) - mXScroll);
00120 }
00121
00122 graphics->setColor(getForegroundColor());
00123 font = getFont();
00124 graphics->setFont(font);
00125
00126 x = 1 - mXScroll;
00127 y = 1;
00128
00129 if (mSelectEndOffset != 0)
00130 {
00131 unsigned int first;
00132 unsigned int len;
00133 int selX;
00134 int selW;
00135 std::string tmpStr;
00136
00137 getTextSelectionPositions(&first, &len);
00138
00139 tmpStr = std::string(mText.substr(0, first));
00140 selX = font->getWidth(tmpStr);
00141
00142 tmpStr = std::string(mText.substr(first, len));
00143 selW = font->getWidth(tmpStr);
00144
00145 graphics->setColor(Color(127, 127, 127));
00146 graphics->fillRectangle(Rectangle(x + selX, y, selW, font->getHeight()));
00147 }
00148
00149 graphics->drawText(mText, x, y);
00150 }
00151
00152 void TextField::drawBorder(Graphics* graphics)
00153 {
00154 Color faceColor = getBaseColor();
00155 Color highlightColor, shadowColor;
00156 int alpha = getBaseColor().a;
00157 int width = getWidth() + getBorderSize() * 2 - 1;
00158 int height = getHeight() + getBorderSize() * 2 - 1;
00159 highlightColor = faceColor + 0x303030;
00160 highlightColor.a = alpha;
00161 shadowColor = faceColor - 0x303030;
00162 shadowColor.a = alpha;
00163
00164 unsigned int i;
00165 for (i = 0; i < getBorderSize(); ++i)
00166 {
00167 graphics->setColor(shadowColor);
00168 graphics->drawLine(i,i, width - i, i);
00169 graphics->drawLine(i,i + 1, i, height - i - 1);
00170 graphics->setColor(highlightColor);
00171 graphics->drawLine(width - i,i + 1, width - i, height - i);
00172 graphics->drawLine(i,height - i, width - i - 1, height - i);
00173 }
00174 }
00175
00176 void TextField::drawCaret(Graphics* graphics, int x)
00177 {
00178 graphics->setColor(getForegroundColor());
00179 graphics->drawLine(x, getHeight() - 2, x, 1);
00180 }
00181
00182 void TextField::mousePress(int x, int y, int button)
00183 {
00184 if (hasMouse() && button == MouseInput::LEFT)
00185 {
00186 mCaretPosition = getFont()->getStringIndexAt(mText, x + mXScroll);
00187 mSelectStart = mCaretPosition;
00188 mSelectEndOffset = 0;
00189 fixScroll();
00190 }
00191 else if (hasMouse() && button == MouseInput::MIDDLE)
00192 {
00193 std::string str;
00194 if (GetClipboard(str) >= 0) {
00195 for (size_t i = 0; i < str.size(); ++i) {
00196 keyPress(Key(str[i]));
00197 }
00198 }
00199 }
00200 }
00201
00202 void TextField::mouseMotion(int x, int y)
00203 {
00204 if (isDragged() && mClickButton == MouseInput::LEFT)
00205 {
00206 mCaretPosition = getFont()->getStringIndexAt(mText, x + mXScroll);
00207 mSelectEndOffset = mCaretPosition - mSelectStart;
00208 setDirty(true);
00209 }
00210 }
00211
00212 bool TextField::keyPress(const Key& key)
00213 {
00214 bool ret = false;
00215 unsigned int selFirst;
00216 unsigned int selLen;
00217
00218 getTextSelectionPositions(&selFirst, &selLen);
00219
00220 if (key.getValue() == Key::LEFT)
00221 {
00222 if (mCaretPosition > 0) {
00223 mCaretPosition = UTF8GetPrev(mText, mCaretPosition);
00224 if (mCaretPosition < 0) {
00225 throw GCN_EXCEPTION("Invalid UTF8.");
00226 }
00227
00228 if (key.isShiftPressed()) {
00229 --mSelectEndOffset;
00230 } else {
00231 mSelectStart = mCaretPosition;
00232 mSelectEndOffset = 0;
00233 }
00234 } else if (!key.isShiftPressed()) {
00235 mSelectStart = mCaretPosition;
00236 mSelectEndOffset = 0;
00237 }
00238
00239 ret = true;
00240 }
00241
00242 else if (key.getValue() == Key::RIGHT)
00243 {
00244 if (mCaretPosition < (int)mText.size()) {
00245 mCaretPosition = UTF8GetNext(mText, mCaretPosition);
00246 if (mCaretPosition > (int)mText.size()) {
00247 throw GCN_EXCEPTION("Invalid UTF8.");
00248 }
00249
00250 if (key.isShiftPressed()) {
00251 ++mSelectEndOffset;
00252 } else {
00253 mSelectStart = mCaretPosition;
00254 mSelectEndOffset = 0;
00255 }
00256 } else if (!key.isShiftPressed()) {
00257 mSelectStart = mCaretPosition;
00258 mSelectEndOffset = 0;
00259 }
00260
00261 ret = true;
00262 }
00263
00264 else if (key.getValue() == Key::DELETE )
00265 {
00266 if (selLen > 0) {
00267 mText.erase(selFirst, selLen);
00268 mCaretPosition = selFirst;
00269 mSelectStart = selFirst;
00270 mSelectEndOffset = 0;
00271 } else if (mCaretPosition < (int)mText.size()) {
00272 int newpos = UTF8GetNext(mText, mCaretPosition);
00273 if (mCaretPosition > (int)mText.size()) {
00274 throw GCN_EXCEPTION("Invalid UTF8.");
00275 }
00276 mText.erase(mCaretPosition, newpos - mCaretPosition);
00277 ret = true;
00278 }
00279 }
00280
00281 else if (key.getValue() == Key::BACKSPACE || key.getValue() == 'h' - 'a' + 1)
00282 {
00283 if (selLen > 0) {
00284 mText.erase(selFirst, selLen);
00285 mCaretPosition = selFirst;
00286 mSelectStart = selFirst;
00287 mSelectEndOffset = 0;
00288 } else if (mCaretPosition > 0) {
00289 int newpos = UTF8GetPrev(mText, mCaretPosition);
00290 if (mCaretPosition < 0) {
00291 throw GCN_EXCEPTION("Invalid UTF8.");
00292 }
00293 mText.erase(newpos, mCaretPosition - newpos);
00294 mCaretPosition = newpos;
00295 ret = true;
00296 }
00297 }
00298
00299 else if (key.getValue() == Key::ENTER)
00300 {
00301 generateAction();
00302 ret = true;
00303 }
00304
00305 else if (key.getValue() == Key::HOME || key.getValue() == 'a' - 'a' + 1)
00306 {
00307 if (key.isShiftPressed()) {
00308 mSelectEndOffset -= mCaretPosition;
00309 } else {
00310 mSelectStart = 0;
00311 mSelectEndOffset = 0;
00312 }
00313 mCaretPosition = 0;
00314
00315 ret = true;
00316 }
00317
00318 else if (key.getValue() == Key::END || key.getValue() == 'e' - 'a' + 1)
00319 {
00320 if (key.isShiftPressed()) {
00321 mSelectEndOffset += mText.size() - mCaretPosition;
00322 } else {
00323 mSelectStart = mText.size();
00324 mSelectEndOffset = 0;
00325 }
00326 mCaretPosition = mText.size();
00327
00328 ret = true;
00329 }
00330
00331 else if (key.getValue() == 'u' - 'a' + 1)
00332 {
00333 setText("");
00334 ret = true;
00335 }
00336
00337 else if (key.getValue() == 'v' - 'a' + 1)
00338 {
00339 std::string str;
00340
00341 if (selLen > 0) {
00342 mText.erase(selFirst, selLen);
00343 mCaretPosition = selFirst;
00344 mSelectStart = selFirst;
00345 mSelectEndOffset = 0;
00346 }
00347
00348 if (GetClipboard(str) >= 0) {
00349 for (size_t i = 0; i < str.size(); ++i) {
00350 keyPress(Key(str[i]));
00351 }
00352 ret = true;
00353 }
00354 }
00355
00356 else if (key.isCharacter())
00357 {
00358 if (selLen > 0) {
00359 mText.erase(selFirst, selLen);
00360 mCaretPosition = selFirst;
00361 mSelectStart = selFirst;
00362 mSelectEndOffset = 0;
00363 }
00364
00365 mText.insert(mCaretPosition,key.toString());
00366 mCaretPosition = UTF8GetNext(mText, mCaretPosition);
00367 if (mCaretPosition > (int)mText.size()) {
00368 throw GCN_EXCEPTION("Invalid UTF8.");
00369 }
00370 mSelectStart = mCaretPosition;
00371 mSelectEndOffset = 0;
00372 ret = true;
00373 }
00374
00375 fixScroll();
00376 setDirty(true);
00377 return ret;
00378 }
00379
00380 void TextField::adjustSize()
00381 {
00382 setWidth(getFont()->getWidth(mText) + 4);
00383 adjustHeight();
00384
00385 fixScroll();
00386 }
00387
00388 void TextField::adjustHeight()
00389 {
00390 setHeight(getFont()->getHeight() + 2);
00391 }
00392
00393 void TextField::fixScroll()
00394 {
00395 if (hasFocus())
00396 {
00397 int caretX = getFont()->getWidth(mText.substr(0, mCaretPosition));
00398
00399 if (caretX - mXScroll > getWidth() - 4)
00400 {
00401 mXScroll = caretX - getWidth() + 4;
00402 }
00403 else if (caretX - mXScroll < getFont()->getWidth(" "))
00404 {
00405 mXScroll = caretX - getFont()->getWidth(" ");
00406
00407 if (mXScroll < 0)
00408 {
00409 mXScroll = 0;
00410 }
00411 }
00412 }
00413 }
00414
00415 void TextField::setCaretPosition(unsigned int position)
00416 {
00417 if (position > mText.size())
00418 {
00419 mCaretPosition = mText.size();
00420 }
00421 else
00422 {
00423 mCaretPosition = position;
00424 }
00425
00426 fixScroll();
00427 }
00428
00429 unsigned int TextField::getCaretPosition() const
00430 {
00431 return mCaretPosition;
00432 }
00433
00434 void TextField::getTextSelectionPositions(unsigned int* first, unsigned int* len)
00435 {
00436 if (mSelectEndOffset < 0)
00437 {
00438 *first = mSelectStart + mSelectEndOffset;
00439 *len = -mSelectEndOffset;
00440 }
00441 else
00442 {
00443 *first = mSelectStart;
00444 *len = mSelectEndOffset;
00445 }
00446 }
00447
00448 const std::string& TextField::getText() const
00449 {
00450 return mText;
00451 }
00452
00453 void TextField::fontChanged()
00454 {
00455 fixScroll();
00456 }
00457 }