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 // optimization for GCC compiler 00035 #ifdef __GNUG__ 00036 #pragma implementation "ExpElement.cpp" 00037 #endif 00038 00039 // includes 00040 #include "mc/mcprec.h" 00041 #ifdef __BORLANDC__ 00042 #pragma hdrstop 00043 #endif 00044 00045 #ifndef mcPRECOMP 00046 //#include <math.h> 00047 #include "mc/ExpElement.h" 00048 #include "mc/Bracket.h" 00049 #include "mc/Number.h" 00050 #include "mc/Radical.h" 00051 #include "mc/Monomial.h" 00052 #endif 00053 00054 00055 mcIMPLEMENT_ABSTRACT_CLASS(mcExpElement, mcElement); 00056 00057 00058 // setup customizable variables 00059 bool mcExpElementHelpers::smath_bConvertToRadicalWhenPossible = FALSE; 00060 00061 00062 00063 00064 00065 // ---------------------------------------- 00066 // mcEXPELEMENT 00067 // ---------------------------------------- 00068 00069 #ifdef __MCDEBUG__ 00070 00071 wxString mcExpElementHelpers::data_Debug(long flags) const 00072 { 00073 wxString str = data_BaseDebug(flags); 00074 00075 // if an exponent is present, add also exponent debug info 00076 // to check if an exponent is present, don't use such a line: 00077 // if (this->data_hasProperty(mcEP_HASEXPONENT)) 00078 // because math functions work modifying the exp without adding 00079 // this flag (sometimes) 00080 if (data_GetExp() != NULL) 00081 str += data_ExpDebug(flags); 00082 00083 // do the same for the subscript 00084 if (this->data_hasProperty(mcEP_HASSUBSCRIPT)) 00085 str += data_SubDebug(flags); 00086 00087 // we don't need to add exp debug info 00088 return str; 00089 } 00090 00091 void mcExpElementHelpers::data_Check() const 00092 { 00093 // first basic checks 00094 mcElementHelpers::data_Check(); 00095 00096 // check if everything is okay with flags/variables 00097 mcASSERT((data_GetExp() != mcEmptyElement && data_hasProperty(mcEP_HASEXPONENT)) || 00098 (data_GetExp() == mcEmptyElement && !data_hasProperty(mcEP_HASEXPONENT)), 00099 wxT("The mcEP_HASEXPONENT flag is not synchronized with the exponent variable !")); 00100 00101 // do we have to check the exponent ? 00102 const mcElement &e = data_GetExp(); 00103 if (e == mcEmptyElement) return; 00104 00105 // check the exponent type 00106 // NOTE: since it's one of our children, it should have 00107 // been already data_Check()ed by mcElementHelpers::data_Check() 00108 mcASSERT(e.data_GetType() == mcET_POLYNOMIAL, 00109 wxT("mcExpElementMath can work only on mcPolynomials as exp")); 00110 } 00111 00112 #define mcEXPELEM_HEADER 0 00113 00114 wxString mcExpElementHelpers::data_ExpDebug(long flags) const 00115 { 00116 int step = mcMathCore::Get()->m_nIndentationStep; 00117 00118 // use the mcElement function data_GetDebug 00119 return wxString(wxT('*'), mcEXPELEM_HEADER) + wxT(" EXPONENT [\n") + 00120 data_GetExp().data_GetDebug(step, flags) + 00121 wxString(wxT('*'), mcEXPELEM_HEADER) + wxT(" EXPONENT ]"); 00122 } 00123 00124 wxString mcExpElementHelpers::data_SubDebug(long flags) const 00125 { 00126 int step = mcMathCore::Get()->m_nIndentationStep; 00127 00128 // use the mcElement function data_GetDebug 00129 return wxString(wxT('*'), mcEXPELEM_HEADER) + wxT(" SUBSCRIPT [\n") + 00130 data_GetSub().data_GetDebug(step, flags) + 00131 wxString(wxT('*'), mcEXPELEM_HEADER) + wxT(" SUBSCRIPT ]"); 00132 } 00133 00134 #endif // __MCDEBUG__ 00135 00136 00137 00138 00139 00140 // ---------------------------------------- 00141 // mcEXPELEMENTDATA 00142 // ---------------------------------------- 00143 00144 void mcExpElementHelpers::data_CreateExpSub(bool exp) 00145 { 00146 data_DestroyExpSub(exp); 00147 00148 if (exp) { 00149 00150 // by default, the exponent is a mcPolynomial 00151 mcASSERT(mdata_bExpEnabled, wxT("Exponent creation is disabled")); 00152 00153 if (!mdata_pExp.data_isOk()) 00154 mdata_pExp.data_SetRefData(new mcPolynomialHelpers()); 00155 else 00156 ((mcPolynomial &)mdata_pExp).data_DeleteAll(); 00157 00158 } else { 00159 00160 // by default, the subscript is a mcText 00161 mcASSERT(mdata_bSubEnabled, wxT("Subscript creation is disabled")); 00162 00163 if (!mdata_pSub.data_isOk()) 00164 mdata_pSub.data_SetRefData(new mcTextHelpers()); 00165 else 00166 ((mcText &)mdata_pSub).data_SetText(wxT("")); 00167 00168 } 00169 00170 // set the expdepth 00171 data_Get(exp).gui_SetAsExpOf(this); 00172 00173 // now we have an exponent... 00174 data_AddProperty(mcEP_HAS(exp)); 00175 mcLOG(wxT("mcExpElementHelpers::data_CreateExpSub [%s] - created the "), 00176 mcTXTTHIS, (exp ? wxT("exponent") : wxT("subscript"))); 00177 } 00178 00179 void mcExpElementHelpers::data_SetExpSub(bool exp, const mcElement &p) 00180 { 00181 // this call erases previous exp (if present) 00182 data_CreateExpSub(exp); 00183 00184 // now, weak copy the exponent 00185 data_Get(exp).data_DeepCopy(p); 00186 } 00187 00188 void mcExpElementHelpers::data_DestroyExpSub(bool exp) 00189 { 00190 data_RemoveProperty(mcEP_HAS(exp)); 00191 00192 if (exp) 00193 mdata_pExp = mcEmptyElement; 00194 else 00195 mdata_pSub = mcEmptyElement; 00196 00197 /* CANNOT UNCOMMENT THE FOLLOWING LINE: a call to a pure virtual function would 00198 result otherwise.... 00199 mcLOG(wxT("mcExpElementHelpers::data_DestroyExp [%s] - exponent removed"), mcTXTTHIS);*/ 00200 } 00201 00202 void mcExpElementHelpers::data_DeepCopyExpSub(bool exp, const mcExpElementHelpers *d) 00203 { 00204 if (d->data_Get(exp) != mcEmptyElement) { 00205 00206 // create & deep copy the sub/exp 00207 data_CreateExpSub(exp); 00208 data_Get(exp).data_DeepCopy(d->data_Get(exp)); 00209 00210 } else { 00211 00212 // or delete it in case it must be NULL 00213 data_DestroyExpSub(exp); 00214 } 00215 } 00216 00217 void mcExpElementHelpers::data_DeepCopy(const mcElementHelpers *p) 00218 { 00219 const mcExpElementHelpers *d = (const mcExpElementHelpers *)p; 00220 00221 // deep copy basic data 00222 mgui_bExpRight = d->mgui_bExpRight; 00223 mgui_bSubRight = d->mgui_bSubRight; 00224 mdata_bExpEnabled = d->mdata_bExpEnabled; 00225 mdata_bSubEnabled = d->mdata_bSubEnabled; 00226 00227 mgui_nCursorLoc = d->mgui_nCursorLoc; 00228 mgui_szBase = d->mgui_szBase; 00229 00230 // deep copy the exponent if present... 00231 data_DeepCopyExpSub(TRUE, d); 00232 data_DeepCopyExpSub(FALSE, d); 00233 } 00234 00235 00236 00237 00238 00239 00240 00241 // ---------------------------------------- 00242 // mcEXPELEMENTGUI 00243 // ---------------------------------------- 00244 /* 00245 void mcExpElementHelpers::gui_DeepCopy(const mcElementGUI *p) 00246 { 00247 mcExpElementGUI *d = (mcExpElementGUI *)p; 00248 00249 mgui_nCursorLoc = d->mgui_nCursorLoc; 00250 mgui_szBase = d->mgui_szBase; 00251 mcElementHelpers::sgui_DeepCopy(p); 00252 }*/ 00253 00254 void mcExpElementHelpers::gui_CreateExpSub(bool exp) 00255 { 00256 data_CreateExpSub(exp); 00257 00258 if (data_Get(exp).data_GetType() == mcET_POLYNOMIAL) 00259 ((mcPolynomial &)data_Get(exp)).gui_AddNewEmptyMonomial(); 00260 } 00261 00262 bool mcExpElementHelpers::gui_isEndKey(const mcKey &ev) const 00263 { 00264 if (gui_isCursorInExpSub(TRUE)) 00265 return gui_isExpSubEndKey(TRUE, ev); 00266 if (gui_isCursorInExpSub(FALSE)) 00267 return gui_isExpSubEndKey(FALSE, ev); 00268 00269 // the cursor is in the base... 00270 bool b = gui_isBaseEndKey(ev); 00271 00272 // check for exponent and subscript 00273 if (b == TRUE && gui_GetBaseCursorPos().isEnd() && gui_hasBaseSthOnRightSide()) 00274 return FALSE; 00275 if (b == TRUE && gui_GetBaseCursorPos().isBegin() && gui_hasBaseSthOnLeftSide()) 00276 return FALSE; 00277 00278 return b; 00279 } 00280 00281 void mcExpElementHelpers::gui_DoRecalcSize() 00282 { 00283 gui_DoRecalcBaseSize(); // this one must update mgui_szBase 00284 00285 // we must call this function specially if mdata_bExpEnabled or mdata_bSubEnabled 00286 // is FALSE: they update the exp/sub size to zero, in that case !!! 00287 gui_RecalcExpSubSize(TRUE); // this one must update data_GetExp().gui_mgui_sz 00288 gui_RecalcExpSubSize(FALSE); // this one must update data_m_txtSub.gui_mgui_sz 00289 00290 // if the exponent is disabled, gui_GetExpSize will return wxSize(0,0), so 00291 // everything works without problem; the same for the subscript 00292 int maxw = mcMAX(gui_GetExpSubOffsetx(TRUE)+gui_GetExpSubSize(TRUE).GetWidth(), 00293 gui_GetExpSubOffsetx(FALSE)+gui_GetExpSubSize(FALSE).GetWidth()); 00294 00295 // base offsety + base height 00296 int maxh = gui_GetBaseOffsety() + gui_GetBaseAndSubSize().GetHeight(); 00297 00298 // set as global size the maximum size we have 00299 mgui_sz.SetWidth(mcMAX(maxw, gui_GetBaseSize().GetWidth())); 00300 mgui_sz.SetHeight(maxh); 00301 } 00302 00303 void mcExpElementHelpers::gui_DrawActivationRect(wxDC &dc, int x, int y) const 00304 { 00305 // make all the bb of this element active 00306 dc.SetBrush(*mcElementHelpers::sgui_pActivationBrush); 00307 dc.SetPen(*wxBLACK_PEN); 00308 00309 // draw the rect taking in count the sgui_nAdditionalActivationSpaceLeftRight 00310 // adjust value... 00311 dc.DrawRectangle(x-sgui_nAdditionalActivationSpaceLeftRight, y, 00312 gui_GetSize().GetWidth()+sgui_nAdditionalActivationSpaceLeftRight*2, 00313 gui_GetSize().GetHeight()); 00314 } 00315 00316 void mcExpElementHelpers::gui_DrawNonActive(wxDC &dc, wxPoint &base, wxPoint &exp, wxPoint &sub) const 00317 { 00318 // draw as non active both base and exp; we don't need 00319 // to check if exp exist or it's visible... 00320 gui_DrawBase(dc, base.x, base.y, mcDRW_NONACTIVE, wxDefaultPosition); 00321 gui_ExpSubDraw(TRUE, dc, exp.x, exp.y, mcDRW_NONACTIVE, wxDefaultPosition); 00322 gui_ExpSubDraw(FALSE, dc, sub.x, sub.y, mcDRW_NONACTIVE, wxDefaultPosition); 00323 } 00324 00325 void mcExpElementHelpers::gui_DrawAllActive(wxDC &dc, wxPoint &orig, wxPoint &base, wxPoint &exp, wxPoint &sub) const 00326 { 00327 // make all the bb of this element active 00328 gui_DrawActivationRect(dc, orig.x, orig.y); 00329 00330 // both base and exp should be drawn using transparent mode 00331 gui_DrawNonActive(dc, base, exp, sub); 00332 } 00333 00334 int mcExpElementHelpers::gui_Draw(wxDC &dc, int x, int y, long flags, const wxPoint &pt) const 00335 { 00336 // precalc some useful data 00337 wxPoint orig(x, y); 00338 wxPoint b(x+gui_GetBaseOffsetx(), y+gui_GetBaseOffsety()), 00339 e(x+gui_GetExpSubOffsetx(TRUE), y+gui_GetExpSubOffsety(TRUE)), 00340 s(x+gui_GetExpSubOffsetx(FALSE), y+gui_GetExpSubOffsety(FALSE)); 00341 int r = mcDRW_NOACTIVEELEM; 00342 00343 00344 if (flags & mcDRW_NONACTIVE) { 00345 00346 // no problems 00347 gui_DrawNonActive(dc, b, e, s); 00348 mcGUILOG(wxT("mcExpElementHelpers::gui_Draw [%s] - just drawn everything as inactive"), mcTXTTHIS); 00349 return mcDRW_NOACTIVEELEM; 00350 00351 } else if (flags & mcDRW_ALLACTIVE) { 00352 00353 // no problems 00354 gui_DrawAllActive(dc, orig, b, e, s); 00355 mcGUILOG(wxT("mcExpElementHelpers::gui_Draw [%s] - just drawn everything as active"), mcTXTTHIS); 00356 00357 } else { 00358 00359 mcASSERT(flags & mcDRW_USEPOINT, wxT("Invalid flags")); 00360 00361 // pt is a valid pointer; check if we have an exponent... 00362 if (!data_hasProperty(mcEP_HASEXPONENT)) { 00363 00364 // point must be in the base, because exp doesn't exist or 00365 // it's not visible; call the base gui_Draw() function with 00366 // the point coord because, if the base is a container 00367 // of some other elements, maybe it wants to use mouse 00368 // position to draw as active only some portions. 00369 r = gui_DrawBase(dc, b.x, b.y, flags, pt); 00370 00371 // the subscript, if present, is always drawn as non-active 00372 if (data_hasProperty(mcEP_HASSUBSCRIPT)) 00373 gui_ExpSubDraw(TRUE, dc, s.x, s.y, mcDRW_NONACTIVE, wxDefaultPosition); 00374 00375 return r; 00376 00377 // exponent is hidden... 00378 } 00379 00380 // create some variables... 00381 wxRect exp(e, data_GetExp().gui_GetSize()); 00382 wxRect base(b, gui_GetBaseSize()); 00383 00384 // an element with an exponent should never allow the exponent to draw its 00385 // selection rectangle because the array containing this mcExpElement will 00386 // care of it, drawing the selection rectangle around this entire element... 00387 int expflags = flags & ~mcDRW_ALLOW_TOTAL_SELECTION; 00388 00389 // check if cursor is inside the empty space 00390 // above and next to the base; all derived elements are assumed to 00391 // consider this space useless; thus the behaviour of the element 00392 // when the cursor is inside these zones, is defined here 00393 bool bInsideExp = exp.Inside(pt); 00394 if (!bInsideExp && !base.Inside(pt)) { 00395 00396 // draw everything in the same way when (flags & mcDRW_ALLACTIVE) != 0 00397 gui_DrawAllActive(dc, orig, b, e, s); 00398 mcGUILOG(wxT("mcExpElementHelpers::gui_Draw [%s] - just drawn everything as active"), mcTXTTHIS); 00399 00400 } else if (bInsideExp) { 00401 00402 // the exponent cannot "decide" to make all the element active, 00403 // so we just have to call the base with mcDRW_NONACTIVE and 00404 // the exp with the pointer 00405 gui_DrawBase(dc, b.x, b.y, mcDRW_NONACTIVE, wxDefaultPosition); 00406 00407 if (data_hasProperty(mcEP_HASSUBSCRIPT)) 00408 gui_ExpSubDraw(FALSE, dc, s.x, s.y, mcDRW_NONACTIVE, wxDefaultPosition); 00409 00410 return gui_ExpSubDraw(TRUE, dc, e.x, e.y, expflags, pt); 00411 00412 } else { 00413 00414 // if cursor is not in the exp nor in the empty space, 00415 // it MUST be inside the base 00416 mcASSERT(base.Inside(pt), wxT("The given cursor position is wrong")); 00417 00418 if (gui_DrawAsActiveOverBase()) { 00419 00420 // the base does not contain subelements: we can draw the entire 00421 // element as active... 00422 gui_DrawAllActive(dc, orig, b, e, s); 00423 00424 } else { 00425 00426 // the base is a container of elements (e.g. mcBracket); the cursor 00427 // may be placed over one of the subelements. Thus the gui_DrawBase 00428 // function must receive a valid mouse cursor position to decide 00429 // which element must be highlighted (that is, drawn as active). 00430 // 00431 // Also the ID returned by this function cannot be the ID of this 00432 // element: it must be the ID of the active subelement inside the 00433 // base !!! 00434 r = gui_DrawBase(dc, b.x, b.y, flags, pt); 00435 00436 if (data_hasProperty(mcEP_HASSUBSCRIPT)) 00437 gui_ExpSubDraw(FALSE, dc, s.x, s.y, mcDRW_NONACTIVE, wxDefaultPosition); 00438 00439 gui_ExpSubDraw(TRUE, dc, e.x, e.y, mcDRW_NONACTIVE, wxDefaultPosition); 00440 00441 return r; 00442 } 00443 } 00444 } 00445 00446 // return our ID 00447 return data_GetID(); 00448 } 00449 00450 mcInputRes mcExpElementHelpers::gui_Input(const mcKey &ev, mcElement *newelem) 00451 { 00452 if (gui_isCursorInExpSub(TRUE)) 00453 return gui_ExpSubInput(TRUE, ev, newelem); 00454 else if (gui_isCursorInExpSub(FALSE)) 00455 return gui_ExpSubInput(FALSE, ev, newelem); 00456 return gui_BaseInput(ev, newelem); 00457 } 00458 00459 mcInsertRes mcExpElementHelpers::gui_Insert(const mcElement &toinsert, mcElement *newelem) 00460 { 00461 if (gui_isCursorInExpSub(TRUE)){ 00462 return data_GetExp().gui_Insert(toinsert, newelem); 00463 } 00464 else if (gui_isCursorInExpSub(FALSE)) { 00465 return data_GetSub().gui_Insert(toinsert, newelem); 00466 } 00467 00468 return gui_BaseInsert(toinsert, newelem); 00469 } 00470 00471 void mcExpElementHelpers::gui_OnSelect(wxDC &dc, wxRect &rc) 00472 { 00473 // remove old selections 00474 gui_DeSelect(); 00475 00476 // if there's no exponent, directly call gui_OnBaseSelect 00477 if (!data_hasProperty(mcEP_HASEXPONENT)) { 00478 gui_OnBaseSelect(dc, rc); 00479 return; 00480 } 00481 00482 int w = gui_GetExpSubOffsetx(TRUE), h = gui_GetBaseOffsety(); 00483 wxRect exprc(wxPoint(w, 0), data_GetExp().gui_GetSize()); 00484 wxRect baserc(wxPoint(0, h), mgui_szBase); 00485 00486 bool base = baserc.Intersects(rc); 00487 bool exp = exprc.Intersects(rc); 00488 00489 // does the selection intersects only the exponent ? 00490 if (exp && !base) { 00491 00492 // select the exponent 00493 rc.Offset(-exprc.x, -exprc.y); 00494 data_GetExp().gui_OnSelect(dc, rc); 00495 00496 // check if we must be set as selected, too 00497 if (data_GetExp().gui_isSelected()) 00498 gui_Select(); 00499 return; 00500 } 00501 00502 // if the selection rectangle intersects exponent rect and also 00503 // the base rect, the entire element must be selected... 00504 if (exp && base) { 00505 this->gui_SelectAll(); 00506 return; 00507 } 00508 00509 // if the selection rectangle intersects the base (or the empty space) only, 00510 // we can call gui_OnBaseSelect... 00511 if (base) 00512 gui_OnBaseSelect(dc, rc); 00513 } 00514 00515 mcElement mcExpElementHelpers::gui_GetSelection() const 00516 { 00517 if (gui_isAllSelected()) 00518 return mcElement(this); // just copy *this... 00519 00520 // if we are not completely selected and we don't have an exponent, 00521 // then the selection to return *must* be given by the base function... 00522 if (!data_hasProperty(mcEP_HASEXPONENT)) 00523 return gui_GetBaseSelection(); 00524 00525 // we've got an exponent to take in count... 00526 if (data_GetExp().gui_isSelected()) 00527 return data_GetExp().gui_GetSelection(); 00528 00529 return gui_GetBaseSelection(); 00530 } 00531 00532 mcMoveCursorRes mcExpElementHelpers::gui_MoveCursor(mcMoveCursorFlag flag, long modifiers) 00533 { 00534 mcMoveCursorRes n = mcMCR_OKAY; 00535 00536 // the IF ... ELSE IF ... construct is indispensable here: gui_ExpMoveCursor, 00537 // gui_BaseMoveCursor or gui_SubMoveCursor could change the cursor position from 00538 // exp to base, from base to sub or viceversa, so we must be sure not 00539 // to process twice the same flag !!! 00540 if (gui_isCursorInExpSub(TRUE)) { 00541 00542 // the gui_ExpMoveCursor function will handle the exponent return flags 00543 n = gui_ExpSubMoveCursor(TRUE, flag, modifiers); 00544 00545 } else if (gui_isCursorInExpSub(FALSE)) { 00546 00547 // the gui_SubMoveCursor function will handle the subscript return flags 00548 n = gui_ExpSubMoveCursor(FALSE, flag, modifiers); 00549 00550 } else if (gui_isCursorInBase()) { 00551 00552 // handle the return flags of gui_BaseMoveCursor here 00553 mcMoveCursorRes r = gui_BaseMoveCursor(flag, modifiers); 00554 00555 switch (r) { 00556 case mcMCR_OKAY: 00557 case mcMCR_CANNOT_SETFOCUS: 00558 break; 00559 00560 case mcMCR_SETFOCUS_NEXT: 00561 00562 // check if the exponent or the subscript is present 00563 if (gui_isOnRight(TRUE) && data_hasProperty(mcEP_HASEXPONENT)) 00564 gui_EditExpSub(TRUE); 00565 else if (data_hasProperty(mcEP_HASSUBSCRIPT)) 00566 gui_EditExpSub(FALSE); 00567 else 00568 return mcMCR_SETFOCUS_NEXT; 00569 break; 00570 00571 case mcMCR_SETFOCUS_PREVIOUS: 00572 00573 // check if the exponent is present 00574 if (gui_isOnRight(TRUE) || !data_hasProperty(mcEP_HASEXPONENT)) 00575 return mcMCR_SETFOCUS_PREVIOUS; 00576 else 00577 gui_EditExpSub(TRUE); 00578 break; 00579 00580 case mcMCR_SETFOCUS_BELOW: 00581 00582 // check if the subscript is present 00583 if (data_hasProperty(mcEP_HASSUBSCRIPT)) 00584 gui_EditExpSub(FALSE); 00585 else 00586 return mcMCR_SETFOCUS_BELOW; 00587 break; 00588 00589 case mcMCR_SETFOCUS_ABOVE: 00590 00591 // check if the exponent is present 00592 if (data_hasProperty(mcEP_HASEXPONENT)) 00593 gui_EditExpSub(TRUE); 00594 else 00595 return mcMCR_SETFOCUS_ABOVE; 00596 break; 00597 } 00598 } 00599 00600 return n; 00601 } 00602 00603 int mcExpElementHelpers::gui_MoveCursorUsingPoint(wxDC &dc, const wxPoint &p) 00604 { 00605 // check if the mouse cursor is inside exponent or 00606 // inside the base 00607 wxRect rc(wxPoint(0, gui_GetBaseOffsety()), gui_GetBaseSize()); 00608 wxPoint pt(p); 00609 00610 if (rc.Inside(p)) { 00611 00612 // cursor is inside the base 00613 pt.y -= gui_GetBaseOffsety(); 00614 int r = gui_BaseMoveCursorUsingPoint(dc, pt); 00615 00616 if (r == mcMCR_CANNOT_SETFOCUS) 00617 return mcMCR_CANNOT_SETFOCUS; 00618 00619 // ok, now the cursor is inside the base 00620 mgui_nCursorLoc = mcECL_INSIDEBASE; 00621 return mcMCR_OKAY; 00622 00623 } else if (data_hasProperty(mcEP_HASEXPONENT)) { 00624 00625 // cursor is inside exp or empty space ? 00626 // STRANGE ERROR WITH GCC & MINGW COMPILERS: if in the following 00627 // line I do not use the THIS pointer to access gui_GetExpSubOffsetx(TRUE, () 00628 // function I get an error..... 00629 wxRect exp(wxPoint(this->gui_GetExpSubOffsetx(TRUE), 0), 00630 data_GetExp().gui_GetSize()); 00631 00632 if (exp.Inside(p)) { 00633 // it's inside the exponent... 00634 int r = gui_ExpSubMoveCursorUsingPoint(TRUE, dc, p); 00635 00636 if (r == mcMCR_CANNOT_SETFOCUS) 00637 return mcMCR_CANNOT_SETFOCUS; 00638 00639 // ok, now the cursor is inside the base 00640 mgui_nCursorLoc = mcECL_INSIDEEXPONENT; 00641 return mcMCR_OKAY; 00642 } 00643 00644 // it's inside empty space: do nothing 00645 00646 } else { 00647 00648 /*mcASSERT(0, wxT("Cursor cannot be in empty space because when ") 00649 wxT("the exponent is absent, there's no empty space"));*/ 00650 } 00651 00652 return mcMCR_OKAY; 00653 } 00654 00655 void mcExpElementHelpers::gui_SetCursorPos(const mcCursorPos &code) 00656 { 00657 if (code.isBegin()) { 00658 00659 // if the exponent is placed on the left... 00660 if (gui_hasBaseSthOnLeftSide()) 00661 gui_SetExpSubCursorPos(TRUE, code); 00662 else 00663 gui_SetBaseCursorPos(code); // if there is no exponent on the left... 00664 00665 } else { 00666 00667 mcASSERT(code.isEnd(), wxT("gui_SetCursorPos can handle only mcCP_BEGIN, mcCP_END")); 00668 00669 // if the exponent is visible and placed on the right 00670 if (gui_hasBaseSthOnRightSide()) 00671 gui_SetExpSubCursorPos(TRUE, code); 00672 00673 // if there is no exponent on the right and there is 00674 // a subscript (the exponent has higher priority than 00675 // subscript).... 00676 if (!data_hasProperty(mcEP_HASEXPONENT) || !gui_isOnRight(TRUE)) { 00677 00678 // the subscript, if present, is always on the right: it has 00679 // higher priority than the base 00680 if (data_hasProperty(mcEP_HASSUBSCRIPT)) 00681 gui_SetExpSubCursorPos(FALSE, code); 00682 else 00683 gui_SetBaseCursorPos(code); 00684 } 00685 } 00686 } 00687 00688 void mcExpElementHelpers::gui_GetCursorPos(mcCursorPos &cp) const 00689 { 00690 if (gui_isCursorInExpSub(TRUE)) 00691 gui_GetExpSubCursorPos(TRUE, cp); 00692 else if (gui_isCursorInExpSub(FALSE)) 00693 gui_GetExpSubCursorPos(FALSE, cp); 00694 else { 00695 00696 // cursor is in the base... 00697 mcCursorPos r(gui_GetBaseCursorPos()); 00698 00699 // if there's no exponent/subscript, the mcCP_BEGIN/mcCP_END flags 00700 // should be okay... 00701 if (r.isBegin() && !gui_hasBaseSthOnLeftSide()) 00702 cp.gui_Push(mcCP_BEGIN); 00703 else if (r.isEnd() && !gui_hasBaseSthOnRightSide()) 00704 cp.gui_Push(mcCP_END); 00705 else 00706 // ... but if they are present, the cursor is at the begin/end 00707 // of the base, NOT at the begin/end of the global element... 00708 cp.gui_Push(mgui_nCursorLoc); 00709 } 00710 } 00711 00712 int mcExpElementHelpers::gui_GetRelCursorPos(wxDC &dc, wxPoint *pt) const 00713 { 00714 int n; 00715 if (gui_isCursorInExpSub(TRUE)) 00716 return gui_GetExpSubRelCursorPos(TRUE, dc, pt); 00717 else if (gui_isCursorInExpSub(FALSE)) 00718 return gui_GetExpSubRelCursorPos(FALSE, dc, pt); 00719 00720 // cursor is in the base... 00721 n = gui_GetBaseRelCursorPos(dc, pt); 00722 00723 // add base offsets 00724 pt->y += gui_GetBaseOffsety(); 00725 pt->x += gui_GetBaseOffsetx(); 00726 00727 return n; 00728 } 00729 00730 int mcExpElementHelpers::gui_GetYAnchor() const 00731 { 00732 // the y-amount of pixels to leave above the center line of the 00733 // containing expression must be a value which makes the 00734 // center line of the base *always* coincide with the center 00735 // line of the containing expression 00736 return gui_GetBaseSize().GetHeight()/2 + gui_GetBaseOffsety(); 00737 } 00738 00739 void mcExpElementHelpers::gui_UpdateExpDepth() 00740 { 00741 // update the exponent 00742 if (data_GetExp() != mcEmptyElement) 00743 data_GetExp().gui_SetAsExpOf(this); 00744 00745 // update the subscript 00746 if (data_GetSub() != mcEmptyElement) 00747 data_GetSub().gui_SetAsExpOf(this); 00748 00749 // always call base class version 00750 mcElementHelpers::gui_UpdateExpDepth(); 00751 } 00752 00753 bool mcExpElementHelpers::gui_isCursorInBase() const 00754 { 00755 // negative flags are preserved for mcExpElement use 00756 if (mgui_nCursorLoc == mcECL_INSIDEBASE) 00757 return TRUE; 00758 return FALSE; 00759 } 00760 00761 bool mcExpElementHelpers::gui_hasBaseSthOnRightSide() const 00762 { 00763 if ((gui_isOnRight(TRUE) && data_hasProperty(mcEP_HASEXPONENT)) 00764 || data_hasProperty(mcEP_HASSUBSCRIPT)) 00765 return TRUE; 00766 return FALSE; 00767 } 00768 00769 bool mcExpElementHelpers::gui_hasBaseSthOnLeftSide() const 00770 { 00771 if (!gui_isOnRight(TRUE) && data_hasProperty(mcEP_HASEXPONENT)) 00772 return TRUE; 00773 return FALSE; 00774 } 00775 00776 int mcExpElementHelpers::gui_HandleSubExpEditKeys(const mcKey &key) 00777 { 00778 // if the user wants to edit the exponent, let him do it 00779 if (mcMathCore::Get()->m_pEditExpKey->MatchKey(key) 00780 && mdata_bExpEnabled) { 00781 gui_EditExpSub(TRUE); 00782 return mcIR_OKAY; 00783 } 00784 00785 // same for the subscript 00786 if (mcMathCore::Get()->m_pEditSubscriptKey->MatchKey(key) 00787 && mdata_bSubEnabled) { 00788 gui_EditExpSub(FALSE); 00789 return mcIR_OKAY; 00790 } 00791 00792 // in this way we are sure to return something which is 00793 // not the mcIR_OKAY flag... 00794 return !mcIR_OKAY; 00795 } 00796 00797 wxSize mcExpElementHelpers::gui_GetBaseAndSubSize() const 00798 { 00799 int h = gui_GetBaseSize().GetHeight(); 00800 00801 // if subscript is present, make sure h is great enough 00802 if (data_hasProperty(mcEP_HASSUBSCRIPT)) 00803 h = mcMAX(gui_GetExpSubOffsety(FALSE) - gui_GetBaseOffsety() 00804 + gui_GetExpSubSize(FALSE).GetHeight(), h); 00805 00806 return wxSize(gui_GetBaseSize().GetWidth()+gui_GetExpSubSize(FALSE).GetWidth(), h); 00807 } 00808 00809 00810 00811 00812 00813 00814 00815 00816 // ---------------------------------------------- 00817 // mcEXPELEMENTGUI - element & subscript handlers 00818 // ---------------------------------------------- 00819 00820 bool mcExpElementHelpers::gui_isCursorInExpSub(bool exp, bool bCheckBeginEndExp) const 00821 { 00822 // be sure that exponent is visible 00823 if (!data_hasProperty(mcEP_HAS(exp))) 00824 return FALSE; 00825 00826 // check the easiest case 00827 if (mgui_nCursorLoc == mcECL_INSIDE(exp)) 00828 return TRUE; 00829 00830 // check if cursor is at begin or end of the exp 00831 if (bCheckBeginEndExp && mgui_nCursorLoc == mcECL_END(exp)) 00832 return TRUE; 00833 00834 if (bCheckBeginEndExp && exp && mgui_nCursorLoc == mcECL_EXPONENTBEGIN) 00835 return TRUE; 00836 00837 return FALSE; 00838 } 00839 00840 bool mcExpElementHelpers::gui_isExpSubEndKey(bool exp, const mcKey &ev) const 00841 { 00842 if (mgui_nCursorLoc == mcECL_BEGIN(exp)) { 00843 00844 // at this position you're allowed only to delete previous 00845 // elements.... 00846 if (mcMathCore::Get()->m_pDeleteKey->MatchKey(ev)) 00847 return FALSE; 00848 00849 // all other inputs are refused 00850 return TRUE; 00851 00852 } else if (mgui_nCursorLoc == mcECL_INSIDE(exp)) { 00853 00854 // the exp/sub class will care of this question; however, 00855 // exp/sub always accept all input, so it should always 00856 // return FALSE.... 00857 return data_Get(exp).gui_isEndKey(ev); 00858 00859 } else if (mgui_nCursorLoc == mcECL_END(exp)) { 00860 00861 // at this position you're allowed only to delete previous 00862 // characters.... 00863 if (mcMathCore::Get()->m_pDeleteKey->MatchKey(ev)) 00864 return FALSE; 00865 if (mcGetEditKey(exp)->MatchKey(ev)) 00866 return FALSE; 00867 00868 // all other inputs are refused 00869 return TRUE; 00870 } 00871 00872 // if exponent is not in the exponent nor at the end of it; this 00873 // is not a cursor position we can handle... 00874 return FALSE; 00875 } 00876 00877 int mcExpElementHelpers::gui_ExpSubDraw(bool exp, wxDC &dc, int x, int y, 00878 long flags, const wxPoint &pt) const 00879 { 00880 // is the exponent/subscript visible ? 00881 if (!data_hasProperty(mcEP_HAS(exp))) 00882 return mcDRW_NOACTIVEELEM; // no exp/sub, no ID 00883 00884 // draw the exponent/subscript at the given pos 00885 return data_Get(exp).gui_Draw(dc, x, y, flags, pt); 00886 } 00887 00888 wxSize mcExpElementHelpers::gui_GetExpSubSize(bool exp) 00889 { 00890 if (data_hasProperty(mcEP_HAS(exp))) 00891 return data_Get(exp).gui_GetSize(); 00892 00893 /* exp/sub is not visible, thus 00894 it doesn't occupy any space */ 00895 return wxSize(0, 0); 00896 } 00897 00898 // in these two versions, the CONST versions 00899 // of gui() and gui_GetSize() are used... 00900 00901 wxSize mcExpElementHelpers::gui_GetExpSubSize(bool exp) const 00902 { 00903 if (data_hasProperty(mcEP_HAS(exp))) 00904 return data_Get(exp).gui_GetSize(); 00905 00906 /* exp/sub is not visible, thus 00907 it doesn't occupy any space */ 00908 return wxSize(0, 0); 00909 } 00910 00911 void mcExpElementHelpers::gui_RecalcExpSubSize(bool exp) 00912 { 00913 // is exp/sub allocated ? 00914 if (data_Get(exp) == mcEmptyElement) 00915 return; // no exp/sub, no size to recalc 00916 00917 // update exp/sub size 00918 data_Get(exp).gui_RecalcSize(); 00919 } 00920 00921 00922 00923 00924 int mcExpElementHelpers::gui_GetBaseOffsety() const 00925 { return mcElementHelpers::gui_GetBaseOffsety(gui_GetExpSubSize(TRUE).GetHeight()); } 00926 00927 int mcExpElementHelpers::gui_GetBaseOffsetx() const 00928 { 00929 // the base should *always* be drawn starting from the leftmost point... 00930 return 0; 00931 } 00932 00933 00934 00935 int mcExpElementHelpers::gui_GetExpSubOffsety(bool exp) const 00936 { 00937 if (!exp) 00938 return gui_GetBaseOffsety() + 00939 mcElementHelpers::gui_GetSubscriptOffsety(gui_GetBaseSize().GetHeight()); 00940 00941 // the exponent, if visible, is *always* placed at the top of the element... 00942 return 0; 00943 } 00944 00945 int mcExpElementHelpers::gui_GetExpSubOffsetx(bool exp) const 00946 { 00947 // if the exponent is placed on the right of the element, we must 00948 // return the size of the entire base... 00949 if (exp && gui_isOnRight(exp)) 00950 return gui_GetBaseSize().GetWidth(); 00951 if (exp) 00952 return 0; 00953 00954 // the subscripts can be placed only on the right... 00955 return gui_GetBaseSize().GetWidth(); 00956 } 00957 00958 00959 00960 00961 int mcExpElementHelpers::gui_GetExpSubRelCursorPos(bool exp, wxDC &dc, wxPoint *pt) const 00962 { 00963 if (mgui_nCursorLoc == mcECL_BEGIN(exp)) { 00964 00965 // cursor is at the begin of an exponent placed on the left of 00966 // the element but ready to type at "element level" 00967 pt->x = 0; 00968 pt->y = 0; 00969 00970 return gui_GetHeight(); 00971 00972 } else if (mgui_nCursorLoc == mcECL_INSIDE(exp)) { 00973 00974 // set the point to the upper-left coord 00975 pt->x = 0; 00976 pt->y = 0; 00977 00978 // call exponent's function 00979 int n = data_Get(exp).gui_GetRelCursorPos(dc, pt); 00980 00981 // set the cursor position relative to the coord. 00982 // of this element adding base width 00983 pt->x += gui_GetExpSubOffsetx(exp); 00984 pt->y += gui_GetExpSubOffsety(exp); 00985 return n; 00986 00987 } else if (mgui_nCursorLoc == mcECL_END(exp)) { 00988 00989 // cursor is at the end of the exponent but ready 00990 // to type at "element level"; because both the 00991 // mcECL_EXPONENTEND and mcECL_SUBSCRIPTEND 00992 // flags are handled in the same way, here we use 00993 // fixed functions. 00994 pt->x = gui_GetWidth(); 00995 pt->y = gui_GetExpSubOffsety(exp); 00996 return gui_GetHeight() - pt->y; 00997 } 00998 00999 // cursor is not inside exp... 01000 return mcNotInside(exp); 01001 } 01002 01003 mcMoveCursorRes mcExpElementHelpers::gui_ExpSubMoveCursor(bool exp, 01004 mcMoveCursorFlag flags, 01005 long modifiers) 01006 { 01007 mcMoveCursorRes r; 01008 if (mgui_nCursorLoc == mcECL_INSIDE(exp)) { 01009 01010 // inside this branch we can always assume the exponent visible: 01011 // the cursor is inside it !!! 01012 r = data_Get(exp).gui_MoveCursor(flags, modifiers); 01013 01014 switch (r) { 01015 case mcMCR_SETFOCUS_NEXT: 01016 if (gui_isOnRight(exp)) 01017 mgui_nCursorLoc = mcECL_END(exp); 01018 else 01019 gui_EditBaseAndSetPos(mcCP_BEGIN); 01020 break; 01021 01022 case mcMCR_SETFOCUS_PREVIOUS: 01023 if (gui_isOnRight(exp)) 01024 gui_EditBaseAndSetPos(mcCP_END); 01025 else 01026 mgui_nCursorLoc = mcECL_BEGIN(exp); 01027 break; 01028 01029 case mcMCR_SETFOCUS_BELOW: 01030 gui_EditBase(); 01031 break; 01032 01033 case mcMCR_SETFOCUS_ABOVE: 01034 return mcMCR_SETFOCUS_ABOVE; 01035 01036 default: 01037 return r; 01038 } 01039 01040 } else if (mgui_nCursorLoc == mcECL_END(exp)) { 01041 01042 // in this branch we can assume the exponent placed at the right 01043 // of the element: otherwise mgui_nCursorLoc would never assume 01044 // the mcECL_EXPONENTEND position 01045 switch (flags) { 01046 case mcMCF_LEFT: 01047 case mcMCF_UP: 01048 gui_EditExpSub(exp); 01049 data_Get(exp).gui_SetCursorPos(mcCP_END); 01050 break; 01051 01052 case mcMCF_RIGHT: 01053 return mcMCR_SETFOCUS_NEXT; 01054 01055 case mcMCF_DOWN: 01056 return mcMCR_SETFOCUS_BELOW; 01057 } 01058 01059 } else if (mgui_nCursorLoc == mcECL_BEGIN(exp)) { 01060 01061 // in this branch we can assume the exponent placed at the left 01062 // of the element: otherwise mgui_nCursorLoc would never assume 01063 // the mcECL_EXPONENTBEGIN position 01064 switch (flags) { 01065 case mcMCF_LEFT: 01066 return mcMCR_SETFOCUS_PREVIOUS; 01067 01068 case mcMCF_DOWN: 01069 return mcMCR_SETFOCUS_BELOW; 01070 01071 case mcMCF_RIGHT: 01072 case mcMCF_UP: 01073 gui_EditExpSub(exp); 01074 data_Get(exp).gui_SetCursorPos(mcCP_BEGIN); 01075 break; 01076 } 01077 01078 } else { 01079 01080 mcASSERT(0, wxT("unhandled cursor pos")); 01081 } 01082 01083 // everything should be okay 01084 return mcMCR_OKAY; 01085 } 01086 /* 01087 mcMoveCursorRes mcExpElementHelpers::gui_SubMoveCursor(mcMoveCursorFlag flags, long modifiers) 01088 { 01089 int r; 01090 01091 if (mgui_nCursorLoc == mcECL_INSIDESUBSCRIPT) { 01092 01093 // inside this branch we can always assume the subscript visible: 01094 // the cursor is inside it !!! 01095 r = data_GetSub().gui_MoveCursor(flags, modifiers); 01096 01097 switch (r) { 01098 case mcMCR_SETFOCUS_NEXT: 01099 mgui_nCursorLoc = mcECL_SUBSCRIPTEND; 01100 break; 01101 01102 case mcMCR_SETFOCUS_PREVIOUS: 01103 gui_EditBaseAndSetPos(mcCP_END); 01104 break; 01105 01106 case mcMCR_SETFOCUS_BELOW: 01107 return mcMCR_SETFOCUS_BELOW; 01108 01109 case mcMCR_SETFOCUS_ABOVE: 01110 gui_EditBase(); 01111 break; 01112 } 01113 01114 } else if (mgui_nCursorLoc == mcECL_SUBSCRIPTEND) { 01115 01116 // move the cursor 01117 switch (flags) { 01118 case mcMCF_LEFT: 01119 case mcMCF_DOWN: 01120 gui_EditSub(); 01121 data_GetSub().gui_SetCursorPos(mcCP_END); 01122 break; 01123 01124 case mcMCF_RIGHT: 01125 return mcMCR_SETFOCUS_NEXT; 01126 01127 case mcMCF_UP: 01128 return mcMCR_SETFOCUS_ABOVE; 01129 } 01130 01131 } else { 01132 01133 mcASSERT(0, wxT("unhandled cursor pos")); 01134 } 01135 01136 // everything should be okay 01137 return mcMCR_OKAY; 01138 }*/ 01139 01140 01141 01142 01143 int mcExpElementHelpers::gui_ExpSubMoveCursorUsingPoint(bool exp, wxDC &dc, const wxPoint &p) 01144 { 01145 if (!gui_isCursorInExpSub(exp)) 01146 return mcNotInside(exp); 01147 01148 // we do not have to handle any return flag... 01149 return data_Get(exp).gui_MoveCursorUsingPoint(dc, p); 01150 } 01151 01152 mcInputRes mcExpElementHelpers::gui_ExpSubInput(bool exp, const mcKey &ev, mcElement *pnew) 01153 { 01154 if (mgui_nCursorLoc == mcECL_BEGIN(exp)) { 01155 01156 if (mcMathCore::Get()->m_pDeleteKey->MatchKey(ev)) { 01157 01158 // user wants to delete something on the previous element... 01159 return mcIR_DELETE_PREVIOUS; 01160 01161 } else { 01162 01163 // something is wrong; all input keys should have 01164 // been blocked by gui_isExpEndKey function 01165 mcASSERT(0, wxT("Code should never get here")); 01166 } 01167 01168 } else if (mgui_nCursorLoc == mcECL_INSIDE(exp)) { 01169 01170 // mcPolynomial will care of everything... 01171 mcInputRes result = data_Get(exp).gui_Input(ev, pnew); 01172 if (result == mcIR_DELETE_PREVIOUS || result == mcIR_DELETE_THIS) { 01173 01174 // remove the exp/sub 01175 gui_DeleteExpSub(exp); 01176 } 01177 01178 gui_RecalcSize(); // size has been modified 01179 01180 } else if (mgui_nCursorLoc == mcECL_END(exp)) { 01181 01182 if (mcMathCore::Get()->m_pDeleteKey->MatchKey(ev)) { 01183 01184 // put the cursor at exp/sub level, moving the cursor 01185 gui_ExpSubMoveCursor(exp, mcMCF_LEFT, mcMCF_NOMODIFIERS); 01186 01187 } else if (mcGetEditKey(exp)->MatchKey(ev)) { 01188 01189 // the user decided to edit the sub/exp 01190 gui_EditExpSub(exp); 01191 01192 } else { 01193 01194 mcASSERT(0, wxT("All the other input should have been blocked ") 01195 wxT("by isSub/ExpEndKey() functions")); 01196 } 01197 } 01198 01199 // everything's okay 01200 return mcIR_OKAY; 01201 } 01202 01203 void mcExpElementHelpers::gui_EditExpSub(bool exp) 01204 { 01205 // cursor is now inside exp/sub 01206 mgui_nCursorLoc = mcECL_INSIDE(exp); 01207 01208 // exp/sub has not allocated yet, do it now 01209 if (data_Get(exp) == mcEmptyElement) { 01210 01211 bool allowed; 01212 01213 if (exp) 01214 allowed = mcElementHelpers::math_isExpAllowed(this); 01215 else 01216 allowed = mcElementHelpers::math_isSubAllowed(this); 01217 01218 if (allowed) { 01219 01220 gui_CreateExpSub(exp); 01221 gui_RecalcSize(); 01222 01223 } else { 01224 01225 // another exp/sub nest level is not allowed !!! 01226 mcMathCore::Get()->SyntaxError(wxT("Cannot nest another exp/sub")); 01227 return; 01228 } 01229 } 01230 01231 // check that the exp/sub is not 'too' empty... 01232 gui_CheckExpSub(exp); 01233 01234 // save exp/sub flag 01235 bool old = data_hasProperty(mcEP_HAS(exp)); 01236 01237 // if this is not the first time the exp/sub is being 01238 // edited, this flag should be already set 01239 data_AddProperty(mcEP_HAS(exp)); 01240 01241 // if this is the first time exp/sub become visible, we 01242 // must recalculate size of this entire element (and set 01243 // cursor position at the end of the exp/sub) 01244 if (old == FALSE) { 01245 gui_RecalcSize(); 01246 data_Get(exp).gui_SetCursorPos(mcCP_END); 01247 } 01248 } 01249 01250 01251 01252 01253 void mcExpElementHelpers::gui_EditBaseAndSetPos(const mcCursorPos &cp) 01254 { 01255 gui_EditBase(); 01256 gui_SetBaseCursorPos(cp); 01257 } 01258 01259 01260 01261 01262 01263 void mcExpElementHelpers::gui_CheckExpSub(bool exp) 01264 { 01265 if (exp) { 01266 mcPolynomial p(data_GetExp()); 01267 if (p.data_isArrayEmpty()) { 01268 p.gui_AddNewEmptyMonomial(); 01269 01270 // the size of this element has changed... 01271 gui_RecalcSize(); 01272 } 01273 } else { 01274 // default implementation does nothing 01275 } 01276 } 01277 01278 void mcExpElementHelpers::gui_SetExpSubCursorPos(bool exp, const mcCursorPos &code) 01279 { 01280 if (!data_hasProperty(mcEP_HAS(exp))) 01281 return; 01282 01283 if (code.isEnd() && gui_isOnRight(exp)) 01284 mgui_nCursorLoc = mcECL_END(exp); 01285 if (code.isBegin() && !gui_isOnRight(exp)) 01286 mgui_nCursorLoc = mcECL_BEGIN(exp); 01287 } 01288 01289 void mcExpElementHelpers::gui_GetExpSubCursorPos(bool exp, mcCursorPos &cp) const 01290 { 01291 if (!data_hasProperty(mcEP_HAS(exp))) { 01292 cp.gui_Push(mcCP_UNDEFINED); 01293 return; 01294 } 01295 01296 if (mgui_nCursorLoc == mcECL_BEGIN(exp)) 01297 cp.gui_Push(mcCP_BEGIN); 01298 else if (mgui_nCursorLoc == mcECL_INSIDE(exp)) 01299 data_Get(exp).gui_GetCursorPos(cp); 01300 else if (mgui_nCursorLoc == mcECL_END(exp)) 01301 cp.gui_Push(mcCP_END); 01302 else 01303 cp.gui_Push(mcCP_UNDEFINED); 01304 } 01305 01306 void mcExpElementHelpers::gui_DeleteExpSub(bool exp) 01307 { 01308 // move cursor in the base 01309 gui_EditBase(); 01310 01311 // when exponent is deleted, it doesn't care if the 01312 // exponent is placed on the left and on the right: 01313 // the cursor must always be placed on the rightmost 01314 // point of the base; the same for the subscript 01315 gui_SetBaseCursorPos(mcCP_END); 01316 01317 // delete the exponent/subscript 01318 data_DestroyExpSub(exp); 01319 data_RemoveProperty(mcEP_HAS(exp)); 01320 } 01321 01322 01323 01324 01325 01326 01327 01328 01329 01330 // ---------------------------------------- 01331 // mcEXPELEMENTIO 01332 // ---------------------------------------- 01333 01334 wxXml2Node mcExpElementHelpers::io_GetMathML(bool bGetPresentation) const 01335 { 01336 bool expv = data_hasProperty(mcEP_HASEXPONENT); 01337 bool subv = data_hasProperty(mcEP_HASSUBSCRIPT); 01338 wxString nodename; 01339 01340 // there are four cases: exp visible and sub hidden, sub visible and 01341 // exp hidden, both visible, both hidden... 01342 if (expv && !subv) 01343 nodename = wxT("msup"); 01344 else if (!expv && subv) 01345 nodename = wxT("msub"); 01346 else if (expv && subv) 01347 nodename = wxT("msubsup"); 01348 else { 01349 01350 // we don't need to create any wrapper tag 01351 return io_GetBaseMathML(bGetPresentation); 01352 } 01353 01354 // save base and exponent/subscript Math ML 01355 wxXml2Node base = io_GetBaseMathML(bGetPresentation); 01356 wxXml2Node maintag(wxXML_ELEMENT_NODE, wxXml2EmptyDoc, nodename); 01357 01358 // add the exp or/and sub mathML 01359 if (bGetPresentation) { 01360 01361 // the base must always be the first 01362 maintag.AddChild(base); 01363 01364 // if present, then comes the subscript 01365 if (subv) { 01366 01367 wxXml2Node node(data_GetSub().io_GetMathML(bGetPresentation)); 01368 maintag.AddChild(node); 01369 } 01370 01371 // if present, last is the exponent 01372 if (expv) { 01373 01374 wxXml2Node node(data_GetExp().io_GetMathML(bGetPresentation)); 01375 maintag.AddChild(node); 01376 } 01377 01378 } else { 01379 01380 mcASSERT(0, wxT("still to implement")); 01381 } 01382 01383 // we have exported both exponent & subscript->.. 01384 return maintag; 01385 } 01386 01387 01388 wxString mcExpElementHelpers::io_GetInlinedExpr() const 01389 { 01390 bool expv = data_hasProperty(mcEP_HASEXPONENT); 01391 bool subv = data_hasProperty(mcEP_HASSUBSCRIPT); 01392 bool bracketize = FALSE; 01393 wxString str = io_GetBaseInlinedExpr(); 01394 01395 if (subv) { 01396 01397 // add the subscript inlined expression 01398 str += wxT("_") + data_GetSub().io_GetInlinedExpr(); 01399 } 01400 01401 if (expv) { 01402 01403 str += wxT("^"); 01404 01405 if (data_GetExp().data_GetChildrenCount() > 1 && 01406 data_GetExp().data_GetType() != mcET_BRACKET) 01407 bracketize = TRUE; 01408 01409 // add the exponent inlined expression, possibly 01410 // bracketizing it... 01411 if (bracketize) str += wxT("("); 01412 str += data_GetExp().io_GetInlinedExpr(); 01413 if (bracketize) str += wxT(")"); 01414 } 01415 01416 // we have exported both exponent & subscript->.. 01417 return str; 01418 } 01419 01420 int GetLastRightBracketIdx(const wxString &str, int nest = 0) 01421 { 01422 int i=0, max=str.Len(); 01423 do { 01424 if (i >= max) return -1; // could not find the last right bracket 01425 01426 if (mcBracketHelpers::gui_isLeftParenthesis(str.GetChar(i))) 01427 nest++; 01428 else if (mcBracketHelpers::gui_isRightParenthesis(str.GetChar(i))) 01429 nest--; 01430 i++; 01431 } while (nest > 0); 01432 01433 return i; 01434 } 01435 01436 void mcExpElementHelpers::io_GetExpSubInlinedToken(wxString &subexp) //const 01437 { 01438 // remove the exponent/subscript symbol... 01439 subexp.Remove(0, 1); 01440 01441 // if the string begins like: ^(...) or _(....) 01442 if (mcBracketHelpers::gui_isLeftParenthesis(subexp.GetChar(0))) { 01443 01444 // find the matching right parenthesis for the first 01445 // left parenthesis... 01446 int i = GetLastRightBracketIdx(subexp); 01447 01448 // truncate the string to that last right parenthesis... 01449 subexp.Truncate(i); 01450 01451 } else { 01452 01453 subexp = subexp.BeforeFirst(wxT('+')); 01454 subexp = subexp.BeforeFirst(wxT('-')); 01455 01456 // take only the first monomial as exp/sub 01457 int i = GetLastRightBracketIdx(subexp, 1); 01458 01459 // truncate the string to that last right parenthesis... 01460 if (i > 0) subexp.Truncate(i-1); 01461 } 01462 } 01463 01464 bool mcExpElementHelpers::io_ImportInlinedExpr(const wxString &str, int *count, wxString &pErr) 01465 { 01466 // first of all, let the abse import its part of the given string: 01467 // exponent and subscript inlined expressions, if present, always 01468 // follows the base... 01469 if (!io_ImportBaseInlinedExpr(str, count, pErr)) 01470 return FALSE; 01471 01472 /* return io_ImportExpSub(str, count, pErr); 01473 } 01474 01475 bool mcExpElementHelpers::io_ImportExpSub(const wxString &str, int *count, wxString &pErr) 01476 {*/ 01477 wxString subexp = str.Right(str.Len()-*count); 01478 bool bexp, bsub; 01479 int n = 0; 01480 01481 // then, if everything is okay, check if an exponent or a subscript 01482 // must be imported ... 01483 bexp = (subexp.GetChar(0) == wxT('^')); 01484 bsub = (subexp.GetChar(0) == wxT('_')); 01485 if (bexp || bsub) { 01486 01487 io_GetExpSubInlinedToken(subexp); 01488 01489 } else { 01490 01491 // our import process finishes here 01492 return TRUE; 01493 } 01494 01495 // import the EXPONENT 01496 if (bexp) { 01497 01498 mcIOLOG(wxT("mcExpElementHelpers::io_ImportInlinedExpr - importing the exp [%s]"), subexp.c_str()); 01499 01500 // this call erases previous exponent (if present) and (if not 01501 // already present) creates it... 01502 data_CreateExpSub(TRUE); 01503 01504 if (!data_GetExp().io_ImportInlinedExpr(subexp, &n, pErr)) { 01505 01506 *count += n+1; 01507 return FALSE; 01508 } 01509 } 01510 01511 // import the SUBSCRIPT 01512 if (bsub) { 01513 01514 mcIOLOG(wxT("mcExpElementHelpers::io_ImportInlinedExpr - importing the subscript [%s]"), subexp.c_str()); 01515 01516 // this call erases previous sub (if present) and (if not 01517 // already present) creates it... 01518 data_CreateExpSub(FALSE); 01519 01520 if (!data_GetSub().io_ImportInlinedExpr(subexp, &n, pErr)) { 01521 *count += n; 01522 return FALSE; 01523 } 01524 } 01525 01526 *count += n+1; // take in count also the wxT('^') or '_' symbol 01527 return TRUE; 01528 } 01529 01530 01531 01532 01533 01534 // ------------------------- 01535 // mcEXPELEMENTMATH 01536 // ------------------------- 01537 01538 bool mcExpElementHelpers::math_hasExp() const 01539 { 01540 // this function cannot be placed in the header because it uses mcExpElement... 01541 //return data_hasProperty(mcEP_HASEXPONENT); 01542 return (data_GetExp() != mcEmptyElement) && data_hasProperty(mcEP_HASEXPONENT); 01543 } 01544 01545 bool mcExpElementHelpers::math_hasSub() const 01546 { 01547 // this function cannot be placed in the header because it uses mcExpElement... 01548 //return data_hasProperty(mcEP_HASEXPONENT); 01549 return (data_GetSub() != mcEmptyElement) && data_hasProperty(mcEP_HASSUBSCRIPT); 01550 } 01551 01552 const mcPolynomial &mcExpElementHelpers::math_GetConstExp() const 01553 { 01554 const mcElement &e = data_GetExp(); 01555 01556 // if not present, create it.... 01557 if (e == mcEmptyElement) { 01558 //data_CreateExp(); 01559 return *mcPolynomialHelpers::smath_pOne; 01560 //return (const mcPolynomial &)data_GetExp(); 01561 } 01562 01563 // exponent should be a polynomial 01564 mcASSERT(e.data_GetType() == mcET_POLYNOMIAL, 01565 wxT("mcExpElementMath can work only on mcPolynomials as exp")); 01566 return (const mcPolynomial &)data_GetExp(); 01567 } 01568 01569 mcPolynomial &mcExpElementHelpers::math_GetExp() 01570 { 01571 if (data_GetExp() == mcEmptyElement) { 01572 data_CreateExpSub(TRUE); 01573 data_SetExpSub(TRUE, *mcPolynomialHelpers::smath_pOne); 01574 } 01575 return (mcPolynomial &)data_GetExp(); 01576 } 01577 01578 const mcText &mcExpElementHelpers::math_GetConstSub() const 01579 { 01580 const mcElement &e = data_GetSub(); 01581 01582 // if not present, create it.... 01583 if (e == mcEmptyElement) 01584 return *mcTextHelpers::smath_pEmpty; 01585 01586 // exponent should be a mcText 01587 mcASSERT(e.data_GetType() == mcET_TEXT, 01588 wxT("mcExpElementMath can work only on mcText as sub")); 01589 return (const mcText &)e; 01590 } 01591 /* 01592 const mcPolynomial &mcExpElementHelpers::math_data_GetExp() const 01593 { 01594 // if exponent does not exist, then return a polynomial containing 01595 // only one mcNumber set to 1.0 01596 if (data_GetExp() == NULL) 01597 return mcPolynomial::math_pOne; 01598 return (const mcPolynomial &)data_GetExp(); 01599 } 01600 01601 const mcText *mcExpElementHelpers::math_GetConstSub() const 01602 { 01603 // if exponent does not exist, then return an empty mcText 01604 if (data_GetSub() == NULL) 01605 return mcText::math_pEmpty; 01606 return (const mcText *)data_GetSub(); 01607 }*/ 01608 01609 mcRealValue mcExpElementHelpers::math_EvaluateExp() const 01610 { 01611 // WARNING: we cannot just call data_GetExp()->math_Evaluate() 01612 // because if the exponent is not present, the function 01613 // would call mcNumber::math_pOne.math_Evaluate() 01614 // which would then call mcExpElementHelpers::math_Evaluate() 01615 // resulting in an infinite loop... 01616 if (!math_hasExp()) 01617 return 1.0; 01618 return data_GetExp().math_Evaluate(); 01619 } 01620 01621 mcRealValue mcExpElementHelpers::math_Evaluate() const 01622 { 01623 mcRealValue base = math_EvaluateBase(); 01624 mcRealValue exp = math_EvaluateExp(); 01625 01626 // now, just raise the base to the exp; just be sure that everything 01627 // is valid: if you try pow(*mcRealValue::pNAN, -1) you will get an exception !!! 01628 if (base.isNAN() || 01629 exp.isNAN()) 01630 return *mcRealValue::pNAN; 01631 return base.pow(exp); 01632 } 01633 01634 mcExpSimRes mcExpElementHelpers::math_Simplify(long flags, mcElement *pnew) 01635 { 01636 // no exp ? no simplifications to do for the exponent... 01637 if (!math_hasExp()) 01638 return math_SimplifyBase(flags, pnew); 01639 01640 // simplify exponent 01641 mcMATHLOG(wxT("mcExpElementHelpers::math_Simplify [%s]"), mcTXTTHIS); 01642 mcExpSimRes r = data_GetExp().math_Simplify(mcEXPSIM_NOFLAGS, NULL); 01643 01644 switch (r) { 01645 case mcESR_DONE: 01646 return math_SimplifyExp(flags, pnew); 01647 01648 case mcESR_INVALID_DATA: 01649 case mcESR_NOTFINISHED: 01650 return r; 01651 01652 case mcESR_DELETE_THIS: 01653 01654 // delete the exponent 01655 data_DestroyExpSub(TRUE); 01656 break; 01657 01658 case mcESR_REPLACE_THIS: 01659 case mcESR_DISTRIBUTE: 01660 break; 01661 01662 default: 01663 mcASSERT(0, wxT("Unhandled return flag")); 01664 } 01665 01666 return mcESR_DONE; 01667 } 01668 01669 mcExpSimRes mcExpElementHelpers::math_Expand(long flags, mcElement *newelem) 01670 { 01671 return math_ExpandBase(flags, newelem); 01672 01673 //return mcESR_NOTFINISHED; 01674 } 01675 01676 mcExpSimRes mcExpElementHelpers::math_SimplifyExp(long flags, mcElement *pnew) 01677 { 01678 // if the exponent cannot be evaluated, we'll get a NAN as result 01679 mcRealValue d = data_GetExp().math_Evaluate(); 01680 01681 if (d == 0.0) { 01682 01683 // we can simplify the base, whatever it is, to one... 01684 mcNumber replacement(*mcNumberHelpers::smath_pOne); 01685 (*pnew) = replacement; 01686 return mcESR_REPLACE_THIS; 01687 } 01688 01689 if (d > 0.0 && d < 1.0 && smath_bConvertToRadicalWhenPossible) { 01690 01691 mcRadical replacement; 01692 mcExpElement copy(this); 01693 01694 // convert this mcExpElement into a mcRadical 01695 copy.data_DestroyExpSub(TRUE); 01696 replacement.data_GetContent().math_WrapSimple(copy); 01697 01698 (*pnew) = replacement; 01699 return mcESR_REPLACE_THIS; 01700 } 01701 01702 if (d == 1.0) { 01703 01704 // just check if the exponent is containing a simple mcNumber("1.0") 01705 // (using the math_Evaluate() function we cannot be sure...); 01706 // if it is, then remove the exponent... 01707 if (math_GetConstExp().data_GetCount() == 1) { 01708 mcMonomial m(math_GetConstExp().data_GetElemOfType(0, mcET_MONOMIAL)); 01709 01710 if (m.data_GetCount() == 1 && 01711 m.data_Get(0).data_GetType() == mcET_NUMBER) 01712 data_DestroyExpSub(TRUE); 01713 } 01714 01715 return mcESR_DONE; 01716 } 01717 01718 // the exponent cannot be evaluated or, if it is, it does not 01719 // evaluate to any special value which allow us special simplification, 01720 // so we can just try to call the base/exp simplification routine... 01721 return math_SimplifyBaseExp(flags, pnew); 01722 } 01723 01724 mcBasicOpRes mcExpElementHelpers::math_RaiseTo(const mcPolynomial &p) 01725 { 01726 mcMATHLOG(wxT("mcExpElementHelpers::math_RaiseTo [%s] - raising to [%s]"), 01727 mcTXTTHIS, mcTXT(p)); 01728 math_GetExp().math_SimpleMultiplyBy(p); 01729 01730 return mcBOR_REMOVE_OPERAND; 01731 } 01732 01733 bool mcExpElementHelpers::math_CompareExp(const mcExpElement &p, long flags) const 01734 { 01735 if (!this->math_hasExp() && !p.math_hasExp()) 01736 return TRUE; // exponent is missing for both 01737 01738 // compare the two exponents 01739 const mcPolynomial &exp = p.math_GetConstExp(); 01740 return math_GetExp().math_Compare(exp, flags); 01741 } 01742 01743 bool mcExpElementHelpers::math_CompareSub(const mcExpElement &p, long flags) const 01744 { 01745 if (!this->math_hasSub() && !p.math_hasSub()) 01746 return TRUE; // exponent is missing for both 01747 01748 // compare the two exponents 01749 return data_GetSub().math_Compare(p.data_GetSub(), flags); 01750 } 01751 01752 bool mcExpElementHelpers::math_Compare(const mcElement &p, long flags) const 01753 { 01754 // first of all discard the most common case 01755 if (data_GetType() != p.data_GetType()) 01756 return FALSE; 01757 01758 mcExpElement e(p); 01759 01760 // then, check the bases 01761 if (!math_CompareThisOnly(e, flags)) 01762 return FALSE; 01763 01764 // check the subscript 01765 if (!math_CompareSub(e, flags)) 01766 return FALSE; 01767 01768 // last, check the exponent 01769 if (!math_CompareExp(e, flags)) 01770 return FALSE; 01771 01772 // ok; the two elements are identic 01773 // (and their children, too) 01774 return TRUE; 01775 } 01776 01777 mcBasicOpRes mcExpElementHelpers::math_MakeReciprocal(mcElement *) 01778 { 01779 // just multiply our exponent by -1..... that is, change the sign of the 01780 // exponent (a quicker operation respect to the * -1) 01781 math_GetExp().math_ChangeAllSigns(); 01782 01783 return mcBOR_REMOVE_OPERAND; 01784 } 01785 01786 mcBasicOpRes mcExpElementHelpers::math_MultOrDiv(const mcElement &e, mcElement *pp, bool mult) 01787 { 01788 mcMATHLOG(wxT("mcExpElementHelpers::math_MultOrDiv - %s [%s] by [%s]"), 01789 (mult ? wxT("multiplying") : wxT("dividing")), mcTXTTHIS, mcTXT(e)); 01790 mcExpElement p(e); 01791 01792 // get the exponents 01793 const mcPolynomial &exp1 = math_GetConstExp(); 01794 const mcPolynomial &exp2 = p.math_GetConstExp(); // don't create exp if not necessary... 01795 mcASSERT(exp1.math_CanBeAddedWith(exp2), 01796 wxT("Two polynomials that cannot be added ?!?")); 01797 01798 // check if the two bases are the same: 01799 // 01800 // x^n * x^m = x^(n+m) or x^n / x^m = x^(n-m) 01801 // 01802 // where x is not necessary a mcSymbol, just the base of this mcExpElement 01803 if (math_CompareThisOnly(p, FALSE)) { 01804 01805 // catch this simple case; otherwise we would see a lot of 01806 // passages like: 01807 // kx/k -. k^(1-1)x 01808 // which can damage readability 01809 if ((!this->math_hasExp() && !p.math_hasExp()) || 01810 exp1.math_Compare(exp2, FALSE)) { 01811 01812 // since the two exponents are identic, the result of this 01813 // operation is: 01814 // 01815 // x^n * x^n = x^2n or x^n / x^n = x^0 = 1 01816 // 01817 if (mult) 01818 math_GetExp().math_SimpleMultiplyBy(*mcNumberHelpers::smath_pTwo); 01819 else 01820 math_GetExp().math_ResetToZero(); 01821 01822 mcMATHLOG(wxT("mcExpElementHelpers::math_MultOrDiv - result is [%s]"), mcTXTTHIS); 01823 return mcBOR_REMOVE_OPERAND; 01824 } 01825 01826 // the two bases are identic: we can add/subtract the exponents 01827 // (if they are present) 01828 if (mult) 01829 data_GetExp().math_SimpleAdd(exp2); 01830 else 01831 data_GetExp().math_SimpleSubtract(exp2); 01832 01833 mcMATHLOG(wxT("mcExpElementHelpers::math_MultOrDiv - result is [%s]"), mcTXTTHIS); 01834 return mcBOR_REMOVE_OPERAND; 01835 } 01836 01837 // check if the two exponents are the same... 01838 // 01839 // x^n * y^n = (x*y)^n or x^n / y^n = (x/y)^n 01840 // 01841 if (exp1.math_Compare(exp2, FALSE)) { 01842 01843 // the two exponents are identic: we can mult/divide the bases... 01844 if (mult) 01845 return math_MultiplyBaseOnlyBy(p, pp); 01846 else 01847 return math_DivideBaseOnlyBy(p, pp); 01848 } 01849 01850 // no quick operations can be done 01851 if (mult) 01852 return math_MultiplyBaseBy(p, pp); 01853 return math_DivideBaseBy(p, pp); 01854 } 01855 01856 mcBasicOpRes mcExpElementHelpers::math_DivideBy(const mcElement &e, mcElement *pp) 01857 { 01858 mcASSERT(math_CanBeDivBy(e), 01859 wxT("This element cannot be divided by the given one")); 01860 return math_MultOrDiv(e, pp, FALSE); 01861 } 01862 01863 mcBasicOpRes mcExpElementHelpers::math_MultiplyBy(const mcElement &e, mcElement *pp) 01864 { 01865 mcASSERT(math_CanBeMultWith(e), 01866 wxT("This element cannot be multiplied by the given one")); 01867 return math_MultOrDiv(e, pp, TRUE); 01868 } 01869 01870 mcMathType mcExpElementHelpers::math_GetMathType() const 01871 { 01872 // if this element does not have an exponent, a call to 01873 // data_GetExp()->math_GetMathType(); would end in 01874 // a stack overflow since mcPolynomial::math_GetMathType 01875 // would probably call mcExpElementHelpers::math_GetMathType... 01876 if (!math_hasExp()) 01877 return math_GetBaseMathType(); 01878 01879 mcMathType res = math_GetExp().math_GetMathType(); 01880 return math_GetBaseMathType().math_RaiseTo(res); 01881 } 01882 01883 mcMonomial mcExpElementHelpers::math_GetBaseLCM(const mcElement &p) const 01884 { 01885 // just multiply ourselves with the given element 01886 mcExpElement res(this); 01887 mcMonomial m; 01888 01889 m.data_AddElements(&res, 1); 01890 res.math_SimpleMultiplyBy(p); 01891 01892 return m; 01893 } 01894 01895 mcMonomial mcExpElementHelpers::math_GetLCM(const mcElement &p) const 01896 { 01897 mcExpElement e(p); 01898 01899 if (!math_CompareThisOnly(p, FALSE)) { 01900 01901 // the bases are different thus we need to use 01902 // a specific algorithm for this element... 01903 return math_GetBaseLCM(p); 01904 } 01905 01906 mcMonomial m; 01907 if (!this->math_hasExp()) { 01908 mcExpElement res(p); 01909 m.data_AddElements(&res, 1); 01910 return m; 01911 } 01912 01913 if (!e.math_hasExp()) { 01914 mcExpElement res(this); 01915 m.data_AddElements(&res, 1); 01916 return m; 01917 } 01918 01919 // we both have an exponent: then just take the lcm between them 01920 mcElement exp = math_GetExp().math_GetLCM(e.data_GetExp()); 01921 mcExpElement res(this); 01922 01923 res.data_SetExpSub(TRUE, exp); 01924 m.data_AddElements(&res, 1); 01925 01926 mcMATHLOG(wxT("mcExpElementHelpers::math_GetLCM - the lcm between [%s] and [%s] is [%s]"), 01927 mcTXTTHIS, mcTXT(p), mcTXT(res)); 01928 01929 return m; 01930 } 01931 01932 mcMonomial mcExpElementHelpers::math_GetGCD(const mcElement &p) const 01933 { 01934 mcExpElement e(p); 01935 01936 if (data_GetType() != p.data_GetType()) 01937 return *mcMonomialHelpers::smath_pOne; 01938 01939 if (math_CompareThisOnly(p, FALSE)) { 01940 01941 // if both the two elements have the same base and they 01942 // both have an exponent, then we can just use mcPolynomial's GCD 01943 // function to get the GCD between the exponents... 01944 if (math_hasExp() && e.math_hasExp()) { 01945 01946 mcMonomial res; 01947 01948 // build an element with the same base of *this (which should 01949 // be also the same base of p) and with an exponent set to the 01950 // GCD of the two exponents 01951 mcExpElement content(this); 01952 mcMonomial gcd(math_GetExp().math_GetGCD(e.math_GetExp())); 01953 content.data_CreateExpSub(TRUE); 01954 content.math_GetExp().data_AddElements(&gcd, 1); 01955 01956 res.data_AddElements(&content, 1); 01957 return res; 01958 01959 } else { 01960 01961 // let the derived class overload only this piece of the algorithm 01962 return math_GetBaseGCD(p); 01963 } 01964 } 01965 01966 return *mcMonomialHelpers::smath_pOne; 01967 } 01968 01969 mcMonomial mcExpElementHelpers::math_GetBaseGCD(const mcElement &p) const 01970 { 01971 mcASSERT(!math_hasExp() || !mcExpElement(p).math_hasExp(), 01972 wxT("This case should have been handled by mcExpElementHelpers::math_GetGCD")); 01973 mcMonomial res; 01974 01975 // put into the monomial to return a copy of the element 01976 // without the exponent... 01977 if (math_hasExp()) 01978 res.data_AddElements(&p, 1); 01979 else { 01980 mcElement tmp(this); 01981 res.data_AddElements(&tmp, 1); 01982 } 01983 01984 return res; 01985 } 01986 01987
[ Top ] |