Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

pglineedit.cpp

Go to the documentation of this file.
00001 /*
00002     ParaGUI - crossplatform widgetset
00003     Copyright (C) 2000,2001,2002  Alexander Pipelka
00004  
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009  
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014  
00015     You should have received a copy of the GNU Library General Public
00016     License along with this library; if not, write to the Free
00017     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  
00019     Alexander Pipelka
00020     pipelka@teleweb.at
00021  
00022     Last Update:      $Author: mbickel $
00023     Update Date:      $Date: 2008-05-01 16:18:12 $
00024     Source File:      $Source: /home/cvspsrv/cvsroot/games/asc/source/libs/paragui/src/widgets/pglineedit.cpp,v $
00025     CVS/RCS Revision: $Revision: 1.3 $
00026     Status:           $State: Exp $
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         // should we draw the cursor ?
00068         if(my_isCursorVisible) {
00069 
00070                 if(my_cursorPosition < my_offsetX) {
00071                         my_offsetX = my_cursorPosition;
00072                 }
00073 
00074                 // check if my_cursorPosition is visible
00075                 if(x + GetCursorXPos() > (my_width - 2)) {
00076                         my_offsetX++;
00077                         DrawText(dst);
00078                         return;
00079                 }
00080 
00081                 DrawTextCursor();
00082         }
00083 
00084         // draw text
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         // draw simple cursor
00098         if(my_srfTextCursor == NULL) {
00099                 DrawVLine(GetCursorXPos() + 2, 2, h-4, PG_Color(0,0,0));
00100         }
00101 
00102         // draw a nice cursor bitmap
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         // loop all cursor positions
00136         for(Uint16 c=my_offsetX; c<=my_text.size(); c++) {
00137 
00138                 my_cursorPosition = c;
00139 
00140                 // get distance between screen point and cursor position
00141                 dist = abs(x - (my_xpos + 3 + GetCursorXPos()));
00142 
00143                 // store the minimum distance
00144                 if(dist < min_dist) {
00145                         min_dist = dist;
00146                         min_pos = c;
00147                 }
00148         }
00149 
00150         my_cursorPosition = old;
00151 
00152         // result should be stored in min_pos
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; // copy key structure
00192         PG_Application::TranslateNumpadKeys(&key_copy);
00193         // from now, we use key_copy which was copied or translated from key
00194 
00195         //
00196         // Maybe it would be a good idea to support the windoze CUI keyboard
00197         // bindings as well?
00198         //  /grendel, Nov 06
00199         //
00200         if( (key_copy.keysym.mod & KMOD_CTRL) && !(key_copy.keysym.mod & (KMOD_ALT | KMOD_SHIFT | KMOD_META  ) ) ) {
00201                 // Handle std emacs bindings
00202                 switch(key_copy.keysym.sym) {
00203                         case SDLK_a: // Beginning of Line
00204                                 SetCursorPos(0);
00205                                 return true;
00206 
00207                         case SDLK_e: // End of Line
00208                                 SetCursorPos(my_text.length());
00209                                 return true;
00210 
00211                         case SDLK_SPACE: // Set mark start
00212                                 StartMark(my_cursorPosition);
00213                                 return true;
00214 
00215                         case SDLK_w: // Cut from start mark
00216                                 if(!my_isEditable) {
00217                                         return false;
00218                                 }
00219                                 EndMark(my_cursorPosition);
00220                                 CopyText(true);
00221                                 return true;
00222 
00223                         case SDLK_k: // Delete all after point
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: // Paste buffer at point
00233                                 if(!my_isEditable) {
00234                                         return false;
00235                                 }
00236                                 PasteText(my_cursorPosition);
00237                                 return true;
00238 
00239                         case SDLK_f: // Forward char
00240                                 SetCursorPos(++my_cursorPosition);
00241                                 return true;
00242 
00243                         case SDLK_b: // Backward char
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                 // Handle std emacs bindings
00263                 switch(key_copy.keysym.sym) {
00264 
00265                         case SDLK_w: // Copy from start mark
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                 /*#ifdef ENABLE_UNICODE
00415                                 my_text.insert(my_cursorPosition, *c);
00416                 #else
00417                                 char buffer[2];
00418                                 buffer[0] = *c;
00419                                 buffer[1] = '\0';
00420                                 my_text.insert(my_cursorPosition, buffer);
00421                 #endif*/
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                 // No text is marked
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); // If end was > start
00467                 Update();
00468         }
00469         my_startMark = my_endMark = -1; // Reset mark
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         // load defaults first
00503         if(widgettype != "LineEdit") {
00504                 LoadThemeStyle("LineEdit");
00505         }
00506 
00507         // load custom values
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 }

Generated on Tue Jun 24 01:27:48 2008 for Advanced Strategic Command by  doxygen 1.4.2