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

Function.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 "Function.cpp"
00037 #endif
00038 
00039 // includes
00040 #include "mc/mcprec.h"
00041 #include <wx/filename.h>
00042 #ifdef __BORLANDC__
00043     #pragma hdrstop
00044 #endif
00045 
00046 #ifndef mcPRECOMP
00047  #include <wx/textfile.h>
00048  #include <wx/gdicmn.h>
00049  //#include <math.h>
00050  
00051  #include "mc/MathCore.h"  // mathcore includes
00052  #include "mc/Function.h"
00053  #include "mc/Symbol.h"
00054  #include "mc/Number.h"
00055 #endif
00056 
00057 
00058 mcIMPLEMENT_MAIN_CLASS(mcFunction, mcExpElement);
00059 
00060 
00061 // setup customizable variables
00062 int mcFunctionHelpers::sgui_nSpaceLeftRight = 0;
00063 int mcFunctionHelpers::sgui_nSpaceAboveBelow = 0;
00064 
00065 // init the array containing all scripted functions.
00066 // the "mc" prefix will be stripped out all functions name, if present
00067 #ifdef mcUSE_WXSCRIPT
00068 wxScriptFunctionArray mcFunction::arrFunctions(wxT("mc"));
00069 #else
00070 wxScriptFunctionArray mcFunction::arrFunctions;
00071 #endif
00072 
00073 // This is the special key which must be used to create a new fraction
00074 // through the mcElementGUI input system.
00075 // This is not a simple CTRL+SHIFT+F combination because gui_isBeginKey() will
00076 // return TRUE only if the given key is set as a special key.
00077 mcKey *mcFunctionHelpers::sgui_pNewFunction = NULL;
00078 
00079 
00080 
00081 
00082 // ----------------------------------------
00083 // mcFUNCTION
00084 // ----------------------------------------
00085 
00086 int mcFunction::data_GetFunctionType(mcElement *s, int n)
00087 {
00088  wxString str;
00089 
00090  // first of all, convert the given sequence of mcSymbols to
00091  // one single string
00092  for (int i=0; i < n; i++) {
00093   if (s[i].data_GetType() == mcET_SYMBOL) {
00094    
00095    // this is a mcSymbol, add it to the string
00096    str += mcSymbol(s[i]).data_GetSymbol();
00097 
00098   } else {
00099    
00100    // all the elements should be mcSymbols...
00101    return mcFUNCTION_TYPE_NOTFOUND;
00102   }
00103  }
00104 
00105  // then try to find a function with the name we built
00106  return data_GetFunctionType(str);
00107 }
00108 
00109 int mcFunction::data_GetFunctionType(const wxString &str)
00110 {
00111 #ifdef mcUSE_WXSCRIPT
00112  // check the given string against all the registered functions
00113  for (int f=0; f < (int)arrFunctions.GetCount(); f++) {
00114   
00115   // get function name, removing eventually the "mc" prefix
00116   // at the beginning of the string...
00117   wxString tmp = mcFunction::arrFunctions.GetName(f);  
00118   if (str.Left(tmp.Len()) == tmp)
00119    return f;
00120  }
00121 #endif
00122 
00123  // no matching function names found...
00124  return mcFUNCTION_TYPE_NOTFOUND;
00125 }
00126 
00127 bool mcFunction::LoadScriptFile(const wxString &name)
00128 {
00129 #ifdef mcUSE_WXSCRIPT
00130  wxScriptFile *f = NULL;
00131 
00132  // load the given file
00133  if ((f = wxScriptInterpreter::Load(name)) == NULL)
00134   return FALSE;
00135 
00136  // append file's contents to the global array
00137  wxScriptFunctionArray arr;
00138  wxScriptInterpreter::GetTotalFunctionList(arr);
00139 
00140  // preserve old strip-off string
00141  wxString str = arrFunctions.GetPrefixToStrip();
00142  arrFunctions.DeepCopy(&arr);
00143  arrFunctions.SetPrefixToStrip(str);
00144 
00145  // cleanup
00146  mcSAFE_DELETE(f);
00147 
00148  return TRUE;
00149 
00150 #else
00151 
00152  // cannot load anything without wxscript
00153  return FALSE;
00154 #endif
00155 }
00156 
00157 
00158 
00159 
00160 
00161 // ----------------------------------------
00162 // mcFUNCTIONDATA
00163 // ----------------------------------------
00164 
00165 #ifdef __MCDEBUG__
00166 
00167 wxString mcFunctionHelpers::data_BaseDebug(long flags) const
00168 {
00169  int n = mcMathCore::Get()->m_nIndentationStep;
00170 
00171  return wxT("mcFunction [\n") + 
00172   data_GetNameObj().data_GetDebug(n, flags) +
00173   data_GetArgObj().data_GetDebug(n, flags) + 
00174   wxT("----------------------------------------- mcFunction ]");
00175 }
00176 
00177 #endif
00178 
00179 void mcFunctionHelpers::data_CreateSub()
00180 {
00181  data_DestroyExpSub(FALSE);
00182 
00183  mcPolynomial mysub;
00184  mdata_pSub = mysub;
00185  mdata_pSub.gui_SetAsExpOf(this);
00186 }
00187 
00188 void mcFunctionHelpers::data_SetFncType(int n)
00189 {
00190  mdata_nFncType = n;
00191 
00192  // change the name accordingly
00193  wxString newname;
00194 
00195  if (n == mcFUNCTION_TYPE_NOTSET)
00196   newname = wxEmptyString;
00197  else
00198 #ifdef mcUSE_WXSCRIPT
00199  newname = mcFunction::arrFunctions.GetName(mdata_nFncType);
00200 #else
00201  newname = wxT("fnc");
00202 #endif
00203 
00204  // change function name
00205  data_SetName(newname);
00206 }
00207 
00208 wxString mcFunctionHelpers::data_GetName() const
00209 {
00210  // get the name from the mcText which holds it...
00211  wxString name = data_GetNameObj().data_GetText().RemoveLast();
00212  return name;
00213 }
00214 
00215 void mcFunctionHelpers::data_CheckName()
00216 {
00217 #ifdef mcUSE_WXSCRIPT
00218  wxString ret = mcFunction::arrFunctions.GetName(mdata_nFncType);
00219 
00220  // do a little check
00221  mcASSERT(ret == data_GetName(), wxT("hmmm, something wrong"));
00222 #endif
00223 }
00224 
00225 wxScriptFunction *mcFunctionHelpers::data_GetScript() const
00226 {
00227 #ifdef mcUSE_WXSCRIPT
00228  return mcFunction::arrFunctions.Get(data_GetFncType());
00229 #else
00230  return NULL;
00231 #endif
00232 }
00233 
00234 
00235 
00236 
00237 
00238 // ----------------------------------------
00239 // mcFUNCTIONGUI
00240 // ----------------------------------------
00241 
00242 void mcFunctionHelpers::gui_DoRecalcBaseSize()
00243 {
00244  data_GetNameObj().gui_RecalcSize();
00245  data_GetArgObj().gui_RecalcSize();
00246 
00247  // calc the size of the function name
00248  // add to it the width of the argument
00249  mgui_szBase.SetWidth(mcMAX(gui_GetNameOffsetx()+gui_GetSizeOfName().GetWidth(), 
00250   gui_GetArgOffsetx()+gui_GetSizeOfArg().GetWidth()));
00251 
00252  // and choose the maximum height...
00253  mgui_szBase.SetHeight(mcMAX(gui_GetNameOffsety()+ gui_GetSizeOfName().GetHeight(), 
00254   gui_GetArgOffsety()+gui_GetSizeOfArg().GetHeight()));
00255 }
00256 
00257 mcInputRes mcFunctionHelpers::gui_BaseInput(const mcKey &key, mcElement *pnew)
00258 {
00259  mcInputRes res = mcIR_OKAY;
00260  int n;
00261 
00262  // discard the begin character used to create this element
00263  if (gui_isBeginKey(key) != FALSE && 
00264   !data_hasProperty(mcEP_INITIALIZED)) {
00265 
00266   // this element is now ready for input
00267   Init();
00268 
00269   return mcIR_OKAY;
00270  }
00271 
00272  switch (mgui_nCursorPos) {
00273  case mcFUNCTION_INSIDENAME:
00274   
00275   // handle the EDITEXP and EDITSUBSCRIPT keypresses
00276   if (gui_HandleSubExpEditKeys(key) == mcIR_OKAY)
00277    return mcIR_OKAY;
00278 
00279   res = data_GetNameObj().gui_Input(key, pnew);
00280 
00281   // recheck if the name matches one of the registered functions...
00282   n=mcFunction::data_GetFunctionType(data_GetName());
00283 
00284   // we allow the user to create mcFunctions with names which are
00285   // not on the registered function list...
00286   // note: we need to check if the n-th type of function have the
00287   //       same name we currently have since data_GetFunctionType()
00288   //       consider wxT("cosec") == "cos" (required to make IO function work)
00289   if (n!=mcFUNCTION_TYPE_NOTFOUND && 
00290    mcFunction::arrFunctions.GetName(n) == data_GetName())
00291    data_SetFncType(n);
00292   else
00293    mdata_nFncType = -1;
00294 
00295   // sometimes, mcText doesn't return mcIR_DELETE_THIS when it's empty...
00296   if (data_GetName().IsEmpty())
00297    res = mcIR_DELETE_THIS;
00298 
00299   // handle the mcText return flags
00300   switch (res) {
00301   case mcIR_OKAY:
00302   case mcIR_DELETE_PREVIOUS:   
00303    break;
00304 
00305   case mcIR_DELETE_NEXT:
00306    mcMathCore::Get()->SyntaxError(wxT("Cannot delete this bracket"));
00307    res = mcIR_OKAY;
00308    break;
00309 
00310   case mcIR_DIRECT_DELETE:
00311   case mcIR_REPLACE_THIS:
00312   case mcIR_DELETE_THIS:
00313    return mcIR_DELETE_THIS;
00314   }
00315   break;
00316 
00317  case mcFUNCTION_INSIDEARG:
00318   res = data_GetArgObj().gui_Input(key, pnew);
00319 
00320   // a little adjustment...
00321   if (res == mcIR_DISTRIBUTE)
00322    res = mcIR_DELETE_THIS;
00323   break;
00324 
00325  default:
00326   mcASSERT(0, wxT("unhandled cursor pos"));
00327  }
00328 
00329  gui_RecalcSize();
00330 
00331  return res;
00332 }
00333 
00334 int mcFunctionHelpers::gui_DrawBase(wxDC &hDC, int Offsetx, int Offsety, 
00335          long flags, const wxPoint &pt) const
00336 {
00337  long fname=mcDRW_USEPOINT, farg=mcDRW_USEPOINT;
00338  wxPoint ptname = pt, ptarg = pt;
00339  int r = 0;
00340 
00341  // locate the cursor
00342  wxPoint nameorg(Offsetx+gui_GetNameOffsetx(), Offsety+gui_GetNameOffsety());
00343  wxPoint argorg(Offsetx+gui_GetArgOffsetx(), Offsety+gui_GetArgOffsety());
00344 
00345  if (flags & mcDRW_USEPOINT) {
00346 
00347   // if we must find where the point is placed, we need those rects
00348   wxRect namerc(nameorg, gui_GetSizeOfName());
00349   wxRect argrc(argorg, gui_GetSizeOfArg());
00350 
00351   if (namerc.Inside(pt)) {
00352 
00353    // if something must be drawn as active, 
00354    // it is not the name of the function...
00355    farg = mcDRW_NONACTIVE;
00356    ptarg = wxDefaultPosition;
00357 
00358   } else if (argrc.Inside(pt)) {
00359 
00360    r = 1;
00361    ptname = wxDefaultPosition;
00362    fname = mcDRW_NONACTIVE;
00363   }
00364  }
00365 
00366  // draw the function name
00367  // (overriding default color if this function is unregistered)
00368  bool breg = data_isRegistered();
00369  data_GetNameObj().gui_Draw(hDC, nameorg.x, nameorg.y, 
00370          fname, /*ptname,*/0, (breg ? NULL : wxRED));
00371 
00372  // draw the argument
00373  int r2 = data_GetArgObj().gui_Draw(hDC, argorg.x, argorg.y, farg, ptarg);
00374 
00375  // then return the right ID
00376  return (r == 0 ? data_GetID() : r2);
00377 }
00378 
00379 mcInsertRes mcFunctionHelpers::gui_BaseInsert(const mcElement &toinsert, mcElement *newelem)
00380 {
00381  return mcINSR_OKAY;
00382 }
00383 
00384 mcMoveCursorRes mcFunctionHelpers::gui_BaseMoveCursor(mcMoveCursorFlag flag, long modifiers)
00385 {
00386  mcMoveCursorRes res;
00387 
00388  switch (mgui_nCursorPos) {
00389  case mcFUNCTION_INSIDENAME:
00390   res = data_GetNameObj().gui_MoveCursor(flag, modifiers);
00391 
00392   switch (res) {
00393   case mcMCR_OKAY:
00394    break;
00395 
00396   case mcMCR_SETFOCUS_PREVIOUS:
00397   case mcMCR_SETFOCUS_ABOVE:
00398   case mcMCR_SETFOCUS_BELOW:
00399    return res;
00400 
00401   case mcMCR_SETFOCUS_NEXT:
00402 
00403    if (data_hasProperty(mcEP_HASEXPONENT))
00404     gui_EditExpSub(TRUE);
00405    else if (data_hasProperty(mcEP_HASSUBSCRIPT))
00406     gui_EditExpSub(FALSE);
00407    else {
00408     
00409     mgui_nCursorPos = mcFUNCTION_INSIDEARG;
00410     data_GetArgObj().gui_SetCursorPos(mcCP_BEGIN);
00411     gui_BaseMoveCursor(mcMCF_RIGHT, modifiers);
00412    }
00413    break;
00414 
00415   default:
00416    mcASSERT(0, wxT("unhandled cursor pos"));   
00417   }
00418   break;
00419 
00420 
00421  case mcFUNCTION_INSIDEARG:
00422   res = data_GetArgObj().gui_MoveCursor(flag, modifiers);
00423 
00424   switch (res) {
00425   case mcMCR_OKAY:
00426    break;
00427 
00428   case mcMCR_SETFOCUS_NEXT:
00429   case mcMCR_SETFOCUS_ABOVE:
00430   case mcMCR_SETFOCUS_BELOW:
00431    return res;
00432 
00433   case mcMCR_SETFOCUS_PREVIOUS:
00434    mcASSERT(0, wxT("the cursor should never be placed on the leftmost point ")
00435     wxT("of the bracket: see the end of this function"));
00436 
00437    /* mgui_nCursorPos = mcFUNCTION_INSIDENAME;
00438     data_GetNameObj().gui_SetCursorPos(mcCP_END);
00439     gui_BaseMoveCursor(mcMCF_LEFT);*/
00440    break;
00441 
00442   default:
00443    mcASSERT(0, wxT("unhandled cursor pos"));   
00444   }
00445   break;
00446 
00447  default:
00448   mcASSERT(0, wxT("unhandled cursor pos"));
00449  }
00450 
00451  // cursor cannot be placed on the leftmost position of the
00452  // argument...
00453  if (mgui_nCursorPos == mcFUNCTION_INSIDEARG &&
00454   data_GetArgObj().gui_GetCursorPos().isBegin()) { 
00455   
00456   if (data_hasProperty(mcEP_HASEXPONENT))
00457    gui_EditExpSub(TRUE);
00458   else if (data_hasProperty(mcEP_HASSUBSCRIPT))
00459    gui_EditExpSub(FALSE);
00460   else {
00461    
00462    mgui_nCursorPos = mcFUNCTION_INSIDENAME;
00463    data_GetNameObj().gui_SetCursorPos(mcCP_END);
00464   }
00465  }
00466 
00467  return mcMCR_OKAY;
00468 }
00469 
00470 mcMoveCursorRes mcFunctionHelpers::gui_MoveCursor(mcMoveCursorFlag flag, long modifiers)
00471 {
00472  mcMoveCursorRes n = mcMCR_OKAY;
00473 
00474  mcASSERT(mgui_bExpRight, wxT("A function should always have the exponent ")
00475        wxT("placed on the right of the function name"));
00476 
00477  if (gui_isCursorInExpSub(TRUE)) {
00478 
00479   n = gui_ExpSubMoveCursor(TRUE, flag, modifiers);
00480 
00481  } else if (gui_isCursorInExpSub(FALSE)) {
00482 
00483   n = gui_ExpSubMoveCursor(FALSE, flag, modifiers);
00484 
00485  } else if (gui_isCursorInBase()) {
00486 
00487   mcMoveCursorRes r = gui_BaseMoveCursor(flag, modifiers);
00488 
00489   switch (r) {
00490   case mcMCR_SETFOCUS_NEXT:
00491   case mcMCR_SETFOCUS_PREVIOUS:
00492   case mcMCR_CANNOT_SETFOCUS:
00493   case mcMCR_OKAY:
00494    return r;
00495    
00496   case mcMCR_SETFOCUS_BELOW:
00497 
00498    // check if the subscript is present
00499    if (data_hasProperty(mcEP_HASSUBSCRIPT))
00500     gui_EditExpSub(FALSE);
00501    else
00502     return mcMCR_SETFOCUS_BELOW;
00503    break;
00504    
00505   case mcMCR_SETFOCUS_ABOVE:
00506 
00507    // check if the exponent is present
00508    if (data_hasProperty(mcEP_HASEXPONENT))
00509     gui_EditExpSub(TRUE);
00510    else
00511     return mcMCR_SETFOCUS_ABOVE;
00512    break;
00513   }
00514  }
00515 
00516  return n;
00517 }
00518 
00519 int mcFunctionHelpers::gui_BaseMoveCursorUsingPoint(wxDC &dc, const wxPoint &pt)
00520 {
00521  // check if the given point is in the name rect
00522 /* wxRect name(wxPoint(GetNameOffsetx(), GetNameOffsety()), gui_GetSizeOfName());
00523  if (name.Inside(*pt)) {
00524   
00525   // ... yes it is
00526   mgui_nCursorPos = mcFUNCTION_INSIDENAME;
00527   pt.x -= name.x;
00528   pt.y -= name.y;
00529   return data_GetNameObj().gui_MoveCursorUsingPoint(dc, pt);
00530   }
00531   
00532   // check if the given point is in the arg rect
00533   wxRect arg(wxPoint(GetArgOffsetx(), GetArgOffsety()), gui_GetSizeOfArg());
00534   if (arg.Inside(*pt)) {
00535   
00536    // ... yes it is
00537   mgui_nCursorPos = mcFUNCTION_INSIDEARG;
00538   pt.x -= arg.x;
00539   pt.y -= arg.y;
00540   return data_GetArgObj().gui_MoveCursorUsingPoint(dc, pt);
00541    }
00542     */
00543  return mcMCR_CANNOT_SETFOCUS;
00544 }
00545 
00546 int mcFunctionHelpers::gui_GetBaseRelCursorPos(wxDC &hDC, wxPoint *pt) const
00547 {
00548  int res = 0;
00549 
00550  switch (mgui_nCursorPos) {
00551  case mcFUNCTION_INSIDENAME:
00552   res = data_GetNameObj().gui_GetRelCursorPos(hDC, pt);
00553   pt->x += gui_GetNameOffsetx();
00554   pt->y += gui_GetNameOffsety();
00555   break;
00556 
00557  case mcFUNCTION_INSIDEARG:
00558   res = data_GetArgObj().gui_GetRelCursorPos(hDC, pt);
00559   pt->x += gui_GetArgOffsetx();
00560   pt->y += gui_GetArgOffsety();
00561   break;
00562 
00563  default:
00564   mcASSERT(0, wxT("unhandled cursor pos"));
00565  }
00566 
00567  return res;
00568 }
00569 
00570 void mcFunctionHelpers::gui_GetBaseCursorPos(mcCursorPos &cp) const
00571 {
00572  if (mgui_nCursorPos == mcFUNCTION_INSIDENAME &&
00573   data_GetNameObj().gui_GetCursorPos().isBegin()) {
00574   cp.gui_Push(mcCP_BEGIN);
00575   return;
00576  }
00577 
00578  // if the cursor is placed on the right of the last letter...
00579  if (mgui_nCursorPos == mcFUNCTION_INSIDEARG &&
00580   data_GetArgObj().gui_GetCursorPos().isEnd()) {
00581   cp.gui_Push(mcCP_END);
00582   return;
00583  }
00584 
00585  cp.gui_Push(mgui_nCursorPos);
00586 }
00587 
00588 void mcFunctionHelpers::gui_EditBase()
00589 {
00590  // move the cursor inside the name
00591  mgui_nCursorPos = mcFUNCTION_INSIDENAME;
00592  mgui_nCursorLoc = mcECL_INSIDEBASE;
00593 }
00594 
00595 void mcFunctionHelpers::gui_EditBaseAndSetPos(const mcCursorPos &cp)
00596 {
00597  gui_EditBase();
00598  data_GetNameObj().gui_SetCursorPos(cp);
00599 }
00600 
00601 void mcFunctionHelpers::gui_SetCursorPos(const mcCursorPos &code)
00602 {
00603  if (code.isBegin()) {
00604 
00605   // the leftmost point for this element is the leftmost point
00606   // of the name object of this function...
00607   mgui_nCursorPos = mcFUNCTION_INSIDENAME;
00608   data_GetNameObj().gui_SetCursorPos(mcCP_BEGIN);
00609 
00610  } else {
00611 
00612   // the rightmost point for this element is the rightmost point
00613   // of the argument
00614   mgui_nCursorPos = mcFUNCTION_INSIDEARG;
00615   data_GetArgObj().gui_SetCursorPos(mcCP_END); 
00616  }
00617 }
00618 
00619 void mcFunctionHelpers::gui_Setup(int fnc)
00620 {
00621  data_SetFncType(fnc);
00622 
00623  // a mcFunction is not allocated like the other mcElements:
00624  // a special function (mcMonomial::gui_ScanArrayForFunctions)
00625  // creates the mcFunctions which never receives the begin key
00626  // which doesn't exist through the gui_Input() function: so,
00627  // mcMonomial calls this function to init the element
00628  data_GetArgObj().data_GetContent().gui_AddNewEmptyMonomial();
00629 
00630  // we need a name; use the name of the first registered function
00631  mcASSERT(mcFunction::arrFunctions.GetCount() != 0, wxT("No function registered ?!?"));
00632  data_SetFncType(0);
00633 
00634  data_AddProperty(mcEP_INITIALIZED);
00635  gui_RecalcSize();
00636 }
00637 
00638 wxSize mcFunctionHelpers::gui_GetSizeOfArg() const
00639 { return data_GetArgObj().gui_GetSize(); }
00640 
00641 wxSize mcFunctionHelpers::gui_GetSizeOfName() const
00642 { return data_GetNameObj().gui_GetSize(); }
00643 
00644 
00645 
00646 
00647 // ARGUMENT offsets
00648 
00649 int mcFunctionHelpers::gui_GetArgOffsetx() const
00650 { return mcMAX(gui_GetExpSubOffsetx(TRUE)+gui_GetExpSubSize(TRUE).GetWidth(),
00651     gui_GetExpSubOffsetx(FALSE)+gui_GetExpSubSize(FALSE).GetWidth()); }
00652 
00653 int mcFunctionHelpers::gui_GetArgOffsety() const
00654 { return 0; }
00655 
00656 
00657 
00658 
00659 // NAME offsets
00660 
00661 int mcFunctionHelpers::gui_GetNameOffsetx() const
00662 { return 0; }
00663 
00664 int mcFunctionHelpers::gui_GetNameOffsety() const
00665 { return (gui_GetBaseSize().GetHeight() - gui_GetSizeOfName().GetHeight())/2; }
00666 
00667 
00668 
00669 // EXPONENT offsets
00670 
00671 int mcFunctionHelpers::gui_GetExpOffsetx() const
00672 { return gui_GetSizeOfName().GetWidth(); }
00673 
00674 int mcFunctionHelpers::gui_GetExpOffsety() const
00675 { return gui_GetNameOffsety(); }
00676 
00677 
00678 
00679 
00680 // SUBSCRIPT offsets
00681 
00682 int mcFunctionHelpers::gui_GetSubOffsetx() const
00683 { return gui_GetExpOffsetx(); }
00684 
00685 int mcFunctionHelpers::gui_GetSubOffsety() const
00686 { return gui_GetNameOffsety()+gui_GetSizeOfName().GetHeight(); }
00687 
00688 
00689 
00690 #define HANDLE_EXPSUB()           \
00691  switch (r) {            \
00692   case mcMCR_SETFOCUS_NEXT:        \
00693    mgui_nCursorPos = mcFUNCTION_INSIDEARG;    \
00694    data_GetArgObj().gui_SetCursorPos(mcCP_BEGIN);  \
00695    gui_BaseMoveCursor(mcMCF_RIGHT, modifiers);   \
00696    break;            \
00697                \
00698   case mcMCR_SETFOCUS_PREVIOUS:      \
00699    gui_EditBaseAndSetPos(mcCP_END);    \
00700    break;           \
00701                \
00702   case mcMCR_SETFOCUS_BELOW:       \
00703    gui_EditBase();         \
00704    break;           \
00705                \
00706   case mcMCR_SETFOCUS_ABOVE:       \
00707    return mcMCR_SETFOCUS_ABOVE;     \
00708  }
00709 
00710 mcMoveCursorRes mcFunctionHelpers::gui_ExpMoveCursor(mcMoveCursorFlag flag, long modifiers)
00711 {
00712  if (mgui_nCursorPos == mcECL_INSIDEEXPONENT) {
00713 
00714   // inside this branch we can always assume the exponent visible:
00715   // the cursor is inside it !!!
00716   int r = data_GetExp().gui_MoveCursor(flag, modifiers);
00717 
00718   HANDLE_EXPSUB();
00719 
00720  } else {
00721 
00722   // 
00723   mcASSERT(0, wxT("In a mcFunction, the cursor can be only placed on the base ")
00724    wxT("or _inside_ the exponent; never at the begin/end of the exp/sub"));
00725  }
00726 
00727  return mcMCR_OKAY;
00728 }
00729 
00730 
00731 void mcFunctionHelpers::gui_CheckSub()
00732 {
00733  mcPolynomial p = data_GetSub();
00734  if (p.data_isArrayEmpty())
00735   p.gui_AddNewEmptyMonomial();
00736 }
00737 
00738 mcMoveCursorRes mcFunctionHelpers::gui_SubMoveCursor(mcMoveCursorFlag flag, long modifiers)
00739 {
00740  if (mgui_nCursorPos == mcECL_INSIDESUBSCRIPT) {
00741 
00742   // inside this branch we can always assume the exponent visible:
00743   // the cursor is inside it !!!
00744   int r = data_GetSub().gui_MoveCursor(flag, modifiers);
00745 
00746   HANDLE_EXPSUB();
00747 
00748  } else {
00749   
00750   mcASSERT(0, wxT("In a mcFunction, the cursor can be only placed on the base ")
00751    wxT("or _inside_ the subscript; never at the begin/end of the exp/sub"));
00752  }
00753 
00754  return mcMCR_OKAY;
00755 }
00756 
00757 
00758 
00759 
00760 
00761 // ----------------------------------------
00762 // mcFUNCTIONIO
00763 // ----------------------------------------
00764 
00765 bool mcFunctionHelpers::io_isBeginChar(const wxString &str) const
00766 {
00767  // just use the STATIC version
00768  return io_isFunctionBeginChar(str);
00769 }
00770 
00771 bool mcFunctionHelpers::io_isFunctionBeginChar(const wxString &str)
00772 {
00773  int n = mcFunction::data_GetFunctionType(str);
00774  if (n != -1) {
00775   
00776   // the name of the function matches; now check if the 
00777   // bracket begin char is okay
00778 #ifdef mcUSE_WXSCRIPT
00779   int len = mcFunction::arrFunctions.GetName(n).Len();
00780 #else
00781   int len = 0;
00782 #endif
00783 
00784   wxString br = str.Right(str.Len()-len);
00785   for (int i=0; i < (int)br.Len(); i++)
00786    if (mcBracketHelpers::io_isBracketBeginChar(br.GetChar(i)))
00787     return TRUE;
00788   return FALSE;
00789  }
00790  
00791  return FALSE;
00792 }
00793 
00794 wxXml2Node mcFunctionHelpers::io_GetBaseMathML(bool bGetPresentation) const
00795 {
00796  // mcExpElement::io_GetMathML will add the exponent & subscript
00797  // to this node, using it as the base....
00798  wxXml2Node n = data_GetNameObj().io_GetMathML(bGetPresentation);
00799 
00800  // use the <MI> tag for the function name
00801  n.SetName(wxT("mi"));
00802  return n;
00803 }
00804 
00805 wxXml2Node mcFunctionHelpers::io_GetMathML(bool bGetPresentation) const
00806 {
00807  wxXml2Node maintag(wxXML_ELEMENT_NODE, wxXml2EmptyDoc, wxT("mrow"));
00808  wxXml2Node op(wxXML_TEXT_NODE, wxXml2EmptyDoc, wxT("mo"), wxT("&ApplyFunction;"));
00809  wxXml2Node exptag(mcExpElementHelpers::io_GetMathML(bGetPresentation));
00810  wxXml2Node arg(data_GetArgObj().io_GetMathML(bGetPresentation));
00811  
00812  // create the function name with, eventually, the subscript and
00813  // the exponent attached
00814  maintag.AddChild(exptag);
00815 
00816  // then, add the ApplyFunction operator
00817  maintag.AddChild(op);
00818 
00819  // and finally, the argument of the function...
00820  maintag.AddChild(arg);
00821  
00822  return maintag;
00823 }
00824 /*
00825 wxString mcFunctionHelpers::io_GetInlinedExpr() const
00826 {
00827  wxString str;
00828 
00829  // merge base (function name) and exponent only: subscript is
00830  // exported inside the base as a function argument.
00831 
00832  // to be sure that mcExpElement::io_GetInlinedExpr() const won't export
00833  // the exponent, we hide it...
00834  bool old = data_hasProperty(mcEP_HASEXPONENT);
00835  ().data_RemoveProperty(mcEP_HASEXPONENT);
00836 
00837  str = mcExpElement::io_GetInlinedExpr() const const;
00838 
00839  // ...and then restore it again
00840  if (old) ().data_AddProperty(mcEP_HASEXPONENT);
00841  
00842  return str;
00843 }*/
00844 
00845 wxString mcFunctionHelpers::io_GetBaseInlinedExpr() const
00846 {
00847  // as base, export the function name + the bracket
00848  wxString str = data_GetNameObj().io_GetInlinedExpr();
00849  str += data_GetArgObj().io_GetInlinedExpr();
00850 
00851  // and eventually, add as second argument the subscript
00852  if (data_hasProperty(mcEP_HASSUBSCRIPT)) {
00853 
00854   str.RemoveLast();
00855   str += wxT(", ") + data_GetSub().io_GetInlinedExpr();
00856  }
00857 
00858  // the exponent will be added at the end of "str":
00859  // if we bracketize it, then the exponent will be
00860  // referred to the entire function and not to the
00861  // argument only:
00862  // 
00863  //    sin^2x(ax)    would be confusing; better export to
00864  //    (sin(ax))^2x
00865  // 
00866  if (data_hasProperty(mcEP_HASEXPONENT)) {
00867 
00868   str.Prepend(wxT("("));
00869   str.Append(wxT(")"));
00870  }
00871 
00872  return str;
00873 }
00874 
00875 bool mcFunctionHelpers::io_ImportPresentationMathML(wxXml2Node tag, wxString &pErr)
00876 {
00877  mcASSERT(0, wxT(""));
00878  return TRUE;
00879 }
00880 
00881 void mcFunctionHelpers::io_GetExpSubInlinedToken(wxString &subexp)
00882 {
00883  // in these cases:
00884  //     fnc^2(arg)   or    fnc^2x(arg)
00885  // we must not import the first monomial we find, 
00886  // as mcExpElement::io_GetExpSubInlinedToken does:
00887  // we must import everything until we found the
00888  // left parenthesis which delimits the argument contents...
00889  subexp = subexp.BeforeFirst(wxT('+'));
00890  subexp = subexp.BeforeFirst(wxT('-'));
00891  subexp = subexp.BeforeFirst(wxT('('));
00892  return;
00893 }
00894 
00895 wxArrayString mcFunctionHelpers::io_ImportArgument(const wxString &arg, int *count, wxString &pErr)
00896 {
00897  wxArrayString argarr;
00898 
00899  // extract the argument
00900  if (!mcBracketHelpers::gui_isLeftParenthesis(arg.GetChar(0))) {
00901 
00902   // oooooops...
00903   pErr = wxT("a left parenthesis should be placed here");
00904   return argarr;
00905  }
00906 
00907  int i, nestlevel=0, begin=1; 
00908  for (i=0; i < (int)arg.Len(); i++) {
00909 
00910   // modify nestlevel
00911   if (mcBracketHelpers::gui_isLeftParenthesis(arg.GetChar(i))) nestlevel++;
00912   if (mcBracketHelpers::gui_isRightParenthesis(arg.GetChar(i))) nestlevel--;
00913 
00914   if (arg.GetChar(i) == wxT(',')) {
00915    
00916    argarr.Add(arg.Mid(begin, i-begin)); 
00917    begin = i+1;
00918   }
00919 
00920   if (nestlevel == 0) { i++; break; }
00921  }
00922 
00923  // remove the useless part of the argument
00924  argarr.Add(arg.Mid(begin, i-1-begin));
00925  *count = i;
00926 
00927  return argarr;
00928 }
00929 
00930 bool mcFunctionHelpers::io_ImportInlinedExpr(const wxString &str, int *count, wxString &pErr)
00931 {
00932  // find which function is this
00933  data_SetFncType(mcFunction::data_GetFunctionType(str));
00934  int n = data_GetFncType();
00935  mcASSERT(n != -1, wxT("Error in mcFunctionHelpers::io_isBeginChar"));
00936 
00937  // remove subscript/exponent from wxT("arg") and store it in "subexp" 
00938  wxString arg = str.Right(str.Len()-data_GetName().Len());
00939  wxString subexp(arg);
00940  io_GetExpSubInlinedToken(subexp);
00941  arg.Remove(0, subexp.Len());
00942 
00943  // get the arg string(s)
00944  wxArrayString args = io_ImportArgument(arg, count, pErr);
00945  if (args.IsEmpty()) return FALSE;
00946 
00947  // FIXME: how to make a generic multiple-arg function ?
00948  arg = args[0];
00949  arg = wxT("(") + arg + wxT(")"); // so it's okay for mcBracket
00950 
00951  // set all the characters we have or we must import
00952  *count = data_GetName().Len()+subexp.Len()+arg.Len();
00953 
00954  // now, import the argument of the function 
00955  if (!data_GetArgObj().io_ImportInlinedExpr(arg, &n, pErr))
00956   return FALSE;
00957  mcASSERT((int)arg.Len() == n, 
00958   wxT("The argument has not been completely imported..."));
00959 
00960  // and then, the subscript/exponent
00961  bool bexp = (subexp.GetChar(0) == wxT('^'));
00962  bool bsub = (subexp.GetChar(0) == wxT('_'));
00963  wxString toimport(subexp);
00964  toimport.Remove(0, 1);  // remove the wxT("^") or "_" symbol
00965  n = 0;
00966 
00967  // import the EXPONENT
00968  if (bexp) {
00969 
00970   // this call erases previous exponent (if present) and (if not
00971   // already present) creates it...
00972   data_CreateExpSub(TRUE);
00973 
00974   if (!data_GetExp().io_ImportInlinedExpr(toimport, &n, pErr))
00975    return FALSE;
00976  }
00977 
00978  // import the SUBSCRIPT
00979  if (bsub) {
00980 
00981   // this call erases previous sub (if present) and (if not
00982   // already present) creates it...
00983   data_CreateExpSub(FALSE);
00984 
00985   if (!data_GetSub().io_ImportInlinedExpr(toimport, &n, pErr))
00986    return FALSE;
00987  }
00988 
00989  mcASSERT((int)toimport.Len() == n, 
00990   wxT("Exp/sub has not been completely imported..."));
00991 
00992  // extra-work required ?
00993  io_PostProcessChildren();
00994 
00995  // ok, everything was okay
00996  mcIOLOG(wxT("mcFunctionHelpers::io_ImportInlinedExpr [%s]"), mcTXTTHIS);
00997  return TRUE;
00998 }
00999 
01000 
01001 
01002 
01003 // ----------------------------------------
01004 // mcFUNCTIONMATH
01005 // ----------------------------------------
01006 
01007 mcRealValue mcFunctionHelpers::math_EvaluateBase() const
01008 {
01009  mcRealValue arg = data_GetArgObj().math_Evaluate();
01010 
01011  // it's better not to apply the function on an invalid value...
01012  if (!arg.isValid())
01013   return *mcRealValue::pNAN;
01014 
01015 #ifdef mcUSE_WXSCRIPT
01016  wxScriptVar returnvalue, argument;
01017  argument.Set(wxSTG_DOUBLE, arg.GetDouble());
01018  if (!data_GetScript()->Exec(returnvalue, &argument))
01019   return *mcRealValue::pNAN;
01020 
01021  return returnvalue.GetContentDouble();
01022 
01023 #else
01024 
01025  return *mcRealValue::pNAN;
01026 
01027 #endif
01028 }
01029 
01030 mcExpSimRes mcFunctionHelpers::math_SimplifyBase(long flags, mcElement *pnew)
01031 {
01032  mcExpSimRes r = data_GetArgObj().math_Simplify(flags, pnew);
01033  if (r != mcESR_DONE) return r;
01034 
01035  // if our argument is constant, then we should be able
01036  // to replace this element with something else...
01037  if (data_GetArgObj().math_isConstant()) {
01038 
01039   // just replace this
01040   mcRealValue val = math_Evaluate();
01041   if (val == *mcRealValue::pNAN)
01042    return mcESR_DONE;  // for some reason we cannot...
01043 
01044   mcNumber replacement(val);
01045   (*pnew) = replacement;
01046   return mcESR_REPLACE_THIS;
01047  }
01048 
01049  return mcESR_DONE;
01050 }
01051 
01052 mcExpSimRes mcFunctionHelpers::math_ExpandBase(long flags, mcElement *pnew)
01053 {
01054  // we can just try to expand our argument
01055  return data_GetArgObj().math_Expand(flags, pnew);
01056  //return mcESR_DONE;
01057 }
01058 
01059 mcMathType mcFunctionHelpers::math_GetBaseMathType() const
01060 {
01061  // if we contain unknowns or parameters, we cannot be evaluated
01062  // and things get much, much more complex.
01063  mcMathType res = data_GetArgObj().math_GetMathType();;
01064 
01065  // FIXME: how do we check the type of the function we are ?
01066  return res;
01067 }
01068 
01069 
01070 


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

[ Top ]