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 "Bracket.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 <wx/dcscreen.h> 00047 #include "mc/Bracket.h" 00048 #include "mc/Monomial.h" 00049 #include "mc/Fraction.h" 00050 #endif 00051 00052 00053 mcIMPLEMENT_MAIN_CLASS(mcBracket, mcExpElement); 00054 00055 00056 // setup customizable variables 00057 int mcBracketHelpers::sgui_nSpaceLeftRight = 0; 00058 int mcBracketHelpers::sgui_nSpaceAboveBelow = 0; 00059 bool mcBracketHelpers::sgui_bCreateBothSymbols = FALSE; 00060 wxString mcBracketHelpers::sgui_strLeftParentheses = wxT("([{"); 00061 wxString mcBracketHelpers::sgui_strRightParentheses = wxT(")]}"); 00062 00063 00064 00065 00066 00067 00068 00069 // ---------------------------------------- 00070 // mcBRACKETDATA 00071 // ---------------------------------------- 00072 00073 wxString mcBracketHelpers::data_GetBracketLeftSymbol(int n) const 00074 { 00075 if (n == -1) n = data_ChooseBracketType(); 00076 00077 // return bracket symbols basing on m_nBracketType variable 00078 switch (n) { 00079 case mcBRACKET_SIMPLE_BRACKETS: 00080 return wxT("("); 00081 case mcBRACKET_SQUARE_BRACKETS: 00082 return wxT("["); 00083 default: 00084 return wxT("{"); 00085 } 00086 } 00087 00088 wxString mcBracketHelpers::data_GetBracketRightSymbol(int n) const 00089 { 00090 if (n == -1) n = data_ChooseBracketType(); 00091 00092 // return bracket symbols basing on m_nBracketType variable 00093 switch (n) { 00094 case mcBRACKET_SIMPLE_BRACKETS: 00095 return wxT(")"); 00096 case mcBRACKET_SQUARE_BRACKETS: 00097 return wxT("]"); 00098 default: 00099 return wxT("}"); 00100 } 00101 } 00102 00103 int mcBracketHelpers::data_ChooseBracketType() const 00104 { 00105 // reset the "bracket type tracker" 00106 int brtype = mcBRACKET_SIMPLE_BRACKETS; 00107 00108 // scan the array 00109 mcElementArray p(data_GetContent()); 00110 00111 // We are sure that the content is a mcPolynomial: it is 00112 // created by mcBracket and thus we can be sure of it. 00113 // Now, mcPolynomials, always contains mcMonomials, and we 00114 // must search for other brackets in the monomials of the 00115 // contained polynomial, NOT directly in the contained 00116 // polynomial 00117 for (int j=0; j < p.data_GetCount(); j++) { 00118 00119 if (p.data_Get(j).data_GetType() == mcET_MONOMIAL) { 00120 00121 // get a pointer to monomial's data 00122 mcElementArray m(p.data_Get(j)); 00123 00124 // now we can use the mcElementArrayData facilities 00125 // (GetElemOfType & GetNumOfElemType) 00126 for (int i=0, max=m.data_GetNumOfElemType(mcET_BRACKET); i < max; i++) { 00127 00128 mcBracket b(m.data_GetElemOfType(i, mcET_BRACKET)); 00129 brtype += b.data_GetBracketDepth(); 00130 } 00131 } 00132 } 00133 00134 return brtype; 00135 } 00136 00137 00138 00139 00140 // ---------------------------------------- 00141 // mcBRACKETGUI 00142 // ---------------------------------------- 00143 00144 int mcBracketHelpers::gui_GetContentOffsetY() const 00145 { 00146 // center bracket vertically 00147 return (mgui_szBracket.GetHeight() - data_GetContent().gui_GetHeight())/2; 00148 } 00149 00150 int mcBracketHelpers::gui_GetContentOffsetX() const 00151 { 00152 // just add the width of one bracket. 00153 return mgui_szBracket.GetWidth(); 00154 } 00155 00156 wxFont mcBracketHelpers::gui_RebuildFont(const mcElementHelpers *elem, int h) 00157 { 00158 wxFont fnt; 00159 00160 // using bracket's font & content height 00161 wxString str = elem->gui_GetStyleForThis()-> 00162 GetTextSettingsFor(mcET_ADDOP)->m_hFont.GetFaceName(); 00163 00164 fnt.SetFamily(wxSWISS); 00165 00166 #ifndef __WXGTK__ 00167 // this is really a problem for wxGTK: it seems that not all fonts 00168 // can accept any point-size. If we try to select an unsupported 00169 // point-size and then we use the font, we will get an error.... 00170 // this implies that brackets cannot change their parentheses 00171 // height on wxGTK.... sorry 00172 int n = h+mcBracketHelpers::sgui_nSpaceAboveBelow*2; 00173 fnt.SetFaceName(str); 00174 fnt.SetPointSize((int)mcElementHelpers::gui_Pixels2PointSize(n)); 00175 #endif 00176 00177 return fnt; 00178 } 00179 00180 void mcBracketHelpers::gui_DoRecalcBaseSize() 00181 { 00182 wxString tmp; 00183 wxScreenDC dc; 00184 00185 // compute size of content 00186 mgui_szBase = data_GetContent().gui_GetSize(); 00187 00188 // if required, update the font... 00189 if (mgui_szBase.GetHeight() != mgui_szBracket.GetHeight()) 00190 mgui_fLastFont = gui_RebuildFont(this, mgui_szBase.GetHeight()); 00191 00192 // now use the font to calculate bracket's height 00193 dc.SetFont(mgui_fLastFont); 00194 mgui_szBracket.Set(0, 0); 00195 mgui_szBracket = gui_GetSizeOf(&dc, data_GetBracketLeftSymbol()); 00196 mcASSERT(mgui_szBracket != wxSize(0, 0), wxT("Couldn't get bracket size")); 00197 00198 // update size member 00199 mgui_szBase.SetWidth(mgui_szBase.GetWidth() + mgui_szBracket.GetWidth()*2 + gui_GetSpaceLeftRight()*2); 00200 mgui_szBase.SetHeight(mgui_szBracket.GetHeight() + gui_GetSpaceAboveBelow()*2); 00201 } 00202 00203 void mcBracketHelpers::gui_DrawContainer(wxDC &hDC, int Offsetx, int Offsety, 00204 long flags, const wxPoint &pt) const 00205 { 00206 // we don't need to check the mouse position because we 00207 // do not want to highlight all the contained expression if the 00208 // cursor is over it or if it is over the parentheses; 00209 // instead, we highlight the part of the expression involved 00210 // (see the mcExpContainerHelpers::gui_Draw() function) 00211 mcUNUSED(pt); 00212 00213 // draw the bracket... we cannot use the std font to print '(' 00214 // or ')', because the contained expression can be taller or 00215 // shorter than the normal font height... 00216 mcElementHelpers::gui_SelectStyle(hDC); 00217 hDC.SetFont(mgui_fLastFont); 00218 00219 hDC.DrawText(data_GetBracketLeftSymbol(), Offsetx, Offsety); 00220 hDC.DrawText(data_GetBracketRightSymbol(), Offsetx+mgui_szBracket.GetWidth()+ 00221 data_GetContent().gui_GetWidth(), Offsety); 00222 } 00223 00224 mcInputRes mcBracketHelpers::gui_BaseInput(const mcKey &key, mcElement *pnew) 00225 { 00226 if (!sgui_bCreateBothSymbols) { 00227 00228 // intercept delete keypresses and create mcParenthesis 00229 // which replace the brackets... 00230 switch (mgui_nCursorPos) { 00231 case mcEXPCONTAINER_LEFTMOST: 00232 if (mcMathCore::Get()->m_pCancelKey->MatchKey(key)) 00233 return gui_OnRemoveLeftBracket(pnew); 00234 break; // proceed with normal processing 00235 00236 case mcEXPCONTAINER_RIGHTMOST: 00237 if (mcMathCore::Get()->m_pDeleteKey->MatchKey(key)) 00238 return gui_OnRemoveRightBracket(pnew); 00239 break; // proceed with normal processing 00240 } 00241 } 00242 00243 mcInputRes n = mcExpContainerHelpers::gui_BaseInput(key, pnew); 00244 00245 // all the inputs dropped to the contained polynomial, 00246 // can change the type of brackets of this class... 00247 if (mgui_nCursorPos == mcEXPCONTAINER_INSIDEEXPR) 00248 data_ChooseBracketType(); 00249 return n; 00250 } 00251 00252 mcInputRes mcBracketHelpers::gui_OnRemoveRightBracket(mcElement *pnew) 00253 { 00254 mgui_bRemoveLeftBracket = FALSE; 00255 *pnew = mcElement(this); 00256 return mcIR_DISTRIBUTE; 00257 } 00258 00259 mcInputRes mcBracketHelpers::gui_OnRemoveLeftBracket(mcElement *pnew) 00260 { 00261 mgui_bRemoveLeftBracket = TRUE; 00262 *pnew = mcElement(this); 00263 return mcIR_DISTRIBUTE; 00264 } 00265 00266 mcInputRes mcBracketHelpers::gui_HandleContentInput(mcInputRes r, mcElement *pnew) 00267 { 00268 if (!sgui_bCreateBothSymbols && r == mcIR_DELETE_NEXT) 00269 return gui_OnRemoveRightBracket(pnew); 00270 00271 if (!sgui_bCreateBothSymbols && r == mcIR_DELETE_PREVIOUS) 00272 return gui_OnRemoveLeftBracket(pnew); 00273 00274 return mcExpContainerHelpers::gui_HandleContentInput(r, pnew); 00275 } 00276 00277 00278 00279 00280 00281 // ---------------------------------------- 00282 // mcBracketHelpersIO 00283 // ---------------------------------------- 00284 00285 wxString mcBracketHelpers::io_GetBaseInlinedExpr() const 00286 { 00287 wxString str = data_GetContent().io_GetInlinedExpr(); 00288 00289 // update bracket symbols 00290 int n = data_ChooseBracketType(); 00291 00292 // just add the parentheses... 00293 return data_GetBracketLeftSymbol(n) + str + 00294 data_GetBracketRightSymbol(n); 00295 } 00296 00297 bool mcBracketHelpers::io_ImportBaseInlinedExpr(const wxString &str, int *count, wxString &pErr) 00298 { 00299 wxChar c = str.GetChar(0); 00300 wxChar e = 0; 00301 00302 // check begin char and find the end one 00303 mcASSERT(c == wxT('(') || c == wxT('[') || c == wxT('{'), wxT("Error in mcBracketHelpers::io_isBeginChar")); 00304 if (c == wxT('(')) e = wxT(')'); 00305 if (c == wxT('[')) e = wxT(']'); 00306 if (c == wxT('{')) e = wxT('}'); 00307 00308 // find the end character of this element 00309 wxString contents = str.Right(str.Len()-1); 00310 contents = contents.BeforeFirst(e); 00311 00312 // then, import the contained expression 00313 bool b = data_GetContent().io_ImportInlinedExpr(contents, count, pErr); 00314 *count += 2; 00315 00316 return b; 00317 } 00318 00319 00320 00321 00322 00323 // ---------------------------------------- 00324 // mcBRACKETMATH 00325 // ---------------------------------------- 00326 00327 mcExpSimRes mcBracketHelpers::math_SimplifyContents(long flags, mcElement *newelem) 00328 { 00329 bool numeric = !data_GetContent().math_ContainsSymbols(); 00330 bool factorized = data_GetContent().math_isFactorized(); 00331 00332 // in case we are just containing another bracket, even if 00333 // flags contains the mcEXPSIM_KEEP_FACTORIZATION flag, we 00334 // must expand ourselves to avoid something like: 00335 // 00336 // {[(a+b+c)]} 00337 // 00338 bool bracketnested = factorized && 00339 data_GetContent().math_Get(0).math_isWrappingOnly(mcET_BRACKET); 00340 00341 // FIXME: before using Distribute we should check if the 00342 // parent polynomial contains something which can be simplified 00343 // (i.e. summed/subtracted) with our contents: 00344 // 00345 // 4x+5(a-y) 00346 // ^^^^^--- this mcBracket should not be removed since 00347 // it would not allow any further simplification... 00348 // 00349 // 4x+5(a-x) 00350 // ^^^^^--- this mcBracket should be simplified to 00351 // 4x+5a-5x since it would bring to a simplification (4x-5x) 00352 00353 if ((!(flags & mcEXPSIM_KEEP_FACTORIZATION) && (factorized || numeric)) 00354 || bracketnested) { 00355 00356 mcExpSimRes r = math_RemoveExp(); 00357 if (r == mcESR_INVALID_DATA) 00358 return mcESR_DONE; 00359 if (r == mcESR_NOTFINISHED) 00360 return r; 00361 00362 // we have to expand ourselves since we contain only numbers... 00363 mcMATHLOG(wxT("mcBracketHelpers::math_SimplifyContents - going to expand [%s]"), mcTXTTHIS); 00364 00365 *newelem = mcElement(this); 00366 return mcESR_DISTRIBUTE; 00367 } 00368 00369 return mcESR_DONE; 00370 } 00371 00372 mcExpSimRes mcBracketHelpers::math_RemoveExp() 00373 { 00374 if (!math_hasExp()) 00375 return mcESR_DONE; 00376 00377 mcMATHLOG(wxT("mcBracketHelpers::math_RemoveExp [%s] - can [%s] be removed ?"), 00378 mcTXTTHIS, mcTXT(math_GetExp())); 00379 if (!data_GetContent().math_CanBeRaisedTo(math_GetExp())) { 00380 00381 // if the exponent is not a constant, then we cannot do anything: 00382 // (a+b+c+...z)^x 00383 // cannot be further expanded... 00384 return mcESR_INVALID_DATA; 00385 } 00386 00387 // we can expand the contents raising them to our exp 00388 data_GetContent().math_RaiseTo(math_GetExp()); 00389 this->data_DestroyExpSub(TRUE); 00390 00391 // we have raised a polynomial; by now, stop here... 00392 return mcESR_NOTFINISHED; 00393 } 00394 00395 mcExpSimRes mcBracketHelpers::math_ExpandContents(long flags, mcElement *newelem) 00396 { 00397 mcExpSimRes r = math_RemoveExp(); 00398 if (r == mcESR_INVALID_DATA) 00399 return mcESR_DONE; 00400 if (r == mcESR_NOTFINISHED) 00401 return r; 00402 00403 // unlike in math_SimplifyContents, this operation should always be performed... 00404 *newelem = mcElement(this); 00405 return mcESR_DISTRIBUTE; 00406 } 00407 00408 mcBasicOpRes mcBracketHelpers::math_MakeReciprocal(mcElement *pp) 00409 { 00410 // just create a fraction with our contents as denominator; 00411 // the brackets can be removed: 00412 // 00413 // 1 00414 // (ax+b+......) = -------------------- 00415 // ax + b + .... 00416 00417 mcFraction f; 00418 f.data_SetDen(data_GetContent()); 00419 00420 *pp = f; 00421 00422 return mcBOR_REMOVE_OPERAND; 00423 } 00424 00425
[ Top ] |