Home || Architecture || Video Search || Visual Search || Scripts || Applications || Important Messages || OGL || Src

TextEdit.h

Go to the documentation of this file.
00001 /*
00002 12345678901234567890123456789012345678901234567890123456789012345678901234567890
00003 */
00004 #ifndef OglGui_TextEdit_h
00005 #define OglGui_TextEdit_h
00006 
00007 #include <deque>
00008 
00009 #ifndef OglGui_DocDimensions_h
00010 #include "OglGui/DocDimensions.h"
00011 #endif
00012 
00013 #ifndef OglGui_WindowScrollBar_h
00014 #include "OglGui/WindowScrollBar.h"
00015 #endif
00016 
00017 #ifndef OglGui_TextEditListener_h
00018 #include "OglGui/TextEditListener.h"
00019 #endif
00020 
00021 
00022 namespace OglGui
00023 {
00024 
00025 class TextEdit : public Window, public DocDimensions, ScrollBarListener, RepeatTimer
00026 {
00027     typedef std::string string;
00028 
00029 public:
00030 
00031     TextEdit(int x, int y, int w, int h, strconst text, int sB=3) :
00032         Window(x, y, w, h)
00033     {
00034         Init(text, w, h, sB);
00035     }
00036 
00037     TextEdit(Window* parent, int w, int h, strconst text, int sB=3) :
00038         Window(parent, w, h)
00039     {
00040         Init(text, w, h, sB);
00041     }
00042 
00043     TextEdit(Window* parent, int x,int y, int w,int h, strconst text, int sB=3):
00044         Window(parent, x, y, w, h)
00045     {
00046         Init(text, w, h, sB);
00047     }
00048 
00050 // ChangeInfo inner class for infinite undo/redo
00051     class ChangeInfo
00052     {
00053     public:
00054         ChangeInfo(int ind1, int ind2, std::string* str, int caret, int mark)
00055         {
00056             mStart = ind1;
00057             mEnd   = ind2;
00058             mCaret = caret;
00059             mMark  = mark;
00060             mStr  = *str;
00061         }
00062 
00063         int Start()       { return mStart; }
00064         int End()         { return mEnd; }
00065         int Caret()       { return mCaret; }
00066         int Mark()        { return mMark; }
00067         std::string Str() { return mStr; }
00068 
00069     private:
00070         std::string     mStr;
00071         int             mStart, mEnd;
00072         int             mCaret, mMark;
00073     };
00074 
00076 // End of ChangeInfo inner class
00078 
00080 // Infinite undo/redo stuff
00081 // NOTE: Should probably be made private
00082     void EmptyChangeInfoDeque(std::deque<ChangeInfo*>& deQue)
00083     {
00084         ChangeInfo *changeInfo;
00085         while (!deQue.empty())
00086         {
00087             changeInfo = deQue.back();
00088             deQue.pop_back();
00089             delete changeInfo;
00090         }
00091     }
00092 
00093     void UndoAction()
00094     {
00095         if (undoDeque.empty())
00096             return;
00097 
00098         ChangeInfo* undo = undoDeque.back();
00099         undoDeque.pop_back();
00100 
00101         ChangeInfo* redo = undoDeque.back();
00102         undoDeque.pop_back();
00103 
00104         mText.replace(undo->Start(), undo->End() - undo->Start(), undo->Str());
00105         mCaret = undo->Caret();
00106         mMark  = undo->Mark();
00107 
00108         redoDeque.push_back(redo);
00109         redoDeque.push_back(undo);
00110 
00111         RecomputeDocument();
00112         PublishChange();
00113     }
00114 
00115     void RedoAction()
00116     {
00117         if (redoDeque.empty())
00118             return;
00119 
00120         ChangeInfo* undo = redoDeque.back();
00121         redoDeque.pop_back();
00122 
00123         ChangeInfo* redo = redoDeque.back();
00124         redoDeque.pop_back();
00125 
00126         mText.replace(redo->Start(), redo->End() - redo->Start(), redo->Str());
00127         mCaret = redo->Caret();
00128         mMark  = redo->Mark();
00129 
00130         undoDeque.push_back(redo);
00131         undoDeque.push_back(undo);
00132 
00133         RecomputeDocument();
00134         PublishChange();
00135     }
00136 
00137     void UndoableInsertKey(int c)
00138     {
00139         string  str = "";
00140         string  redoStr = "";
00141         char    buf[2];
00142         int     left, right;
00143 
00144         if (!redoDeque.empty())
00145             EmptyChangeInfoDeque(redoDeque);
00146 
00147         buf[0] = c; buf[1] = '\0';
00148         redoStr += buf;
00149 
00150         GetSelectionLeftRight(left, right);
00151 
00152         ChangeInfo* redo = new ChangeInfo(left, right, &redoStr,
00153                                           left+(c?1:0), left+(c?1:0));
00154         if (left != right)
00155             str = mText.substr(left, right-left);
00156         ChangeInfo* undo = new ChangeInfo(left, left+(c?1:0), &str,
00157                                           mCaret, mMark);
00158 
00159         undoDeque.push_back(redo);
00160         undoDeque.push_back(undo);
00161     }
00162 
00163     void UndoableInsertString(string str)
00164     {
00165         string  undoStr = "";
00166         int     left, right;
00167 
00168         if (!redoDeque.empty())
00169             EmptyChangeInfoDeque(redoDeque);
00170 
00171         GetSelectionLeftRight(left, right);
00172 
00173         if (left != right)
00174             undoStr = mText.substr(left, right-left);
00175 
00176         ChangeInfo* redo = new ChangeInfo(left, left+undoStr.length(), &str,
00177                                           left+str.length(), left+str.length());
00178 
00179         ChangeInfo* undo = new ChangeInfo(left, left + str.length(), &undoStr,
00180                                           mCaret, mMark);
00181 
00182         undoDeque.push_back(redo);
00183         undoDeque.push_back(undo);
00184     }
00185 
00186     void UndoableDeleteKey(int dir)
00187     {
00188         string  str = "";
00189         string  undoStr = "";
00190         char    buf[2];
00191 
00192         if (!redoDeque.empty())
00193             EmptyChangeInfoDeque(redoDeque);
00194 
00195         int chInd = mCaret + (dir == -1 ? -1 : 0); 
00196         buf[0] = mText[chInd];
00197         buf[1] = '\0';
00198         undoStr += buf;
00199 
00200         ChangeInfo* redo = new ChangeInfo(mCaret + (dir==-1 ? -1:0),
00201                                           mCaret + (dir==-1 ?  0:1), &str,
00202                                           mCaret, mCaret);
00203 
00204         ChangeInfo* undo = new ChangeInfo(mCaret + (dir==-1 ? -1:0),
00205                                           mCaret + (dir==-1 ? -1:0), &undoStr,
00206                                           mCaret, mMark);
00207         undoDeque.push_back(redo);
00208         undoDeque.push_back(undo);
00209     }
00211 // End of undo/redo related stuff
00213 
00215 // Convenience functions
00216     bool ReadFile(strconst fileName)
00217     {
00218         if (mSingleLine)
00219             return false;
00220 
00221         int nBytes = -1;
00222         FILE *fp = fopen(fileName.c_str(), "rb");
00223         if (fp)
00224         {
00225             fseek(fp, 0, SEEK_END);
00226             nBytes = ftell(fp);
00227             fseek(fp, 0, SEEK_SET);
00228             char* buf = (char *) malloc(nBytes+1);
00229             if (buf)
00230             {
00231                 nBytes = fread(buf, sizeof(char), nBytes, fp);
00232                 buf[nBytes] = '\0';
00233                 // Get rid of 13 10 newline combinations
00234                 char *tmpBuf = (char*) malloc(nBytes+1);
00235                 if (tmpBuf)
00236                 {
00237                     int ind=0;
00238                     for (int i=0; i<=nBytes; i++)
00239                         if (buf[i] != 13)
00240                             tmpBuf[ind++] = buf[i];
00241                     SetText(tmpBuf);
00242                     free(tmpBuf);
00243                 }
00244                 else
00245                     SetText(buf);
00246                 free(buf);
00247             }
00248             else
00249                 nBytes = -1;
00250             fclose(fp);
00251         }
00252         return nBytes != -1;
00253     }
00254 
00255     void PublishChange()
00256     {
00257         if (mListener)
00258             mListener->TextEditChangedEvent(this, mListenerData);
00259     }
00260 
00262 // Setters / Getters
00263     void SetTextEditListener(TextEditListener* listener, void* userData=0)
00264     {
00265         mListener = listener;
00266         mListenerData = userData;
00267     }
00268 
00269     void SetText(strconst txt)
00270     {
00271         EmptyChangeInfoDeque(undoDeque);
00272         EmptyChangeInfoDeque(redoDeque);
00273 
00274         if (mSingleLine)
00275         {
00276             string str;
00277             int pos = txt.find_first_of("\n", 0);
00278             if (pos == string::npos)
00279                 pos = txt.length();
00280             str = txt.substr(0, pos);
00281             mText = str;
00282         }
00283         else
00284             mText = txt;
00285 
00286         mDocX = mDocY = 0;
00287         mCaret = mMark = 0;
00288         RecomputeDocument();
00289         PublishChange();
00290         mDocX = 0;
00291     }
00292 
00293     string GetText() { return mText; }
00294 
00295     ScrollBar* HorizontalScrollBar() { return mHorizontalScrollBar; }
00296     ScrollBar* VerticalScrollBar() { return mVerticalScrollBar; }
00297 
00298     void  Editable(bool mode) { mEditable = mode; }
00299     bool  Editable() { return mEditable; }
00300 
00301     void  SingleLine(bool mode) { mSingleLine = mode; }
00302     bool  SingleLine() { return mSingleLine; }
00303 
00304     void  ClipBackground(bool mode) { mClipBackground = mode; }
00305     bool  ClipBackground() { return mClipBackground; }
00306 
00307     void  CaretColor(ULONG col) { mCaretColor = col; }
00308     ULONG CaretColor() { return mCaretColor; }
00309 
00310     void  TextShadowed(bool mode) { mTextShadowed = mode; }
00311     bool  TextShadowed() { return mTextShadowed; }
00312 
00313     void  TextShadowColor(ULONG shadCol) { mShadowColor = shadCol; };
00314     ULONG TextShadowColor() { return mShadowColor; };
00315 
00316     void  LineHeight(int h) { mLineH = h; }
00317     int   LineHeight() { return mLineH; }
00318 
00319     int   Length() { return mText.length(); }
00320 
00321     string GetSelection()
00322     {
00323         if (mMark == mCaret)
00324             return "";
00325 
00326         int left, right;
00327         GetSelectionLeftRight(left, right);
00328         return mText.substr(left, right-left);
00329     }
00330 
00331     void SetCaretMark(int caret, int mark)
00332     {
00333         Caret(caret);
00334         Mark(mark);
00335     }
00336 
00337     void Caret(int ind)
00338     {
00339         if ((mCaret = ind) > mText.length())
00340             mCaret = mText.length();
00341         if (mCaret < 0)
00342             mCaret = 0;
00343     }
00344 
00345     void  Mark(int ind)
00346     {
00347         if ((mMark = ind) > mText.length())
00348             mMark = mText.length();
00349         if (mMark < 0)
00350             mMark = 0;
00351     }
00352 
00353     int Caret()  { return mCaret; }
00354     int Mark()   { return mMark; }
00355     int CaretX() { return mCaretX; }
00356     int CaretY() { return mCaretY; }
00358 // End of Setter / Getters
00360     void RecomputeDocument()
00361     {
00362         ComputeDocHeight();
00363         ClampDocY();
00364         ComputeCaretPosition();
00365         MoveToCaret();
00366     }
00367 
00368     int ComputeDocHeight()
00369     {
00370         int h = 0;
00371         int nChar;
00372         int ind = 0;
00373 
00374         while ((nChar = GetLineAtIndex(0, ind))!=-1)
00375         {
00376             ind += nChar+1;
00377             h += mLineH;
00378         }
00379         return mDocH = h;
00380     }
00381 
00382     int ComputeMaxWidth()
00383     {
00384         string  str;
00385         int     nChar;
00386         int     lineInd = 0;
00387         int     x, maxX = 0;
00388 
00389         while ((nChar = GetLineAtIndex(&str, lineInd) + 1))
00390         {
00391             x = FindWidthAtIndex(&str, str.length());
00392             if (x > maxX)
00393                 maxX = x;
00394             lineInd += nChar;
00395         }
00396         return maxX;
00397     }
00398 
00399     void ComputeCaretPosition()
00400     {
00401         int y = mDocH + mDocY - mLineH;
00402         int lineInd = 0;
00403         int nChar;
00404 
00405         while ((nChar = GetLineAtIndex(0, lineInd) + 1) &&
00406                lineInd+nChar <= mCaret)
00407         {
00408             lineInd += nChar;
00409             y -= mLineH;
00410         }
00411         mCaretY = y;
00412 
00413         int x = mLeftMargin;
00414         if (nChar)
00415         {
00416             string str;
00417             GetLineAtIndex(&str, lineInd);
00418             x = FindWidthAtIndex(&str, mCaret - lineInd) + mDocX;
00419         }
00420         mCaretX = x;
00421     }
00422 
00423     void ClampDocX()
00424     {
00425         if (mDocX > 0)
00426             mDocX = 0;
00427         if (mDocX + mDocW < W())
00428             mDocX = W() - mDocW;
00429     }
00430 
00431     void ClampDocY()
00432     {
00433         if (mDocY < H() - mDocH)
00434             mDocY = H() - mDocH;
00435         if (mDocY > H() - mLineH)
00436             mDocY = H() - mLineH;
00437     }
00438 
00439     void GetSelectionLeftRight(int& left, int& right)
00440     {
00441         if (mMark < mCaret)
00442         {
00443             left  = mMark;
00444             right = mCaret;
00445         }
00446         else
00447         {
00448             left  = mCaret;
00449             right = mMark;
00450         }
00451     }
00452 
00453     int FindIndexAtWidth(string* str, int w)
00454     {
00455         int len = str->length();
00456         int ind = 0, indW;
00457         while (ind<len && (indW=FindWidthAtIndex(str, ind)) < w)
00458             ind++;
00459         return ind;
00460     }
00461 
00462     int FindInsertionIndexAtWidth(string* str, int w)
00463     {
00464         int len = str->length();
00465         int ind = 0, indW;
00466         while (ind<len && (indW=FindWidthAtIndex(str, ind)) < w)
00467             ind++;
00468  
00469         // Find closest side for insertion. If clicked on first halve of
00470         // character insert before, otherwise after
00471         if (ind && (indW - (indW - FindWidthAtIndex(str, ind-1))/2) > w)
00472             ind--;
00473         return ind;
00474     }
00475 
00476     int FindWidthAtIndex(string* str, int ind)
00477     {
00478         char    buf[2048];
00479         int     w, h;
00480         void*   font;
00481 
00482         int     tPos, tInd = 0, tCnt = 0, tabW;
00483         int     totWidth = 0;
00484         string  tabStr;
00485 
00486         if (ind > str->length())
00487             ind = str->length();
00488         if (ind > 2047)
00489             ind = 2047;
00490 
00491         FindOglFont(mOglWnd, &font, NULL);
00492 
00493         if ((tPos = str->find_first_of("\t")) == string::npos)
00494         {
00495             buf[0] = '\0';
00496             strncpy(buf, str->c_str(), ind);
00497             buf[ind] = '\0';
00498             oglSys.AbstFontTextSize(mOglWnd, font, buf, &w, &h);
00499             return mLeftMargin + w;
00500         }
00501 
00502         oglSys.AbstFontTextSize(mOglWnd, font, "    ", &w, &h);
00503         tabW = w;
00504 
00505         bool done = false;
00506         while (!done && ((tPos = str->find_first_of("\t",tInd)) != string::npos))
00507         {
00508             tabStr = str->substr(tInd, tPos-tInd);
00509             if (ind > tInd + tabStr.length())
00510             {
00511                 oglSys.AbstFontTextSize(mOglWnd, font, tabStr.c_str(), &w, &h);
00512                 tCnt = (totWidth + w) / tabW + 1;
00513                 totWidth = tCnt * tabW;
00514             }
00515             else
00516             {
00517                 tabStr = tabStr.substr(0, ind - tInd);
00518                 oglSys.AbstFontTextSize(mOglWnd, font, tabStr.c_str(), &w, &h);
00519                 totWidth += w;
00520                 done = true;
00521             }
00522             tInd = tPos+1;
00523         }
00524         if (!done)
00525         {
00526             tabStr = str->substr(tInd, ind - tInd);
00527             oglSys.AbstFontTextSize(mOglWnd, font, tabStr.c_str(), &w, &h);
00528             totWidth += w;
00529         }
00530         return mLeftMargin + totWidth;
00531     }
00532 
00533 /*
00534     // No tab support version
00535     int FindWidthAtIndex(string* str, int ind)
00536     {
00537         char    buf[2048];
00538         int     w, h, font;
00539         
00540         FindOglFont(mOglWnd, &font, NULL);
00541 
00542         buf[0] = '\0';
00543         strncpy(buf, str->c_str(), ind);
00544         buf[ind] = '\0';
00545         oglSys.AbstFontTextSize(mOglWnd, font, buf, &w, &h);
00546         return mLeftMargin + w;
00547     }
00548 */
00549 
00550     int FindLineAtY(int wndY, int &lineY)
00551     {
00552         int ind = 0, nChar = 0;
00553         int y = mDocH + mDocY - mLineH;
00554 
00555         while (y > wndY && (nChar = GetLineAtIndex(0, ind))!=-1)
00556         {
00557             ind += nChar+1;
00558             y -= mLineH;
00559         }
00560         if (ind > mText.length())
00561             ind = mText.length();
00562         lineY = y;
00563         return ind;
00564     }
00565 
00566     int FindFirstVisibleLine(int &lineY)
00567     {
00568         return FindLineAtY( H(), lineY);
00569     }
00570 
00571     int GetLineAtIndex(string* str, int ind)
00572     {
00573         if (ind >= mText.length())
00574             return -1;
00575         int pos = mText.find_first_of("\n", (size_t) ind);
00576         if (pos == string::npos)
00577             pos = mText.length();
00578         if (str!=0)
00579             *str = (pos-ind) ? mText.substr(ind, pos-ind) : "";
00580         return pos-ind;
00581     }
00582 
00583     void InvertBlock(int x1, int y1, int x2, int y2)
00584     {
00585         glColor3d(1,1,1);
00586         glEnable(GL_BLEND);
00587         glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
00588         glBegin(GL_QUADS);
00589         glVertex2d(x1, y1);
00590         glVertex2d(x1, y2);
00591         glVertex2d(x2, y2);
00592         glVertex2d(x2, y1);
00593         glEnd();
00594         glDisable(GL_BLEND);
00595     }
00596 
00597     void HandleInvertLineSelection(string *str, int ind, int indEnd, int y)
00598     {
00599         if (mMark == mCaret)
00600             return;
00601 
00602         int left, right;
00603         int xEnd, xStart, yEnd = y + mLineH;
00604 
00605         GetSelectionLeftRight(left, right);
00606 
00607         if (ind >= left && indEnd <= right)
00608         {
00609             if (*str == "")
00610                 xEnd = mLeftMargin+4;
00611             else
00612                 xEnd = FindWidthAtIndex(str, indEnd-ind); 
00613             InvertBlock(mLeftMargin+mDocX, y, xEnd+mDocX, yEnd);
00614         }
00615         else
00616         {
00617             if (ind >= left && ind <= right)
00618             {
00619                 xEnd = FindWidthAtIndex(str, right-ind);
00620                 InvertBlock(mLeftMargin+mDocX, y, xEnd+mDocX, yEnd);
00621             }
00622             if (indEnd > left && indEnd <= right)
00623             {
00624                 xStart = FindWidthAtIndex(str, left-ind)+mDocX;
00625                 xEnd = FindWidthAtIndex(str, indEnd-ind)+mDocX; 
00626                 InvertBlock(xStart, y, xEnd, yEnd);
00627             }
00628             if (ind < left && indEnd > right)
00629             {
00630                 xStart = FindWidthAtIndex(str, left-ind)+mDocX;
00631                 xEnd = FindWidthAtIndex(str, right-ind)+mDocX;
00632                 InvertBlock(xStart, y, xEnd, yEnd);
00633             }
00634         }
00635     }
00636 
00637     void PrintBuf(int x, int y, const char* buf)
00638     {
00639         int col = GetForeground();
00640         if (!mTextShadowed)
00641             oglSys.PosColPrintf(mOglWnd, x, y, col, "%s", buf);
00642         else
00643             oglSys.ShadowPrintf(mOglWnd, x, y, mShadowColor, col, "%s", buf);
00644     }
00645 
00646     void DrawTabbedLine(int x, int y, const char* buf)
00647     {
00648         string  str = buf;
00649 
00650         if (str.find_first_of("\t") == string::npos)
00651             return PrintBuf(x, y, buf);
00652 
00653         string  tabStr;
00654         int     tabPos, tabInd = 0;
00655         int     totWidth = 0, tabCnt = 0;
00656         int     w, h;
00657         int     tabWidth;
00658         void*   font;
00659 
00660         FindOglFont(mOglWnd, &font, NULL);
00661         oglSys.AbstFontTextSize(mOglWnd, font, "    ", &tabWidth, &h);
00662 
00663         while ((tabPos = str.find_first_of("\t", tabInd)) != string::npos)
00664         {
00665             tabStr = str.substr(tabInd, tabPos-tabInd);
00666             PrintBuf(x + totWidth, y, tabStr.c_str());
00667 
00668             oglSys.AbstFontTextSize(mOglWnd, font, tabStr.c_str(), &w, &h);
00669             tabCnt = (totWidth + w) / tabWidth + 1;
00670             totWidth = tabCnt * tabWidth;
00671             tabInd = tabPos+1;
00672         }
00673         if (tabInd < str.length())
00674         {
00675             tabStr = str.substr(tabInd, str.length()-tabInd);
00676             PrintBuf(x + totWidth, y, tabStr.c_str());
00677         }
00678     }
00679 
00680     void DrawText()
00681     {
00682         int    yPos = H();
00683         int    ind = 0;
00684 
00685         if ((ind = FindFirstVisibleLine(yPos)) > mText.length())
00686             return;
00687 
00688         string  line;
00689         char    buf[2048];
00690         int     nChar;
00691 
00692         while (yPos >= -mLineH && (nChar = GetLineAtIndex(&line, ind))!=-1)
00693         {
00694             int  bufInd = 0;
00695             int  xOff = mLeftMargin + mDocX;
00696             bool doShow = true;
00697 
00698             strncpy(buf, line.c_str(), 2047);
00699             buf[2047] ='\0';
00700 
00701             if (mDocX < 0)
00702             {
00703                 bufInd = FindIndexAtWidth(&line, -mDocX);
00704                 if ((xOff = FindWidthAtIndex(&line, bufInd) + mDocX) < 0)
00705                     doShow = false;
00706             }
00707             if (doShow) // RvB added 2 to allow for smaller single line height
00708                 DrawTabbedLine(xOff, yPos+2, buf + bufInd);
00709 
00710             if (mMark != mCaret) // RvB: changed -4 into -2 for smaller line heights
00711                 HandleInvertLineSelection(&line, ind, ind+nChar+1, yPos-2);
00712             ind += nChar+1;
00713             yPos -= mLineH;
00714         }
00715         if (GetOGLWND() == oglFocusWnd) {
00716             SetSolidLineColor(mCaretColor);
00717         } else {
00718             SetSolidLineColor(mShadowColor);
00719         }
00720         // RvB used to draw -4 changed to -2 to allow for smaller line height
00721         DrawLine(mCaretX, mCaretY-2, mCaretX, mCaretY-2+mLineH);
00722     }
00723 
00724     void MoveToCaret()
00725     {
00726         int minY = mHorizontalScrollBar ? mHorizontalScrollBar->H() : 0;
00727         int maxW = W() - (mVerticalScrollBar ? mVerticalScrollBar->W() : 0);
00728 
00729         if (mCaretY < minY)
00730         {
00731             mDocY -= (mCaretY-minY)-6;
00732             mCaretY = minY + 6;
00733         }
00734         if (mCaretY > H() - mLineH)
00735         {
00736             mDocY -= mCaretY - (H() - mLineH);
00737             mCaretY = H() - mLineH;
00738         }
00739         if (mCaretX < 0)
00740         {
00741             mDocX -= mCaretX-mLeftMargin;;
00742             mCaretX = mLeftMargin;
00743         }
00744         if (mCaretX > maxW - 8)
00745         {
00746             mDocX -= mCaretX - (maxW-8);
00747         }
00748     }
00749 
00750     void HandleMoveKey(int c, int state)
00751     {
00752         bool    shift   = (state & oglShift) ? true : false;
00753         bool    control = (state & oglControl) ? true : false;
00754         string  str;
00755 
00756         if (c==oglUP || c==oglDOWN || c==oglPAGEUP || c==oglPAGEDOWN)
00757         {
00758             int     lineInd = FindLineAtY(mCaretY, mCaretY);
00759             int     dY;
00760 
00761             if (mUpDownPos == -1)
00762                 mUpDownPos = mCaret - lineInd;
00763 
00764             if (c==oglUP || c==oglDOWN)
00765                 dY = (c==oglUP ? mLineH : -mLineH);
00766             else
00767                 dY = (c==oglPAGEUP ? H()-2*mLineH : -H()+2*mLineH);
00768 
00769             lineInd = FindLineAtY(mCaretY + dY, mCaretY);
00770             if (c==oglPAGEUP || c==oglPAGEDOWN)
00771             {
00772                 int oldCaretY = mCaretY;
00773                 ComputeCaretPosition();
00774                 mDocY += mCaretY - oldCaretY;
00775                 ClampDocY();
00776             }
00777             GetLineAtIndex(&str, lineInd);
00778             int sLen = str.length();
00779             mCaret = lineInd + ((sLen > mUpDownPos) ? mUpDownPos : sLen);
00780         }
00781         else
00782         {
00783             mUpDownPos = -1;
00784             if (c==oglLEFT || c==oglRIGHT)
00785                 if ((mCaret += (c==oglLEFT) ? -1 : 1) < 0)
00786                     mCaret = 0;
00787 
00788             if (c==oglHOME && control)
00789                 mCaret = 0;
00790             else if(c == oglHOME)
00791                 mCaret = FindLineAtY(mCaretY, mCaretY);
00792 
00793             if (c==oglEND && control)
00794                 mCaret = mText.size();
00795             else if (c==oglEND)
00796             {
00797                 int lineInd = FindLineAtY(mCaretY, mCaretY);
00798                 GetLineAtIndex(&str, lineInd);
00799                 mCaret = lineInd + str.length();
00800             }
00801         }
00802 
00803         if (mCaret > mText.length())
00804             mCaret = mText.length();
00805 
00806         if (!shift)
00807             mMark = mCaret;
00808 
00809         ComputeCaretPosition();
00810     }
00811 
00812     void DoDeleteSelection()
00813     {
00814         int left,right;
00815         GetSelectionLeftRight(left, right);
00816         //mText = mText.erase(left, right - left);
00817 mText.erase(left, right - left);
00818         mCaret = mMark = left;
00819     }
00820 
00821     void InsertKey(int c)
00822     {
00823         UndoableInsertKey(c);
00824         if (mCaret != mMark)
00825             DoDeleteSelection();
00826         mText.insert(mCaret, 1, c);
00827         mCaret++;
00828         mMark = mCaret;
00829         ComputeCaretPosition();
00830         PublishChange();
00831     }
00832 
00833     void InsertString(string str)
00834     {
00835         UndoableInsertString(str);
00836         if (mCaret != mMark)
00837             DoDeleteSelection();
00838         mText.insert(mCaret, str);
00839         mMark = mCaret += str.length();
00840         ComputeCaretPosition();
00841         PublishChange();
00842     }
00843 
00844     void DeleteSelection()
00845     {
00846         bool changed = mCaret != mMark;
00847         UndoableInsertKey(0);
00848         DoDeleteSelection();
00849         if (changed)
00850             PublishChange();
00851     }
00852 
00853     void BackSpace()
00854     {
00855         bool changed = mCaret != mMark;
00856 
00857         if (mCaret != mMark)
00858             DeleteSelection();
00859         else if (mCaret > 0)
00860         {
00861             changed = true;
00862             UndoableDeleteKey(-1);
00863             mMark = --mCaret;
00864             //mText = mText.erase(mCaret, 1);
00865 mText.erase(mCaret, 1);
00866         }
00867         ComputeCaretPosition();
00868         if (changed)
00869             PublishChange();
00870     }
00871 
00872     void DeleteKey()
00873     {
00874         bool changed = mCaret != mMark;
00875         if (mCaret != mMark)
00876             DeleteSelection();
00877         else if (mCaret < mText.size())
00878         {
00879             changed = true;
00880             UndoableDeleteKey(1);
00881             //mText = mText.erase(mCaret, 1);
00882 mText.erase(mCaret, 1);
00883         }
00884         ComputeCaretPosition();
00885         if (changed)
00886             PublishChange();
00887     }
00888 
00889     void Paste()
00890     {
00891         if (mClipboardString.empty())
00892             return;
00893         if (mSingleLine)
00894         {
00895             string str;
00896             int pos = mClipboardString.find_first_of("\n", 0);
00897             if (pos == string::npos)
00898                 pos = mClipboardString.length();
00899             str = mClipboardString.substr(0, pos);
00900             InsertString(str);
00901         }
00902         else
00903             InsertString(mClipboardString);
00904         PublishChange();
00905     }
00906 
00907     void Copy()
00908     {
00909         if (mCaret == mMark)
00910             return;
00911 
00912         int left,right;
00913         GetSelectionLeftRight(left, right);
00914         mClipboardString = mText.substr(left, right - left);
00915     }
00916 
00917     void Cut()
00918     {
00919         bool changed = mCaret != mMark;
00920         Copy();
00921         DeleteSelection();
00922         if (changed)
00923             PublishChange();
00924     }
00925 
00926     void StartScrollClipping()
00927     {
00928         int x = 0, y = 0, w = W(), h = H();
00929         if (mHorizontalScrollBar)
00930         {
00931             y = mHorizontalScrollBar->H();
00932             h -= mHorizontalScrollBar->H();
00933         }
00934         if (mVerticalScrollBar)
00935             w -= mVerticalScrollBar->W();
00936         oglSys.StartScissor(mOglWnd, x, y, w, h);
00937 
00938     }
00939 
00940     void EndScrollClipping()
00941     {
00942         oglSys.EndScissor();
00943     }
00944 
00945     virtual void OnScroll(ScrollBar *src, int position, void* userData)
00946     {
00947         if (src == mHorizontalScrollBar)
00948             mDocX = -position;
00949         if (src == mVerticalScrollBar)
00950             mDocY = -mDocH + H() + position;
00951         ComputeCaretPosition();
00952     }
00953 
00954     void HandleScrollBarsOnDisplay()
00955     {
00956         if (mVerticalScrollBar)
00957         {
00958             int extra = mHorizontalScrollBar ? mHorizontalScrollBar->H() : 0;
00959             mVerticalScrollBar->SetRange(mDocH+4 + extra, H() - extra - mLineH);
00960             int nPos = mDocH - H() + mDocY;
00961             mVerticalScrollBar->SetNewPos(nPos);
00962         }
00963 
00964         if (mHorizontalScrollBar)
00965         {
00966             mHorizontalScrollBar->SetRange(mDocW, W()-20);
00967             mHorizontalScrollBar->SetNewPos(-mDocX);
00968         }
00969 
00970         if (mPropagateScrollingY && RepeatTime())
00971         {
00972             mDocY += mPropagateScrollingY;
00973             ClampDocY();
00974             MouseFunc(oglMouseMove, 0, oglLeftButton, mLastMouseX, mLastMouseY);
00975         }
00976 
00977         if (mPropagateScrollingX && RepeatTime())
00978         {
00979             mDocX += mPropagateScrollingX;
00980             ClampDocX();
00981             MouseFunc(oglMouseMove, 0, oglLeftButton, mLastMouseX, mLastMouseY);
00982         }
00983     }
00984 
00985     virtual void InitFunc()
00986     {
00987         Window::InitFunc();
00988         mInitialized = true;
00989     }
00990 
00991     virtual void ExitFunc()
00992     {
00993         EmptyChangeInfoDeque(undoDeque);
00994         EmptyChangeInfoDeque(redoDeque);
00995         Window::ExitFunc();
00996     }
00997 
00998     virtual void InitDisplayFunc()
00999     {
01000         if (mClipBackground && (mHorizontalScrollBar || mVerticalScrollBar))
01001             StartScrollClipping();
01002         Window::InitDisplayFunc();
01003     }
01004 
01005     virtual void DisplayFunc()
01006     {
01007         Window::DisplayFunc();
01008 
01009         HandleScrollBarsOnDisplay();
01010  
01011         if (!mClipBackground && (mHorizontalScrollBar || mVerticalScrollBar))
01012             StartScrollClipping();
01013 
01014         OGC oldOGC;
01015         OGCSave(&oldOGC);
01016         DrawText();
01017         OGCRestore(&oldOGC);
01018         ComputeCaretPosition();
01019 
01020         if (mHorizontalScrollBar || mVerticalScrollBar)
01021             EndScrollClipping();
01022     }
01023 
01024     virtual void MouseFunc(int msg, int btn, int state, int x, int y)
01025     {
01026         if (msg == oglMouseDown && btn == oglLeftButton && !(state&oglControl))
01027         {
01028             string  str;
01029             int     lineInd = FindLineAtY(y, mCaretY);
01030 
01031             GetLineAtIndex(&str, lineInd);
01032             mCaret = lineInd + FindInsertionIndexAtWidth(&str, -mDocX+x);
01033             if (!(state & oglShift))
01034                 mMark = mCaret;
01035 
01036             StartRepeatTime();
01037             oglSys.SetAlwaysDraw(mOglWnd, 1);
01038             mLastMouseX = x;
01039             mLastMouseY = y;
01040             mUpDownPos = mCaret - lineInd;
01041         }
01042         if (msg == oglMouseMove && (state & oglLeftButton))
01043         {
01044             string  str;
01045             int     lineInd = FindLineAtY(y, mCaretY);
01046 
01047             GetLineAtIndex(&str, lineInd);
01048             mCaret = lineInd + FindInsertionIndexAtWidth(&str, -mDocX+x);
01049 
01050             mPropagateScrollingX = mPropagateScrollingY = 0;
01051 
01052             int minY = mHorizontalScrollBar ? mHorizontalScrollBar->H() : 0;
01053             if (y < minY)
01054                 mPropagateScrollingY = 4 - (y-minY)/2;
01055             else if(y > H())
01056                 mPropagateScrollingY = -4 - (y - H())/2;
01057 
01058             int maxW = W() - (mVerticalScrollBar ? mVerticalScrollBar->W() : 0); 
01059             if (x < 0)
01060                 mPropagateScrollingX = 4 - x/2;
01061             else if(x > maxW)
01062                 mPropagateScrollingX = -4 - (x - maxW)/2;
01063 
01064             mLastMouseX = x;
01065             mLastMouseY = y;
01066             mUpDownPos = mCaret - lineInd;
01067         }
01068 
01069         if (msg == oglMouseUp && btn == oglLeftButton)
01070         {
01071             mPropagateScrollingY = mPropagateScrollingX = 0;
01072             oglSys.SetAlwaysDraw(mOglWnd, 0);
01073         }
01074 
01075         if (msg == oglMouseWheelUp || msg == oglMouseWheelDown)
01076         {
01077             mDocY += (msg == oglMouseWheelUp ? -mLineH : mLineH);
01078             ClampDocY();
01079         }
01080 
01081         ComputeCaretPosition();
01082         Window::MouseFunc(msg, btn, state, x, y);
01083     }
01084 
01085     virtual void KeyboardFunc(int c, int state)
01086     {
01087         bool shift = (state & oglShift) ? true : false;
01088         int  oldDocH = mDocH;
01089 
01090         Window::KeyboardFunc(c, state);
01091 
01092         if (c == oglUP     || c == oglDOWN ||
01093             c == oglLEFT   || c == oglRIGHT ||
01094             c == oglPAGEUP || c == oglPAGEDOWN ||
01095             c == oglHOME   || c == oglEND)
01096         {
01097             HandleMoveKey(c, state);
01098         }
01099         if (c == oglCTRL('c'))
01100             Copy();
01101 
01102         if (mEditable)
01103         {
01104             if (c == oglCTRL('z'))
01105                 UndoAction();
01106             if (c == oglCTRL('y'))
01107                 RedoAction();
01108 
01109             if (c == oglCTRL('x'))
01110                 Cut();
01111             if (c == oglCTRL('v'))
01112                 Paste();
01113 
01114             if( c == '\r' )
01115                 c = '\n';
01116 
01117             if( c == 8 )
01118                 BackSpace();
01119             if (c == oglDELETE)
01120                 DeleteKey();
01121             if (c == '\n' || c == '\t' || c == ' ' || isalnum(c) || ispunct(c))
01122                 if (!(mSingleLine && c == '\n'))
01123                     InsertKey(c);
01124 
01125             mDocY -= ComputeDocHeight() - oldDocH;
01126         }
01127 
01128         MoveToCaret();
01129     }
01130 
01131 
01132     virtual void ReshapeFunc(int w, int h)
01133     {
01134         Window::ReshapeFunc(w,h);
01135 
01136         if (!mInitialized)
01137             return;
01138 
01139         ComputeDocHeight();
01140 
01141         // Anchor text at upper left corner
01142         mDocY += (h - mOldH);
01143         mOldH = h;
01144 
01145         ClampDocY();
01146         ComputeCaretPosition();
01147     }
01148 
01149 protected:
01150 
01151     void Init(strconst text, int w, int h, int sB)
01152     {
01153         SetBorderType( BEV_RIDGE );
01154         mListener = 0;
01155         mHorizontalScrollBar = mVerticalScrollBar = 0;
01156 
01157         // Used to be true, but I do not know why
01158         // mClipBackground = true;
01159         mClipBackground = false;
01160 
01161         mInitialized = false;
01162         mEditable = true;
01163         mSingleLine = false;
01164  
01165         //mDocX = 0;
01166         mDocW = 800;
01167         mOldH = h;
01168         mLeftMargin = 8;
01169 
01170         mMark = 0;
01171         mCaret = 0;
01172         mCaretY = h - mLineH;
01173         mCaretX = mLeftMargin;
01174         mCaretColor = oglLIGHTRED;
01175 
01176         mTextShadowed = false;
01177         mShadowColor = oglLIGHTGREY;
01178         mLineH = 16;
01179 
01180         SetText(text);
01181 
01182 
01183         if (sB & 1)
01184         {
01185             mHorizontalScrollBar = new WindowScrollBar(this, true, 1, 16,
01186                                                        (sB&2)?16:0);
01187             mHorizontalScrollBar->SetLineIncrement(mLineH);
01188             mHorizontalScrollBar->SetScrollBarListener(this);
01189             mHorizontalScrollBar->MapKeysTo(this);
01190         }
01191         if (sB & 2)
01192         {
01193             mVerticalScrollBar = new WindowScrollBar(this, false, 1, 16,
01194                                                      (sB&1)?16:0);
01195             mVerticalScrollBar->SetLineIncrement(mLineH);
01196             mVerticalScrollBar->SetScrollBarListener(this);
01197             mVerticalScrollBar->MapKeysTo(this);
01198         }
01199 
01200         mUpDownPos = -1;
01201 
01202         mPropagateScrollingY = 0;
01203         mPropagateScrollingX = 0;
01204         mLastMouseX = 0;
01205 
01206         SetDisableGlobalKeyListener( true );
01207         SetDisableOGLViewKeys( true );
01208         SetDisableOGLViewMouse( true );
01209 
01210         SetBackground(oglWHITE);
01211     }
01212 
01213     std::deque<ChangeInfo*> undoDeque;
01214     std::deque<ChangeInfo*> redoDeque;
01215 
01216     WindowScrollBar*    mHorizontalScrollBar;
01217     WindowScrollBar*    mVerticalScrollBar;
01218     bool                mClipBackground;
01219 
01220     string      mText;
01221     int         mLineH;
01222 
01223     bool        mInitialized;
01224     bool        mEditable;
01225     bool        mSingleLine;
01226 
01227     int         mMark;
01228     int         mCaret;
01229     int         mCaretX;
01230     int         mCaretY;
01231     ULONG       mCaretColor;
01232 
01233     int         mLeftMargin;
01234     
01235     int         mOldH;
01236     int         mUpDownPos;
01237 
01238     bool        mTextShadowed;
01239     ULONG       mShadowColor;
01240 
01241     int         mPropagateScrollingY;
01242     int         mPropagateScrollingX;
01243 
01244     int         mLastMouseX;
01245     int         mLastMouseY;
01246 
01247 
01248     TextEditListener* mListener;
01249     void*             mListenerData;
01250 };
01251 
01252 } // namespace oglGui
01253 #endif

Generated on Fri Mar 19 09:31:39 2010 for ImpalaSrc by  doxygen 1.5.1