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 #include "pglineedit.h"
00030 #include "pgapplication.h"
00031 #include "pgtheme.h"
00032
00033 PG_LineEdit::PG_LineEdit(PG_Widget* parent, const PG_Rect& r, const std::string& style, int _my_maximumLength) : PG_ThemeWidget(parent, r, style) {
00034
00035 my_buffer = "";
00036 my_cursorPosition = 0;
00037 my_maximumLength = _my_maximumLength;
00038 my_isCursorVisible = false;
00039 my_isEditable = true;
00040 my_offsetX = 0;
00041 my_srfTextCursor = NULL;
00042 my_startMark = -1;
00043 my_endMark = -1;
00044 my_passchar = 0;
00045 my_cursorBlinkState = true;
00046
00047 LoadThemeStyle(style);
00048
00049 if ( cursorBlinkingTime > 0 )
00050 PG_Application::GetApp()->sigAppIdle.connect( SigC::slot( *this, &PG_LineEdit::IdleBlinker ));
00051 }
00052
00053 PG_LineEdit::~PG_LineEdit() {}
00054
00055 void PG_LineEdit::eventBlit(SDL_Surface* surface, const PG_Rect& src, const PG_Rect& dst) {
00056 PG_ThemeWidget::eventBlit(surface, src, dst);
00057
00058 DrawText(dst);
00059 }
00060
00061 void PG_LineEdit::DrawText(const PG_Rect& dst) {
00062 int x, y;
00063
00064 x = 3;
00065 y = (my_height - GetFontHeight()) >> 1;
00066
00067
00068 if(my_isCursorVisible) {
00069
00070 if(my_cursorPosition < my_offsetX) {
00071 my_offsetX = my_cursorPosition;
00072 }
00073
00074
00075 if(x + GetCursorXPos() > (my_width - 2)) {
00076 my_offsetX++;
00077 DrawText(dst);
00078 return;
00079 }
00080
00081 DrawTextCursor();
00082 }
00083
00084
00085 PG_Widget::DrawText(x, y, GetDrawText());
00086 }
00087
00088 void PG_LineEdit::DrawTextCursor() {
00089 int x = my_xpos + 1;
00090 int y = my_ypos + 1;
00091 int h = my_height - 2;
00092
00093 my_cursorBlinkState = GetBlinkState();
00094 if ( !my_cursorBlinkState )
00095 return;
00096
00097
00098 if(my_srfTextCursor == NULL) {
00099 DrawVLine(GetCursorXPos() + 2, 2, h-4, PG_Color(0,0,0));
00100 }
00101
00102
00103 else {
00104 PG_Rect src, dst;
00105 PG_Rect rect(x + GetCursorXPos(), y + (Height() - my_srfTextCursor->h)/2, my_srfTextCursor->w, my_srfTextCursor->h);
00106 GetClipRects(src, dst, rect);
00107 PG_Widget::eventBlit(my_srfTextCursor, src, dst);
00108 }
00109
00110 }
00111
00112 Uint16 PG_LineEdit::GetCursorXPos() {
00113 Uint16 w;
00114
00115 int newpos = my_cursorPosition - my_offsetX;
00116
00117 if(newpos == 0)
00118 return 0;
00119
00120 PG_String drawtext = GetDrawText().substr(0, newpos);
00121 if(drawtext.empty())
00122 return 0;
00123
00124 PG_FontEngine::GetTextSize(drawtext, GetFont(), &w);
00125
00126 return w;
00127 }
00128
00129 int PG_LineEdit::GetCursorPosFromScreen(int x, int y) {
00130 int min_dist = 1000000;
00131 int min_pos = 0;
00132 int dist = 0;
00133 int old = my_cursorPosition;
00134
00135
00136 for(Uint16 c=my_offsetX; c<=my_text.size(); c++) {
00137
00138 my_cursorPosition = c;
00139
00140
00141 dist = abs(x - (my_xpos + 3 + GetCursorXPos()));
00142
00143
00144 if(dist < min_dist) {
00145 min_dist = dist;
00146 min_pos = c;
00147 }
00148 }
00149
00150 my_cursorPosition = old;
00151
00152
00153 return min_pos;
00154 }
00155
00156 PG_String PG_LineEdit::GetDrawText() {
00157 if (my_passchar == '\0')
00158 return my_text.substr(my_offsetX);
00159
00160 return PG_String(my_text.length(), my_passchar).substr(my_offsetX);
00161 }
00162
00163 void PG_LineEdit::EditBegin() {
00164 SetInputFocus();
00165 my_isCursorVisible = true;
00166 Update();
00167
00168 sigEditBegin(this);
00169 eventEditBegin(GetID(), this, 0,0);
00170 }
00171
00172 void PG_LineEdit::EditEnd() {
00173 my_offsetX = 0;
00174 my_cursorPosition = 0;
00175 my_isCursorVisible = false;
00176 Update();
00177 ReleaseInputFocus();
00178
00179 sigEditEnd(this);
00180 eventEditEnd(GetID(), this, 0,0);
00181 }
00182
00183 bool PG_LineEdit::eventKeyDown(const SDL_KeyboardEvent* key) {
00184 PG_Char c;
00185
00186 if(!my_isCursorVisible) {
00187 return false;
00188 }
00189
00190
00191 SDL_KeyboardEvent key_copy = *key;
00192 PG_Application::TranslateNumpadKeys(&key_copy);
00193
00194
00195
00196
00197
00198
00199
00200 if( (key_copy.keysym.mod & KMOD_CTRL) && !(key_copy.keysym.mod & (KMOD_ALT | KMOD_SHIFT | KMOD_META ) ) ) {
00201
00202 switch(key_copy.keysym.sym) {
00203 case SDLK_a:
00204 SetCursorPos(0);
00205 return true;
00206
00207 case SDLK_e:
00208 SetCursorPos(my_text.length());
00209 return true;
00210
00211 case SDLK_SPACE:
00212 StartMark(my_cursorPosition);
00213 return true;
00214
00215 case SDLK_w:
00216 if(!my_isEditable) {
00217 return false;
00218 }
00219 EndMark(my_cursorPosition);
00220 CopyText(true);
00221 return true;
00222
00223 case SDLK_k:
00224 if(!my_isEditable) {
00225 return false;
00226 }
00227 StartMark(my_cursorPosition);
00228 EndMark(my_text.length());
00229 CopyText(true);
00230 return true;
00231
00232 case SDLK_y:
00233 if(!my_isEditable) {
00234 return false;
00235 }
00236 PasteText(my_cursorPosition);
00237 return true;
00238
00239 case SDLK_f:
00240 SetCursorPos(++my_cursorPosition);
00241 return true;
00242
00243 case SDLK_b:
00244 SetCursorPos(--my_cursorPosition);
00245 return true;
00246
00247 case SDLK_d:
00248 if(!my_isEditable) {
00249 return false;
00250 }
00251 if(eventFilterKey(key)) {
00252 return false;
00253 }
00254 SendDel();
00255 return true;
00256
00257 default:
00258 return false;
00259 }
00260 } else if(key_copy.keysym.mod & (KMOD_ALT | KMOD_META)) {
00261
00262
00263 switch(key_copy.keysym.sym) {
00264
00265 case SDLK_w:
00266 EndMark(my_cursorPosition);
00267 CopyText();
00268 return true;
00269
00270 default:
00271 goto handleModKeys;
00272 }
00273 }
00274
00275 switch(key_copy.keysym.sym) {
00276
00277 case SDLK_TAB:
00278 return false;
00279
00280 case SDLK_LEFT:
00281
00282 SetCursorPos(--my_cursorPosition);
00283 return true;
00284
00285 case SDLK_RIGHT:
00286
00287 SetCursorPos(++my_cursorPosition);
00288 return true;
00289
00290 case SDLK_KP_ENTER:
00291 case SDLK_RETURN:
00292 if(!my_isEditable) {
00293 return false;
00294 }
00295 EditEnd();
00296 sigEditReturn(this);
00297 return true;
00298
00299 case SDLK_HOME:
00300 SetCursorPos(0);
00301 return true;
00302
00303 case SDLK_END:
00304 SetCursorPos(my_text.length());
00305 return true;
00306
00307 case SDLK_BACKSPACE:
00308 if(!my_isEditable) {
00309 return false;
00310 }
00311 if(eventFilterKey(key)) {
00312 return false;
00313 }
00314 SendBackspace();
00315 return true;
00316
00317 case SDLK_DELETE:
00318 if(!my_isEditable) {
00319 return false;
00320 }
00321 if(eventFilterKey(key)) {
00322 return false;
00323 }
00324 SendDel();
00325 return true;
00326
00327 default:
00328 handleModKeys:
00329 if(!my_isEditable) {
00330 return false;
00331 }
00332
00333 if(key_copy.keysym.unicode == 0) {
00334 return false;
00335 }
00336
00337 if(eventFilterKey(key)) {
00338 return false;
00339 }
00340
00341 if ((key_copy.keysym.unicode & 0xFF80) == 0) {
00342 c = key_copy.keysym.unicode & 0x7F;
00343
00344 if(!IsValidKey(c)) {
00345 return false;
00346 }
00347
00348 InsertChar(c);
00349 return true;
00350 } else {
00351 c = (PG_Char)key_copy.keysym.unicode;
00352
00353 if(!IsValidKey(c)) {
00354 return false;
00355 }
00356
00357 InsertChar(c);
00358 return true;
00359 }
00360
00361 return false;
00362 }
00363
00364 return false;
00365 }
00366
00367 void PG_LineEdit::eventInputFocusLost(PG_MessageObject* newfocus) {
00368 EditEnd();
00369 }
00370
00371 void PG_LineEdit::SetCursorPos(int p) {
00372
00373 if(p < 0) {
00374 p = 0;
00375 }
00376
00377 if(p > (int)my_text.size()) {
00378 p = (int)my_text.size();
00379 }
00380
00381 if (p > my_maximumLength) {
00382 p = my_maximumLength;
00383 }
00384
00385 my_cursorPosition = p;
00386
00387 if(my_offsetX > my_cursorPosition) {
00388 my_offsetX = my_cursorPosition;
00389 }
00390
00391 Update();
00392 }
00393
00394 int PG_LineEdit::GetCursorPos() {
00395 return my_cursorPosition;
00396 }
00397
00398 bool PG_LineEdit::eventMouseButtonUp(const SDL_MouseButtonEvent* button) {
00399 if(!my_isEditable) {
00400 return false;
00401 }
00402
00403 if(!my_isCursorVisible) {
00404 EditBegin();
00405 }
00406
00407 int p = GetCursorPosFromScreen(button->x, button->y);
00408 SetCursorPos(p);
00409 return true;
00410 }
00411
00412 void PG_LineEdit::InsertChar(const PG_Char& c) {
00413 if (my_cursorPosition < my_maximumLength) {
00414
00415
00416
00417
00418
00419
00420
00421
00422 my_text.insert(my_cursorPosition, 1, c);
00423 SetCursorPos(++my_cursorPosition);
00424 sigEditUpdate(this);
00425 }
00426 }
00427
00429 void PG_LineEdit::DeleteChar(Uint16 pos) {
00430 my_text.erase(pos, 1);
00431 sigEditUpdate(this);
00432 }
00433
00435 void PG_LineEdit::StartMark(Uint16 pos) {
00436 my_startMark = pos;
00437 my_endMark = -1;
00438 }
00439
00441 void PG_LineEdit::EndMark(Uint16 pos) {
00442 my_endMark = pos;
00443 }
00444
00446 void PG_LineEdit::CopyText(bool del) {
00447 int start, len;
00448 if(my_endMark == -1) {
00449 my_endMark = my_cursorPosition;
00450 }
00451 if(my_startMark == my_endMark ||
00452 my_startMark == -1) {
00453
00454 return;
00455 }
00456 if(my_startMark > my_endMark) {
00457 start = my_endMark;
00458 len = my_startMark - start;
00459 } else {
00460 start = my_startMark;
00461 len = my_endMark - start;
00462 }
00463 my_buffer = my_text.substr(start, len);
00464 if(del) {
00465 my_text.erase(start, len);
00466 SetCursorPos(my_cursorPosition);
00467 Update();
00468 }
00469 my_startMark = my_endMark = -1;
00470 }
00471
00473 void PG_LineEdit::PasteText(Uint16 pos) {
00474 if(!my_buffer.length()) {
00475 return;
00476 }
00477 my_text.insert(pos, my_buffer);
00478 my_cursorPosition += my_buffer.length();
00479 my_startMark = my_endMark = -1;
00480 Update();
00481 }
00482
00483 void PG_LineEdit::SetText(const std::string& new_text) {
00484 my_cursorPosition = 0;
00485 my_offsetX = 0;
00486 PG_Widget::SetText(new_text);
00487 }
00488
00489 void PG_LineEdit::eventEditBegin(int id, PG_Widget* widget, unsigned long data, void *clientdata) {}
00490
00491 void PG_LineEdit::eventEditEnd(int id, PG_Widget* widget, unsigned long data, void *clientdata) {}
00492
00493 bool PG_LineEdit::IsCursorVisible() {
00494 return my_isCursorVisible;
00495 }
00496
00497 bool PG_LineEdit::eventFilterKey(const SDL_KeyboardEvent* key) {
00498 return false;
00499 }
00500
00501 void PG_LineEdit::LoadThemeStyle(const std::string& widgettype) {
00502
00503 if(widgettype != "LineEdit") {
00504 LoadThemeStyle("LineEdit");
00505 }
00506
00507
00508 PG_ThemeWidget::LoadThemeStyle(widgettype, "LineEdit");
00509 LoadThemeStyle(widgettype, "LineEdit");
00510 }
00511
00512 void PG_LineEdit::LoadThemeStyle(const std::string& widgettype, const std::string& objectname) {
00513 PG_Theme* t = PG_Application::GetTheme();
00514
00515 my_srfTextCursor = t->FindSurface(widgettype, objectname, "textcursor");
00516
00517 const std::string& keys = t->FindString(widgettype, objectname, "validkeys");
00518
00519 if(!keys.empty()) {
00520 SetValidKeys(keys);
00521 }
00522 }
00523
00524 void PG_LineEdit::SendChar(PG_Char c) {
00525 if(!IsValidKey(c)) {
00526 return;
00527 }
00528
00529 InsertChar(c);
00530 }
00531
00532 void PG_LineEdit::SendDel() {
00533 DeleteChar(my_cursorPosition);
00534 SetCursorPos(my_cursorPosition);
00535 }
00536
00537 void PG_LineEdit::SendBackspace() {
00538 if(my_cursorPosition > 0) {
00539 PG_Application::BulkModeActivator bulk;
00540 DeleteChar(my_cursorPosition-1);
00541 SetCursorPos(--my_cursorPosition);
00542 bulk.disable();
00543 Update();
00544 }
00545 }
00546
00547 void PG_LineEdit::SetValidKeys(const std::string& keys) {
00548 my_validkeys = keys;
00549 }
00550
00551 bool PG_LineEdit::IsValidKey(PG_Char c) {
00552 if(my_validkeys.size() == 0) {
00553 return true;
00554 }
00555
00556 return (my_validkeys.find(c) != PG_String::npos);
00557 }
00558
00559 void PG_LineEdit::eventHide() {
00560 if(my_isCursorVisible) {
00561 EditEnd();
00562 }
00563 }
00564
00565 void PG_LineEdit::SetEditable(bool edit) {
00566 my_isEditable = edit;
00567 if (!edit && my_isCursorVisible)
00568 EditEnd();
00569 }
00570
00571 bool PG_LineEdit::GetEditable() {
00572 return my_isEditable;
00573 }
00574
00575 bool PG_LineEdit::Action(KeyAction action) {
00576
00577 switch(action) {
00578 case ACT_OK:
00579 EditBegin();
00580 return true;
00581 case ACT_CANCEL:
00582 EditEnd();
00583 return true;
00584 default:
00585 break;
00586 }
00587
00588 return PG_Widget::Action(action);
00589 }
00590
00591 void PG_LineEdit::SetPassHidden(const PG_Char& passchar) {
00592 my_passchar = passchar;
00593 }
00594
00595 char PG_LineEdit::GetPassHidden() {
00596 return my_passchar;
00597 }
00598
00599
00600 int PG_LineEdit::cursorBlinkingTime = 0;
00601
00602 void PG_LineEdit::SetBlinkingTime( int msec )
00603 {
00604 cursorBlinkingTime = msec;
00605 }
00606
00607 bool PG_LineEdit::GetBlinkState()
00608 {
00609 if ( cursorBlinkingTime <= 0 )
00610 return true;
00611 else
00612 return (SDL_GetTicks() / cursorBlinkingTime) & 1;
00613 }
00614
00615
00616 bool PG_LineEdit::IdleBlinker()
00617 {
00618 if ( my_isCursorVisible )
00619 if ( GetBlinkState() != my_cursorBlinkState )
00620 Update();
00621
00622 return true;
00623 }