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
[ Top ] |