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

Text.cpp

Go to the documentation of this file.
00001 
00002 // MathCore = a WYSIWYG equation editor + a powerful math engine     //
00003 // Copyright (C) 2003 by Francesco Montorsi                          //
00004 //                                                                   //
00005 // This library is free software; you can redistribute it and/or     //
00006 // modify it under the terms of the GNU Lesser General Public        //
00007 // License as published by the Free Software Foundation; either      //
00008 // version 2.1 of the License, or (at your option) any later         //
00009 // version.                                                          //
00010 //                                                                   //
00011 // This library is distributed in the hope that it will be useful,   //
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of    //
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the      //
00014 // GNU Lesser General Public License for more details.               //
00015 //                                                                   //
00016 // You should have received a copy of the GNU Lesser General Public  //
00017 // License along with this program; if not, write to the Free        //
00018 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,   //
00019 // MA 02111-1307, USA.                                               //
00020 //                                                                   //
00021 // For any comment, suggestion or feature request, please contact    //
00022 // the administrator of the project at frm@users.sourceforge.net     //
00023 //                                                                   //
00031 
00032 
00033 
00034 
00035 // optimization for GCC compiler
00036 #ifdef __GNUG__
00037 #pragma implementation "Text.h"
00038 #endif
00039 
00040 // includes
00041 #include "mc/mcprec.h"
00042 #ifdef __BORLANDC__
00043     #pragma hdrstop
00044 #endif
00045 
00046 #ifndef mcPRECOMP
00047     #include <wx/dcscreen.h>
00048  #include "mc/MathCore.h"
00049  #include "mc/Text.h"
00050 #endif
00051 
00052 
00053 mcIMPLEMENT_MAIN_CLASS(mcText, mcDecoration);
00054 
00055 
00056 // setup statics
00057 mcText *mcTextHelpers::smath_pEmpty = NULL;
00058 
00059 
00060 
00061 
00062 
00063 // ----------------------------------------
00064 // mcTEXTDATA
00065 // ----------------------------------------
00066 
00067 void mcTextHelpers::data_DeepCopy(const mcElementHelpers *p)
00068 {
00069  const mcTextHelpers *e = (const mcTextHelpers *)p;
00070  
00071  mdata_arrStr = e->mdata_arrStr;
00072  mdata_bMultiline = e->mdata_bMultiline;
00073  mdata_strFilter = e->mdata_strFilter;
00074 
00075  // deep copy the GUI section
00076  mgui_nCursorPos = e->mgui_nCursorPos;
00077  mgui_nRowPos = e->mgui_nRowPos;
00078  mgui_bDrawEmptyBoxIfEmpty = e->mgui_bDrawEmptyBoxIfEmpty;
00079 
00080  // create an empty box, if required
00081  if (e->mgui_pEmptyBox)
00082   mgui_pEmptyBox = new mcEmptyBox();
00083  else
00084   mcSAFE_DELETE(mgui_pEmptyBox);
00085 }
00086 
00087 void mcTextHelpers::data_SetText(const wxString &str)
00088 {
00089  wxString mystr(str);
00090 
00091  if (mystr.Freq(wxT('\n')) > 0) {
00092 
00093   mcASSERT(mdata_bMultiline == TRUE,
00094    wxT("Cannot set text with \\n in a single line element"));
00095 
00096   // if the given text contains various lines, break it into
00097   // several wxStrings
00098   for (int i=0, m=str.Freq(wxT('\n')); i < m; i++) {
00099    mdata_arrStr.Add(str.Left(mystr.Index(wxT('\n'))));
00100    mystr = mystr.Right(mystr.Len()-mystr.Index(wxT('\n')));
00101   }
00102 
00103  } else {
00104 
00105   // do a simple copy
00106   mdata_arrStr.Clear();
00107   mdata_arrStr.Add(mystr);
00108  }
00109 
00110  if (mcMathCore::Get()->isGUIEnabled())
00111   gui_SetCursorPos(mcCP_END);
00112 }
00113 
00114 
00115 
00116 
00117 
00118 // ----------------------------------------
00119 // mcTEXTGUI
00120 // ----------------------------------------
00121 
00122 void mcTextHelpers::gui_Init()
00123 {
00124  mgui_bDrawEmptyBoxIfEmpty = TRUE;
00125  mgui_nCursorPos = mgui_nRowPos = 0;
00126 
00127  // create the empty box
00128  mgui_pEmptyBox = new mcEmptyBox();
00129  mcDecorationHelpers::gui_Init();
00130 }
00131 
00132 mcInputRes mcTextHelpers::gui_Input(const mcKey &key, mcElement *pnew)
00133 {
00134  // handle DELETE key
00135  if (mcMathCore::Get()->m_pDeleteKey->MatchKey(key)) {
00136 
00137   if (mgui_nCursorPos > 0) {
00138 
00139    // remove the character before the focused one
00140    mdata_arrStr[mgui_nRowPos] =
00141     mdata_arrStr[mgui_nRowPos].Left(mgui_nCursorPos-1) +
00142     mdata_arrStr[mgui_nRowPos].Right(
00143      mdata_arrStr[mgui_nRowPos].Len()-mgui_nCursorPos);
00144    mgui_nCursorPos--;
00145 
00146    if (mgui_nCursorPos == 0 && mdata_arrStr[mgui_nRowPos].IsEmpty())
00147     mdata_arrStr.Remove(mgui_nRowPos);
00148 
00149    if (data_isArrayEmpty())
00150     return mcIR_DELETE_THIS;
00151 
00152   } else if (mgui_nRowPos > 0) {
00153 
00154    // if we are here, cursor should be placed at the beginning
00155    // of the focused line
00156    mcASSERT(mgui_nCursorPos == 0, wxT("something wrong"));
00157    mdata_arrStr.Remove(mgui_nRowPos);
00158    mgui_nRowPos--;
00159    gui_SetCursorPos(mcCP_END);
00160 
00161   } else {
00162 
00163    if (data_isArrayEmpty())
00164     return mcIR_DELETE_THIS;
00165 
00166    mdata_arrStr.Empty();
00167   }
00168 
00169   return mcIR_OKAY;
00170  }
00171 
00172  // handle CANCEL key
00173  if (mcMathCore::Get()->m_pCancelKey->MatchKey(key)) {
00174 
00175   if (mgui_nCursorPos == (int)mdata_arrStr[mgui_nRowPos].Len()) {
00176 
00177    if (mgui_nRowPos < data_GetRowCount()-1) {
00178 
00179     // merge the following line with the current one
00180     mdata_arrStr[mgui_nRowPos] += mdata_arrStr[mgui_nRowPos+1];
00181     mdata_arrStr.Remove(mgui_nRowPos+1);
00182 
00183    } else {
00184 
00185     // nothing to delete on the right of the cursor
00186     return mcIR_DELETE_NEXT;
00187    }
00188   }
00189 
00190   if (data_isArrayEmpty())
00191    return mcIR_DELETE_THIS;
00192 
00193   mdata_arrStr[mgui_nRowPos] =
00194    mdata_arrStr[mgui_nRowPos].Left(mgui_nCursorPos) +
00195    mdata_arrStr[mgui_nRowPos].Right(
00196    mdata_arrStr[mgui_nRowPos].Len()-mgui_nCursorPos-1);
00197 
00198   return mcIR_OKAY;
00199  }
00200 
00201  // handle the RETURN key
00202  if (mcMathCore::Get()->m_pNewLineKey->MatchKey(key)) {
00203 
00204   if (mdata_bMultiline) {
00205 
00206    // create a new line only if this is a multiline element
00207    mdata_arrStr.Add(wxT(""));
00208    mgui_nRowPos++;
00209    mgui_nCursorPos = 0;
00210 
00211   } else {
00212 
00213    // sorry, not in multi-line mode
00214    mcMathCore::Get()->SyntaxError(wxT("Cannot create a new line here"));
00215   }
00216 
00217   return mcIR_OKAY;
00218  }
00219 
00220 
00221  // discard all invalid inputs
00222  if (data_isToReject((wxChar)key.GetKeyCode())) {
00223 
00224   mcMathCore::Get()->SyntaxError(wxT("Cannot accept this input here"));
00225   return mcIR_OKAY;
00226  }
00227 
00228  // reset everything
00229  if (data_isArrayEmpty()) {
00230   mdata_arrStr.Add(wxT(""));
00231   mgui_nRowPos = mgui_nCursorPos = 0;
00232  }
00233 
00234  // handle all other keys
00235  // insert char and advance cursor
00236  wxString &str = mdata_arrStr.Item(mgui_nRowPos);
00237 
00238  str = str.Left(mgui_nCursorPos) + wxString((wxChar)key.GetKeyCode(), 1) +
00239    str.Right(str.Len()-mgui_nCursorPos);
00240  mgui_nCursorPos++;
00241 
00242  return mcIR_OKAY;
00243 }
00244 
00245 mcMoveCursorRes mcTextHelpers::gui_MoveCursor(mcMoveCursorFlag flag, long modifiers)
00246 {
00247  if (data_isArrayEmpty() && mgui_bDrawEmptyBoxIfEmpty)
00248   return mgui_pEmptyBox->hlp()->gui_MoveCursor(flag, modifiers);
00249 
00250  switch (flag) {
00251  case mcMCF_LEFT:
00252   if (mgui_nCursorPos > 0)
00253    mgui_nCursorPos--;
00254   else
00255    return mcMCR_SETFOCUS_PREVIOUS;
00256   break;
00257 
00258  case mcMCF_RIGHT:
00259   if (mgui_nCursorPos < (int)mdata_arrStr[mgui_nRowPos].Len())
00260    mgui_nCursorPos++;
00261   else
00262    return mcMCR_SETFOCUS_NEXT;
00263   break;
00264 
00265  case mcMCF_UP:
00266   if (mgui_nRowPos > 0) {
00267    mgui_nRowPos--;
00268 
00269    // set the cursor at the end of the line if necessary
00270    mgui_nCursorPos = (mgui_nCursorPos > (int)mdata_arrStr[mgui_nRowPos].Len()) ?
00271     mdata_arrStr[mgui_nRowPos].Len() : mgui_nCursorPos;
00272   } else
00273    return mcMCR_SETFOCUS_ABOVE;
00274   break;
00275 
00276  case mcMCF_DOWN:
00277   if (mgui_nRowPos < data_GetRowCount()-1) {
00278    mgui_nRowPos++;
00279 
00280    // set the cursor at the end of the line if necessary
00281    mgui_nCursorPos = (mgui_nCursorPos > (int)mdata_arrStr[mgui_nRowPos].Len()) ?
00282     mdata_arrStr[mgui_nRowPos].Len() : mgui_nCursorPos;
00283   } else
00284    return mcMCR_SETFOCUS_BELOW;
00285   break;
00286  }
00287 
00288  return mcMCR_OKAY;
00289 }
00290 
00291 int mcTextHelpers::gui_MoveCursorUsingPoint(wxDC &dc, const wxPoint &p)
00292 {
00293  if (data_isArrayEmpty() && mgui_bDrawEmptyBoxIfEmpty) {
00294   mgui_nCursorPos = 0;
00295     mgui_nRowPos = 0; 
00296   return mcMCR_OKAY; // we are an empty box...
00297  }
00298 
00299  // draw the text using the correct style and alignment
00300  gui_SelectStyle(dc);
00301  
00302  int h, w, y = 0;
00303  for (int i=0; i < data_GetRowCount(); y+=h, i++) {
00304   h = gui_GetRowHeight(&dc, i);
00305   w = gui_GetRowWidth(&dc, i);
00306   if (p.x >= 0 && p.x <= w &&
00307    p.y >= y && p.y <= y+h) {
00308    
00309    // get the approximated width of each char
00310    int dx = w/mdata_arrStr[i].Len();
00311    
00312    // this line contains the given point
00313    mgui_nCursorPos = p.x/dx;
00314    mgui_nRowPos = i;
00315    
00316    return mcMCR_OKAY;
00317      }
00318  }
00319 
00320  // we could not find a row containing the given point...
00321  return mcMCR_CANNOT_SETFOCUS;
00322 }
00323 
00324 int mcTextHelpers::gui_Draw(wxDC &dc, int x, int y, long flags, int w, wxColour *col) const
00325 {
00326  if (data_isArrayEmpty() && mgui_bDrawEmptyBoxIfEmpty) {
00327 
00328   // draw an empty box...
00329   mgui_pEmptyBox->hlp()->gui_Draw(dc, x, y, mcDRW_NONACTIVE, wxDefaultPosition);
00330   return data_GetID();
00331  }
00332 
00333  // draw the text using the correct style and alignment
00334  gui_SelectStyle(dc);
00335  if (col) dc.SetTextForeground(*col);  // override color if requires
00336 
00337  for (int i=0; i < data_GetRowCount(); y+=gui_GetRowHeight(&dc, i), i++)
00338   dc.DrawText(mdata_arrStr[i], x, y);
00339 
00340  // return our ID
00341  return data_GetID();
00342 }
00343 
00344 int mcTextHelpers::gui_GetRelCursorPos(wxDC &dc, wxPoint *pt) const
00345 {
00346  if (data_isArrayEmpty() && mgui_bDrawEmptyBoxIfEmpty) {
00347 
00348   // draw an empty box...
00349   return mgui_pEmptyBox->hlp()->gui_GetRelCursorPos(dc, pt);
00350  }
00351 
00352  if (mdata_arrStr.IsEmpty())
00353   return 0;
00354 
00355  // to correctly retrieve string sizes...
00356  gui_SelectStyle(dc);
00357 
00358  pt->x = gui_GetWidthOf(&dc,
00359   mdata_arrStr[mgui_nRowPos].Left(mgui_nCursorPos));
00360  pt->y = 0;
00361 
00362  // add y offset for preceding lines
00363  for (int i=0; i < mgui_nRowPos; i++)
00364   pt->y += gui_GetRowHeight(&dc, i);
00365 
00366  // return the height of the string or the height of a simple
00367  // char if the string is empty
00368  return gui_GetRowHeight(&dc, mgui_nRowPos);
00369 }
00370 
00371 void mcTextHelpers::gui_DoRecalcSize()
00372 {
00373  int h=0;
00374  wxScreenDC dc;
00375 
00376  if (data_isArrayEmpty() && mgui_bDrawEmptyBoxIfEmpty) {
00377 
00378   // use as this object's size the size of an empty box...
00379   mgui_pEmptyBox->hlp()->gui_RecalcSize();
00380   mgui_sz = mgui_pEmptyBox->hlp()->gui_GetSize();
00381   return;
00382  }
00383 
00384  // to correctly retrieve string sizes...
00385  gui_SelectStyle(dc);
00386  for (int i=0; i < data_GetRowCount(); i++)
00387   h += gui_GetRowHeight(&dc, i);
00388 
00389  mgui_sz = wxSize(gui_GetWidthOf(&dc, data_GetLongestStr()), h);
00390 }
00391 
00392 void mcTextHelpers::gui_SetCursorPos(const mcCursorPos &code)
00393 {
00394  if (code.isBegin()) {
00395 
00396   // place cursor at the left of first character
00397   mgui_nCursorPos = 0;
00398 
00399  } else if (code.isEnd()) {
00400 
00401   // place the cursor at the end of the text
00402   if (!data_isArrayEmpty())
00403    mgui_nCursorPos = mdata_arrStr[mgui_nRowPos].Len();
00404   else
00405    mgui_nCursorPos = 0;
00406 
00407  } else {
00408 
00409   mcASSERT(0, wxT("Cannot accept this flag"));
00410  }
00411 }
00412 
00413 void mcTextHelpers::gui_GetCursorPos(mcCursorPos &cp) const
00414 {
00415  if (mgui_nCursorPos == 0)
00416   cp.gui_Push(mcCP_BEGIN);
00417  else if (mgui_nCursorPos == (int)mdata_arrStr[mgui_nRowPos].Len() && 
00418          mgui_nRowPos == data_GetRowCount()-1)
00419   cp.gui_Push(mcCP_END);
00420  else 
00421   cp.gui_Push(mgui_nCursorPos);
00422 }
00423 
00424 void mcTextHelpers::gui_UpdateExpDepth()
00425 {
00426  if (mcMathCore::Get()->isGUIEnabled()) {
00427   mcElement *p = mgui_pEmptyBox;
00428   if (p) p->gui_SetAtSameLevelOf(this);
00429  }
00430  
00431  // base class version needs to be called
00432  mcElementHelpers::gui_UpdateExpDepth();
00433 }
00434 
00435 
00436 
00437 
00438 
00439 // ----------------------------------------
00440 // mcTEXTIO
00441 // ----------------------------------------
00442 
00443 wxXml2Node mcTextHelpers::io_GetMathML(bool bGetPresentation) const
00444 {
00445  // cannot export in MathML a multiline text object
00446  mcASSERT(!mdata_bMultiline, wxT("Cannot create a multiline MTEXT tag"));
00447 
00448  // just create an MTEXT string
00449  return wxXml2Node(wxXML_TEXT_NODE, wxXml2EmptyDoc, wxT("mtext"), mdata_arrStr[0]);
00450 }
00451 
00452 wxString mcTextHelpers::io_GetInlinedExpr() const
00453 {
00454  if (mdata_arrStr.IsEmpty()) return wxEmptyString;
00455 
00456  // export only first line...
00457  return mdata_arrStr[0];
00458 }
00459 
00460 bool mcTextHelpers::io_ImportPresentationMathML(wxXml2Node tag, wxString &pErr)
00461 {
00462  return TRUE;
00463 }
00464 
00465 bool mcTextHelpers::io_ImportInlinedExpr(const wxString &str, int *count, wxString &pErr)
00466 {
00467  // no problems...
00468  data_SetText(str);
00469  *count = str.Len();
00470 
00471  return TRUE;
00472 }
00473 
00474 
00475 
00476 // ----------------------------------------
00477 // mcTEXTMATH
00478 // ----------------------------------------
00479 
00480 bool mcTextHelpers::math_CompareThisOnly(const mcElement &p, long flags) const
00481 {
00482  if (!mcElementHelpers::math_CompareThisOnly(p, flags))
00483   return FALSE;
00484 
00485  // check text
00486  if (data_GetText() == mcText(p).hlp()->data_GetText())
00487   return TRUE;
00488  return FALSE;
00489 }
00490 
00491 


Documentation generated with Doxygen on Sun Feb 6 17:10:49 2005
Visit MathStudio home page for more info

[ Top ]