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("⁡")); 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
[ Top ] |