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

Bracket.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 "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 


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

[ Top ]