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

ExpElement.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 // 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 


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

[ Top ]