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

MathBox.cpp

Go to the documentation of this file.
00001 
00002 // MathGUI = 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 //                                                                   //
00030 
00031 
00032 
00033 // optimization for GCC compiler
00034 #ifdef __GNUG__
00035    #pragma implementation "MathBox.h"
00036 #endif
00037 
00038 
00039 // includes
00040 #include "mg/mgprec.h"
00041 
00042 #ifndef mgPRECOMP
00043    // for the "Insert fraction, radical, function" commands
00044    #include "mc/MathCore.h"
00045    #include "mc/Function.h"
00046    #include "mc/Fraction.h"
00047    #include "mc/Radical.h"
00048 
00049    #include "mg/GUIUtils.h"
00050    #include "mg/MathBox.h"
00051 #endif
00052 
00053 // Additional wxWidgets headers
00054 #include <wx/image.h>
00055 #include <wx/wfstream.h>
00056 #include <wx/txtstrm.h>
00057 #include <wx/mstream.h>
00058 #include <wx/filename.h>
00059 #include <wx/clipbrd.h>
00060 
00061 
00062 
00063 // set up customizable variables
00064 int mgMathBox::nCursorWidth = 2;
00065 int mgMathBox::nSpaceAround = 5;
00066 bool mgMathBox::bUseNativeNewLines = TRUE;
00067 
00068 
00069 mgMathBoxCmd mgMathBox::cmd[] = 
00070 {
00071    // simple edit commands
00072    { mgMBC_CUT, wxT("Cut") },
00073    { mgMBC_COPY_ASPLAIN, wxT("Copy as plain text") },
00074    { mgMBC_COPY_ASMATHML, wxT("Copy as MathML") },
00075    { mgMBC_PASTE, wxT("Paste") },
00076    { mgMBC_SELECTALL, wxT("Select all") },
00077 
00078    { mgMBC_CREATENEW_ANDLINE, wxT("Create a new line connected with AND") },
00079    { mgMBC_CREATENEW_ORLINE, wxT("Create a new line connected with OR") },
00080    { mgMBC_SIMPLEEND, wxT("") },
00081 
00082    // advanced edit commands
00083    { mgMBC_EMBED_NUMFRACTION, wxT("Embed as num of a fraction") },
00084    { mgMBC_EMBED_DENFRACTION, wxT("Embed as den of a fraction") },
00085    { mgMBC_EMBED_RADICAL, wxT("Embed into a radical") },
00086    { mgMBC_EMBED_BRACKET, wxT("Bracketize") },  
00087    { mgMBC_ADVEND, wxT("") },
00088 
00089 #ifdef __MGDEBUG__
00090    { mgMBC_DEBUG, wxT("View debug info") },
00091 #endif
00092 
00093    { mgMBC_LAST, wxT("") }
00094 };
00095 
00096 
00097 // defines the custom command event sent to the client window
00098 // (by default it's the parent window) when the element under
00099 // mouse cursor changes...
00100 DEFINE_EVENT_TYPE( mgEVT_ACTIVE_ELEM_CHANGED )
00101 
00102 
00103 
00104 
00105 // mgMATHBOX
00106 IMPLEMENT_CLASS(mgMathBox, wxWindow)//wxResizeableControl)
00107 BEGIN_EVENT_TABLE(mgMathBox, wxWindow)//wxResizeableControl)
00108 
00109    // focus events
00110    EVT_SET_FOCUS(mgMathBox::OnSetFocus)
00111    EVT_KILL_FOCUS(mgMathBox::OnFocusLost)
00112 
00113    // miscellaneous events
00114    EVT_SIZE(mgMathBox::OnSize)
00115    EVT_PAINT(mgMathBox::OnPaint)
00116 
00117    // mouse events
00118    //EVT_SET_CURSOR(mgMathBox::OnSetCursor)     // not needed
00119    //EVT_RIGHT_DOWN(mgMathBox::OnRDown)
00120    EVT_RIGHT_UP(mgMathBox::OnRUp)            // used for context menu
00121    EVT_LEAVE_WINDOW(mgMathBox::OnLeaveWindow)
00122    EVT_LEFT_DOWN(mgMathBox::OnLDown)         // used for starting selections
00123    EVT_LEFT_UP(mgMathBox::OnLUp)          // used to end selections
00124    EVT_MOTION(mgMathBox::OnMouseMove)        // used to select
00125 
00126    // keyboard events
00127    EVT_CHAR(mgMathBox::OnChar)
00128 
00129    // context menu events
00130    EVT_MENU_RANGE(mgMATHBOX_CONTEXTMENU_BASEID,
00131                mgMATHBOX_CONTEXTMENU_FINALID,
00132                mgMathBox::OnCtxMenuItem)
00133 END_EVENT_TABLE()
00134 
00135 
00136 
00137 
00138 
00139 
00140 // --------------------------------------------
00141 // mgMATHBOX - general functions
00142 // --------------------------------------------
00143 
00144 void mgMathBox::Init()
00145 {
00146    m_pClient = NULL; // this is the only pointer contained by mgMathBox
00147 
00148    // set WHITE as the window background color
00149    SetBackgroundColour(wxColour(255, 255, 255));   
00150 
00151    // init all
00152    SetClientEvtHandler(GetParent());
00153    m_bProcSpecialChar = FALSE;
00154    m_bAutoExpand = FALSE;
00155    Clean();
00156 
00157    // init the selection rect
00158    ResetSelectionRect();
00159 
00160    // if the caret of this window does not exist, create it
00161    if (GetCaret() == NULL)
00162       SetCaret(new wxCaret(this, nCursorWidth, 10));  
00163 
00164    // by default, everything is initially enabled... use
00165    // the #EnableInput, #EnableSelection, #EnableContextMenu
00166    // to modify those variables...
00167    EnableInput(TRUE);
00168    m_bSelectionEnabled = TRUE;
00169    m_bContextMenuEnabled = TRUE;
00170    m_bPreProcessingEnabled = TRUE;
00171 
00172    UpdateCaretPos();
00173    UpdateCaret();
00174 }
00175 
00176 void mgMathBox::EnableInput(bool bEnable)
00177 {
00178    m_bInputEnabled = bEnable;
00179 
00180    // set the type of cursor accordingly
00181    if (m_bInputEnabled) {
00182       SetCursor(wxCursor(wxCURSOR_IBEAM));
00183    } else {
00184       SetCursor(wxCursor(wxCURSOR_ARROW));
00185    }
00186 
00187    // the caret must be hidden when input is disabled...
00188    UpdateCaret();
00189 }
00190 
00191 void mgMathBox::DeepCopy(const mgMathBox &tocopy)
00192 {
00193    // deep copy everything
00194    m_mathContent.data_DeepCopy(tocopy.m_mathContent);
00195 
00196    m_rcSelection = tocopy.m_rcSelection;
00197    m_bProcSpecialChar = tocopy.m_bProcSpecialChar;
00198 
00199    // remaining variables doesn't need to be deep copied...
00200 }
00201 
00202 void mgMathBox::Clean()
00203 {
00204    // re init  
00205    m_mathContent.data_Clear();
00206 
00207    // create a mcMathAndSystem with a mcMathLine with the left member
00208    // containing a mcEmptyBox...
00209    GetMathObj().gui_AddEmptyLineToNewAndSystem();
00210    /*data_AddLineToNewAndSystem(new mcMathLine());
00211    GetMathObj().data_GetSys(0).data_GetLine(0).data_GetLeftMem().gui_AddNewEmptyMonomial();*/
00212 
00213    // update everything
00214    ResetGUI();
00215 }
00216 
00217 wxString mgMathBox::GetDebug() const
00218 {
00219    // return just the contained math data debug info...
00220    return m_mathContent.data_GetDebug(0, mcELEMENT_DBG_SELECTION);
00221 }
00222 
00223 
00224 
00225 
00226 
00227 // --------------------------------------------
00228 // mgMATHBOX - SIZE functions
00229 // --------------------------------------------
00230 
00231 wxSize mgMathBox::GetContentSize() const
00232 {
00233    int w = m_mathContent.gui_GetWidth()+nSpaceAround*2,
00234       h = m_mathContent.gui_GetHeight()+nSpaceAround*2;
00235 
00236    return wxSize(w, h);
00237 }
00238 
00239 void mgMathBox::FitContents()
00240 {
00241    // update client size to contain all the data. This could mean
00242    // that this function expands the window; it never shrinks it. <-- WHY ???
00243    wxSize min = GetContentSize();
00244    SetSize(min);
00245    UpdateContentPos();
00246    /*wxSize sz = GetSize();
00247    if (min.GetWidth() > sz.GetWidth()) sz.SetWidth(min.GetWidth());
00248    if (min.GetHeight() > sz.GetHeight()) sz.SetHeight(min.GetHeight());
00249    SetSize(sz);*/
00250 }
00251 
00252 void mgMathBox::SetSizeHintsToFitContents()
00253 {
00254    FitContents();
00255 
00256    // with this call, resize system will not be allowed to shrink this
00257    // window under the content size...
00258    wxSize s = GetContentSize();
00259    SetSizeHints(s.GetWidth(), s.GetHeight());
00260 }
00261 
00262 
00263 
00264 
00265 // --------------------------------------------
00266 // mgMATHBOX - UPDATE functions
00267 // --------------------------------------------
00268 
00269 void mgMathBox::UpdateContentPos()
00270 {  
00271    wxSize sz(GetClientSize()), mathsz(GetContentSize());
00272 
00273    // center vertically the mcMathOrSystem in this window.
00274    m_ptPos.y = (sz.GetHeight()-mathsz.GetHeight())/2;
00275 
00276    // center horizontally the mcMathOrSystem in this window.
00277    m_ptPos.x = (sz.GetWidth()-mathsz.GetWidth())/2;
00278 
00279    // this is the top-leftmost position allowed...
00280    if (m_ptPos.x < 0) m_ptPos.x = 0;
00281    if (m_ptPos.y < 0) m_ptPos.y = 0;
00282 }
00283 
00284 void mgMathBox::UpdateCaret()
00285 {
00286    // the caret should have been already built.. anyway better check
00287    mgCaret *cur = GetCaret();
00288    if (!cur) return;
00289 
00290    //bool oldstate = cur->IsVisible();
00291    if (!m_bInputEnabled || isSelecting()) {
00292 
00293       // never show the caret in these cases
00294       cur->ForceHide();    
00295 
00296    } else {
00297 
00298       cur->ForceShow();
00299    }
00300 
00301    //if (oldstate != cur->IsVisible())
00302    // ForceBmpUpdate();
00303 }
00304 
00305 void mgMathBox::UpdateCaretPos()
00306 {
00307    wxClientDC dc(this);
00308    int n;
00309    
00310    // get current cursor position
00311    wxPoint p = m_mathContent.gui_GetRelCursorPos(dc, GetXPos(), GetYPos(), &n);
00312    mcASSERT(n != 0, wxT("Cursor is not positioned in a valid point..."));
00313    
00314    // and update the window's caret
00315    wxCaret *cur = GetCaret();
00316    if (!cur) return;
00317    cur->Move(p);
00318    cur->SetSize(nCursorWidth, n);
00319 
00320    UpdateCaret();
00321 }
00322 
00323 int mgMathBox::UpdateMathBmp(long flags, const wxPoint &p)
00324 {
00325    // IF WE DO SOMETHING LIKE THIS:
00326    // 
00327    // wxRect rc(GetXPos(), GetYPos(),  m_mathContent.gui_GetWidth(), 
00328    //                         m_mathContent.gui_GetHeight());
00329    // if (!rc.Inside(cursor)) {
00330    //    mgLogBoxEvent("mgMathBox::UpdateActiveElem() - update rejected");
00331    //    return;
00332    // }
00333    //
00334    // THEN WE WOULD:
00335    // 1) make this function a little slower, instead of faster,
00336    //    because mcMathOrSystemHelpers::gui_UpdateBmp already
00337    //    does this type of check
00338    // 2) render something wrong (that is, still as active) when
00339    //    the cursor exits the math content box because math contents
00340    //    would never receive the info "the mouse cursor is not over you"
00341    //    and thus would continue to draw as active something which is not
00342    //    anymore.
00343    
00344    // mcMathOrSystem will care of everything...
00345    int x=GetXPos(), y=GetYPos();
00346    int ret = m_mathContent.gui_UpdateBmp(x, y, flags, p);
00347 
00348    // do we need to redraw ?
00349    if (m_mathContent.gui_NeedsRefresh()) {
00350 
00351       wxClientDC dc(this);
00352       RedrawMath(dc, x, y);
00353    }
00354 
00355    // do we need to fire an event ?
00356    if (m_mathContent.gui_isIDChanged()) {
00357 
00358       wxCommandEvent ev(mgEVT_ACTIVE_ELEM_CHANGED, GetId());
00359       ev.SetExtraLong(m_mathContent.gui_GetActiveElemID());
00360       if (m_pClient) m_pClient->AddPendingEvent(ev);
00361    }
00362 
00363    return ret;
00364 }
00365 
00366 void mgMathBox::UpdateMathBmpWithCurrentPos()
00367 {
00368    wxPoint p = wxGetMousePosition();
00369 
00370    // remap cursor position in the correct way
00371    p = ScreenToClient(p);     // from screen to window coord.
00372 
00373    // use std version of the function
00374    UpdateMathBmp(mcDRW_USEPOINT, p);
00375 }
00376 
00377 void mgMathBox::ForceBmpUpdate()
00378 {
00379    int x=GetXPos(), y=GetYPos();
00380    wxPoint p = wxGetMousePosition();
00381 
00382    // remap cursor position in the correct way
00383    p = ScreenToClient(p);     // from screen to window coord.
00384 
00385    // force the update
00386    m_mathContent.gui_ForceBmpUpdate(x, y, mcDRW_USEPOINT, p);
00387 
00388    // and redraw the updated bitmap
00389    wxClientDC dc(this);
00390    RedrawMath(dc, x, y);
00391 }
00392 
00393 
00394 
00395 
00396 // --------------------------------------------
00397 // mgMATHBOX - miscellaneous
00398 // --------------------------------------------
00399 
00400 void mgMathBox::RedrawMath(wxDC &dc, int x, int y)
00401 {
00402    // before drawing, we must be sure that caret is hidden
00403 #if 0
00404    mgCaret *caret = GetCaret();
00405    if (caret) caret->ForceHide();
00406 #endif
00407    m_mathContent.gui_DrawBmp(dc, x, y);
00408 
00409    // after drawing, we should restore the caret, if it
00410    // is necessary
00411    UpdateCaret();
00412 }
00413 
00414 void mgMathBox::ResetGUI()
00415 {
00416    m_mathContent.gui_SetCursorPos(mcCP_BEGIN);
00417    m_mathContent.gui_UpdateExpDepth();
00418    m_mathContent.gui_DeepRecalcSize();
00419 
00420    // the order is important !
00421    ForceBmpUpdate();
00422    UpdateContentPos();
00423    UpdateCaretPos(); 
00424    Refresh();
00425 }
00426 
00427 void mgMathBox::CheckReturnFlag(int res)
00428 {
00429    switch (res) {
00430    case mcMCR_SETFOCUS_PREVIOUS:
00431    case mcMCR_SETFOCUS_NEXT:
00432    case mcMCR_SETFOCUS_ABOVE:
00433    case mcMCR_SETFOCUS_BELOW:
00434       mcMathCore::Get()->SyntaxError(wxT("Cannot move cursor beyond math data"));
00435       break;
00436 
00437    case mcMCR_CANNOT_SETFOCUS:
00438       //m_mathContent.gui_DeSelect();     // WHY ?
00439       //Refresh();
00440       break;
00441    }
00442 }
00443 
00444 
00445 
00446 // --------------------------------------------
00447 // mgMATHBOX - miscellaneous event handlers
00448 // --------------------------------------------
00449 
00450 void mgMathBox::OnPaint(wxPaintEvent &ev)
00451 {
00452    wxCaretSuspend cs(this);
00453    wxPaintDC dc(this);
00454 
00455    // on MS windows, this sets up some optimizations
00456    dc.BeginDrawing();
00457    
00458    // draw the selection rectangle
00459    dc.SetBrush(*wxCYAN_BRUSH);
00460    dc.DrawRectangle(m_rcSelection);
00461    
00462    // draw using the image of the line
00463    RedrawMath(dc, GetXPos(), GetYPos());
00464    
00465    // on MS windows, shut down draw optimizations
00466    dc.EndDrawing();
00467 
00468    // for debugging
00469    mgLogBoxEvent(wxT("mgMathBox::OnPaint() - window repainted"));
00470 }
00471 
00472 void mgMathBox::OnSize(wxSizeEvent &se)
00473 {
00474    // when size changes, the cursor position must be updated because
00475    // the math data is centered in the window...
00476    UpdateCaretPos();
00477 
00478    // we need to erase old bitmap: we can now its exact position
00479    // because our m_ptPos variable has not been updated yet...
00480    wxClientDC dc(this);
00481    dc.SetPen(*wxWHITE_PEN);
00482    dc.SetBrush(*wxWHITE_BRUSH);
00483    dc.DrawRectangle(m_ptPos, GetContentSize());
00484 
00485    // we can now draw the new bitmap in the updated pos...
00486    UpdateContentPos();
00487    UpdateCaretPos();
00488    RedrawMath(dc, GetXPos(), GetYPos());
00489 
00490    // for debugging
00491    mgLogBoxEvent(wxT("mgMathBox::OnSize() - window resized"));
00492 }
00493 
00494 void mgMathBox::OnSpecialChar(wxKeyEvent &ke)
00495 {
00496    m_bProcSpecialChar = TRUE;
00497    OnChar(ke);
00498    m_bProcSpecialChar = FALSE;
00499 }
00500 
00501 void mgMathBox::OnChar(wxKeyEvent &ke)
00502 {
00503    wxClientDC dc(this);
00504    int r, mod=mcMCF_NOMODIFIERS;
00505 /*
00506    if (ke.GetKeyCode() == 13 && !m_bProcSpecialChar)
00507       return;
00508 */
00509    // block here the ALT+xxxx keypresses.
00510    if (ke.AltDown()) {
00511       ke.Skip();     // otherwise menu shortcut won't work
00512       return;
00513    }
00514 
00515    // block here some other special keypresses
00516    // (like the Windows' START keypress)
00517    if (ke.GetKeyCode() == WXK_START
00518 #ifdef __WXMSW__
00519       || ke.GetKeyCode() == 397  // on winXP at least, start button has keycode = 397
00520 #endif
00521       ) {
00522       ke.Skip();
00523       return;
00524    }
00525 
00526    // is input enabled ?
00527    if (!m_bInputEnabled) {
00528       wxBell();         // cannot accept any input... sorry
00529       return;
00530    }
00531 
00532    // are we moving the cursor and selecting ?
00533    if (ke.ShiftDown())  
00534       mod = mcMCF_EXTEND_SELECTION; // maybe: pass to the gui_MoveCursor a "modifier"
00535 
00536    // remove the SHIFT flag from capital letters....
00537    if (ke.GetKeyCode() >= 65 && ke.GetKeyCode() <= 90 && ke.ShiftDown())
00538       ke.m_shiftDown = FALSE;
00539 
00540    switch (ke.m_keyCode) {
00541 
00542       // cursor movement keys handlers
00543    case WXK_LEFT:
00544       r = m_mathContent.gui_MoveCursor(mcMCF_LEFT, mod);
00545       CheckReturnFlag(r);
00546       UpdateCaretPos();
00547       break;
00548    case WXK_RIGHT:
00549       r = m_mathContent.gui_MoveCursor(mcMCF_RIGHT, mod);
00550       CheckReturnFlag(r);
00551       UpdateCaretPos();
00552       break;
00553    case WXK_UP:
00554       r = m_mathContent.gui_MoveCursor(mcMCF_UP, mod);
00555       CheckReturnFlag(r);
00556       UpdateCaretPos();
00557       break;
00558    case WXK_DOWN:
00559       r = m_mathContent.gui_MoveCursor(mcMCF_DOWN, mod);
00560       CheckReturnFlag(r);
00561       UpdateCaretPos();
00562       break;
00563    case WXK_HOME:
00564       m_mathContent.gui_SetCursorPos(mcCP_BEGIN);
00565       UpdateCaretPos();
00566       break;
00567    case WXK_END:
00568       m_mathContent.gui_SetCursorPos(mcCP_END);
00569       UpdateCaretPos();
00570       break;
00571 
00572 
00573    default:
00574 
00575       if (!m_bProcSpecialChar) {
00576 
00577          // a numpad key was pressed; ignore it; this function will be called
00578          // again, by wxWidgets, with a translated ASCII code
00579          if (ke.m_keyCode >= WXK_NUMPAD0 && ke.m_keyCode <= WXK_NUMPAD9)
00580             return;
00581 
00582 #ifdef __WXMSW__
00583          // a little exception: if user pressed CTRL+ENTER we must correct,
00584          // on win32 the key event which we receive....
00585          if (ke.ControlDown() && ke.GetKeyCode() == 10) {
00586 
00587             // Get Win32 native scancode
00588             if ((ke.GetRawKeyFlags() >> 16) == 28) // 28 = ENTER scancode
00589                ke.m_keyCode = 13;
00590          }
00591 #endif
00592       }
00593 
00594 #ifdef __WXGTK__
00595       // this flag is always set on Linux when the NUMLOCK is on)... but this would
00596       // prevent MathCore from recognizing the keypress...
00597       ke.m_metaDown = false;
00598 #endif
00599 
00600       // convert the wxKeyEvent to a mcKey
00601       mcKey mykey(ke);
00602 
00603       // to create a relational operator, we must always
00604       // use special keys...
00605       wxChar c = ke.GetKeyCode();
00606       if (m_bProcSpecialChar || c == mcMMRO_LESS || 
00607          c == mcMMRO_GREATER || c == mcMMRO_EQUAL)
00608          mykey.SetAsSpecialKey();
00609 
00610       // one of ()0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ
00611       // or abcdefghijklmnopqrstuvwxyz key was pressed
00612       mgLogBoxEvent(wxT("mgMathBox::OnChar() - before processing: [%s]"), 
00613          m_mathContent.io_GetInlinedExpr().c_str());
00614       m_mathContent.gui_Input(mykey, NULL);
00615       mgLogBoxEvent(wxT("mgMathBox::OnChar() - after processing: [%s]"), 
00616          m_mathContent.io_GetInlinedExpr().c_str());
00617 
00618       // update cursor pos and redraw the window
00619       if (m_bAutoExpand)
00620          FitContents();
00621       
00622       UpdateContentPos();
00623       UpdateCaretPos();
00624 
00625       Refresh();
00626       ForceBmpUpdate();
00627       //UpdateMathBmpWithCurrentPos();    
00628    }
00629 
00630    // for debugging
00631    mgLogBoxEvent(wxT("mgMathBox::OnChar() - input handled"));
00632 }
00633 
00634 
00635 
00636 
00637 
00638 // --------------------------------------------
00639 // mgMATHBOX - mouse event handlers
00640 // --------------------------------------------
00641 
00642 void mgMathBox::OnSetCursor(wxSetCursorEvent &ev)
00643 {
00644    SetCursor(wxCursor(wxCURSOR_ARROW));//*wxSTANDARD_CURSOR);
00645 
00646    // for debugging
00647    mgLogBoxEvent(wxT("mgMathBox::OnSetCursor() - cursor has been set"));
00648 }
00649 
00650 void mgMathBox::OnLeaveWindow(wxMouseEvent &ev)
00651 {
00652    // sometimes, when the user moves the cursor out of the mcMathOrSystem
00653    // very fast, the math system doesn't receive a correct UpdateActiveElem()
00654    // call and thus, the element highlighting remains even if the mouse
00655    // cursor is not over that element anymore...
00656    UpdateMathBmp(mcDRW_NONACTIVE);  
00657 
00658    // for debugging
00659    mgLogBoxEvent(wxT("mgMathBox::OnLeaveWindow() - cursor has leaved the box"));
00660 }
00661 
00662 void mgMathBox::OnLDown(wxMouseEvent &me)
00663 {
00664    // if the selection system is not enabled, then this event handler's
00665    // code should not be executed since it only handles the SELECTION
00666    if (!m_bSelectionEnabled)
00667       return;
00668    
00669    // the first thing to do, is to delete the old selection...
00670    bool needsupdate = m_mathContent.gui_isSelected();
00671    m_mathContent.gui_DeSelect();
00672    if (needsupdate) ForceBmpUpdate();
00673 
00674    // prepare some variables
00675    wxClientDC dc(this);
00676    wxPoint pt = me.GetLogicalPosition(dc);
00677 
00678    // set up the drag start point of the selection
00679    m_rcSelection.x = pt.x;
00680    m_rcSelection.y = pt.y;
00681 
00682    // this settings will work as a flag: the selection
00683    // rectangle is now being dragged (see isSelecting())
00684    m_rcSelection.width = 0;
00685    m_rcSelection.height = 0;
00686 
00687    // capture the mouse (so, if it exits the window
00688    // the OnLUP function will still be called)
00689    CaptureMouse();
00690 
00691    // hide caret & change cursor
00692    UpdateCaret(); 
00693    //SetCursor(*wxSTANDARD_CURSOR);
00694 
00695    // for debugging
00696    mgLogBoxEvent(wxT("mgMathBox::OnLDown() - started selection dragging"));
00697 }
00698 
00699 void mgMathBox::OnLUp(wxMouseEvent &me)
00700 {
00701    // when this event handler is called, then it is because
00702    // the user should be selecting something...
00703    // check if the drag point was in this same mgMathBox
00704    if (GetCapture() == this) {
00705 
00706       // user has just finished to create a selection rectangle...
00707       // all the math data must have been already selected by
00708       // OnMouseMove... just reset selection system
00709       ResetSelectionRect();
00710 
00711       // free the cursor
00712       ReleaseMouse();      
00713 
00714       // move the cursor inside the math data
00715       wxClientDC dc(this);
00716       wxPoint pt = me.GetLogicalPosition(dc);
00717       wxRect rc(GetRectOfContents());
00718 
00719       // check if point is inside the math data
00720       if (rc.Inside(pt)) {
00721 
00722          // user released button over the math expression; move the cursor
00723          // to the nearest available position
00724          m_mathContent.gui_MoveCursorUsingPoint(dc, 
00725                         wxPoint(pt.x-rc.x, pt.y-rc.y));
00726          
00727          // don't use CheckReturnFlag since it would emit
00728          // a dummy sound if the given position is not valid
00729          // (and this almost always TRUE when the user
00730          //  drags a big rectangle on the math data)           
00731 
00732       } else {
00733 
00734          if (pt.x < rc.x) {
00735 
00736             // the cursor is on the LEFT side of the math content
00737             m_mathContent.gui_SetCursorPos(mcCP_BEGIN);
00738 
00739          } else if (pt.x > rc.x+rc.width) {
00740 
00741             // the cursor is on the RIGHT side of the math content
00742             m_mathContent.gui_SetCursorPos(mcCP_END);
00743 
00744          } else if (pt.y < rc.y || pt.y > rc.y+rc.height) {
00745 
00746             // the cursor is above/below the math content: ajust
00747             // the point so that it falls inside the math content
00748             pt.y = rc.y+m_mathContent.gui_GetHeight()/2;
00749             m_mathContent.gui_MoveCursorUsingPoint(dc, 
00750                         wxPoint(pt.x-rc.x, pt.y-rc.y));
00751          }
00752       }
00753 
00754       // restore caret & cursor
00755       UpdateCaretPos();
00756       UpdateCaret();
00757       //SetCursor(*m_pCursor);
00758 
00759       // for debugging
00760       mgLogBoxEvent(wxT("mgMathBox::OnLUp() - selection ended (%d elements selected)"),
00761                   m_mathContent.gui_isSelected());
00762    }
00763 }
00764 
00765 void mgMathBox::OnRUp(wxMouseEvent &me)
00766 {
00767    // this event handler is used only for context menu handling
00768    if (!m_bContextMenuEnabled)
00769       return;
00770 
00771    // check if the user right-clicked on the selection or not
00772    wxClientDC dc(this);
00773    wxPoint tmp = me.GetLogicalPosition(dc);
00774    if (m_mathContent.gui_GetActiveElemID() != mcDRW_ONSELECTION) {
00775 
00776       // create a dummy selection to select the element the
00777       // user right-clicked on...
00778       m_rcSelection.x = tmp.x;
00779       m_rcSelection.y = tmp.y;
00780       m_rcSelection.width = 1;
00781       m_rcSelection.height = 1;
00782 
00783       // if this selection rectangle would destroy the
00784       // current selection without selecting anything new, 
00785       // then avoid it...
00786       if (m_rcSelection.Intersects(GetRectOfContents())) {  
00787 
00788          // if the user clicked on a valid element, we are sure
00789          // it's now selected
00790          m_rcSelection.x-=GetXPos();
00791          m_rcSelection.y-=GetYPos();
00792          m_mathContent.gui_OnSelect(dc, m_rcSelection);
00793          ForceBmpUpdate();
00794 
00795       }
00796 
00797       // we can now proceed...
00798    }
00799 
00800    // create the context menu
00801    wxMenu m;
00802    m_eSelection = m_mathContent.gui_GetSelection();
00803    GetContextMenu(m, m_eSelection);
00804 
00805    // pop up the context menu
00806    PopupMenu(&m, tmp);
00807 
00808    // for debugging
00809    mgLogBoxEvent(wxT("mgMathBox::OnRUp() - popped the context menu"));
00810 }
00811 
00812 void mgMathBox::OnMouseMove(wxMouseEvent &me)
00813 {
00814    wxClientDC dc(this);
00815 
00816    // get the point in scrolled window coord
00817    wxPoint tmp = me.GetLogicalPosition(dc);
00818 
00819    if (GetCapture() == this) {
00820 
00821       // we are not just moving the cursor into the window:
00822       // we are dragging a selection rectangle...
00823 
00824       // update selection rectangle
00825       m_rcSelection.width = tmp.x-m_rcSelection.x;
00826       m_rcSelection.height = tmp.y-m_rcSelection.y;
00827 
00828       // normalize rect
00829       wxRect rc(m_rcSelection);
00830       if (rc.width < 0) {
00831          rc.x += rc.width;    // the X could become negative but it's okay
00832          rc.width = -rc.width;
00833       }
00834       if (rc.height < 0) {
00835          rc.y += rc.height;
00836          rc.height = -rc.height;
00837       }
00838 
00839       // do not allow null rects
00840       if (rc.width == 0) rc.width++;
00841       if (rc.height == 0) rc.height++;
00842 
00843       // check that everything's okay
00844       mcASSERT(rc.width > 0 && rc.height > 0, wxT("invalid rect"));     
00845       wxRect mathrc(GetRectOfContents());
00846       if (!mathrc.Intersects(rc))
00847          return;
00848 
00849       // update selection
00850       rc.Offset(-mathrc.x, -mathrc.y);
00851       m_mathContent.gui_OnSelect(dc, rc);
00852 
00853       // update the math bitmap: to make things clearer,
00854       // do not draw any activation state
00855       ForceBmpUpdate();
00856 
00857    } else {
00858 
00859       // we are just moving the cursor around the window:
00860       // update activation state...
00861       UpdateMathBmp(mcDRW_USEPOINT, tmp);
00862    }
00863 
00864    // for debugging
00865    mgLogBoxEvent(wxT("mgMathBox::OnMouseMove() - mouse movement handled"));
00866 }
00867 
00868 
00869 
00870 // --------------------------------------------
00871 // mgMATHBOX - focus event handlers
00872 // --------------------------------------------
00873 
00874 void mgMathBox::OnSetFocus(wxFocusEvent &fe)
00875 {
00876    // just for debugging purpose...
00877    mgLogDebug(wxT("mgMathBox::OnSetFocus() - focus set"));
00878 }
00879 
00880 void mgMathBox::OnFocusLost(wxFocusEvent &fe)
00881 {
00882    // just for debugging purpose...
00883    mgLogDebug(wxT("mgMathBox::OnSetFocus() - focus lost"));
00884 }
00885 
00886 
00887 
00888 // --------------------------------------------
00889 // mgMATHBOX - context menu
00890 // --------------------------------------------
00891 
00892 void mgMathBox::OnCtxMenuItem(wxCommandEvent &ce)
00893 {
00894    wxClientDC dc(this);
00895 
00896    // exec the command chosen by the user
00897    switch (ce.GetId()-mgMATHBOX_CONTEXTMENU_BASEID) {
00898    case mgMBC_CUT:
00899       Cut(m_eSelection);
00900       break;
00901 
00902    case mgMBC_COPY_ASPLAIN:
00903       CopyAsPlainText(m_eSelection);
00904       break;
00905 
00906    case mgMBC_COPY_ASMATHML:
00907       CopyAsMathML(m_eSelection);
00908       break;
00909 
00910    case mgMBC_SELECTALL:
00911       m_mathContent.gui_SelectAll();
00912       break;
00913 
00914    case mgMBC_PASTE:
00915       Paste(m_eSelection);
00916       break;
00917 
00918    case mgMBC_EMBED_NUMFRACTION:
00919       EmbedAsFractionNum(m_eSelection);
00920       break;
00921 
00922    case mgMBC_EMBED_DENFRACTION:
00923       EmbedAsFractionDen(m_eSelection);
00924       break;
00925 
00926    case mgMBC_CREATENEW_ANDLINE:
00927       m_mathContent.gui_AddEmptyLineToLastAndSystem();
00928       break;
00929 
00930    case mgMBC_CREATENEW_ORLINE:
00931       m_mathContent.gui_AddEmptyLineToNewAndSystem();
00932       break;
00933 
00934 #ifdef __MGDEBUG__
00935    case mgMBC_DEBUG:
00936 
00937       // user clicked on our special debug item
00938       mgLogDebug(m_mathContent.data_GetDebug(0, 
00939          mcELEMENT_DBG_EXPDEPTH | mcELEMENT_DBG_SELECTION | mcELEMENT_DBG_ID));
00940       break;
00941 #endif
00942 
00943    default:
00944       break;
00945 
00946       // not our item...
00947 //    m_mathContent.gui_ExecCmdOnSel(m_nCmdID[n]);
00948    }
00949 
00950    // update cursor pos and redraw the window
00951    ResetGUI();
00952 
00953    // for debugging
00954    mgLogBoxEvent(wxT("mgMathBox::OnCtxMenuItem - context menu click handled"));
00955 }
00956 
00957 void mgMathBox::GetContextMenu(wxMenu &m, const mcElement &selection) const
00958 {
00959    int j;
00960 
00961    // basic edit commands
00962    for (j=0; j<mgMBC_SIMPLEEND; j++)
00963       m.Append(mgMATHBOX_CONTEXTMENU_BASEID+cmd[j].m_nID, 
00964                cmd[j].m_strDescription);
00965    m.AppendSeparator();
00966    
00967    // some more advanced commands...
00968    for (j=mgMBC_SIMPLEEND+1; j<mgMBC_ADVEND; j++)
00969       m.Append(mgMATHBOX_CONTEXTMENU_BASEID+cmd[j].m_nID, 
00970                cmd[j].m_strDescription);
00971 
00972    // should we add any math command ?
00973    wxArrayString arr;
00974    if (selection != mcEmptyElement) {
00975       
00976       // get an array of string from the math object
00977       //arr = m_mathContent.gui_GetPossibleOpOnSel(m_nCmdID);
00978 
00979    } else {
00980    }
00981 
00982    // append the math commands...
00983    int startid=mgMATHBOX_CONTEXTMENU_MATHCMD_BASEID+m.GetMenuItemCount();
00984    if (arr.GetCount()) m.AppendSeparator();
00985    for (j=0; j < (int)arr.GetCount(); j++)
00986       m.Append(startid+j, arr.Item(j));
00987 
00988 #ifdef __WXDEBUG__
00989    m.AppendSeparator();
00990    m.Append(mgMATHBOX_CONTEXTMENU_BASEID+mgMBC_DEBUG, wxT("View debug info"));
00991 #endif
00992 }
00993 
00994 
00995 
00996 // --------------------------------------------
00997 // mgMATHBOX - context menu commands
00998 // --------------------------------------------
00999 
01000 void mgMathBox::InsertFraction() {
01001    wxKeyEvent fakekey = mcFractionHelpers::sgui_pNewFraction->GetEvent();
01002    OnSpecialChar(fakekey);
01003 }
01004 
01005 void mgMathBox::InsertRadical() {
01006    wxKeyEvent fakekey = mcRadicalHelpers::sgui_pNewRadical->GetEvent();
01007    OnSpecialChar(fakekey);
01008 }
01009 
01010 void mgMathBox::InsertFunction() {
01011    wxKeyEvent fakekey = mcFunctionHelpers::sgui_pNewFunction->GetEvent();
01012    OnSpecialChar(fakekey);
01013 }
01014 
01015 void mgMathBox::EditExponent() {
01016    wxKeyEvent fakekey = mcMathCore::Get()->m_pEditExpKey->GetEvent();
01017    OnSpecialChar(fakekey);
01018 }
01019 
01020 void mgMathBox::EditSubscript() {
01021    wxKeyEvent fakekey = mcMathCore::Get()->m_pEditSubscriptKey->GetEvent();
01022    OnSpecialChar(fakekey);
01023 }
01024 
01025 void mgMathBox::Cut(const mcElement &sel)
01026 {
01027    // do copy
01028    CopyAsPlainText(sel);
01029 
01030    // do cut...
01031    m_mathContent.gui_DeleteSelection();
01032 }
01033 
01034 #define mgGET_SEL(x)                   \
01035    mcElement x(sel);                   \
01036    if (x == mcEmptyElement) {             \
01037       x = m_mathContent.gui_GetSelection();  \
01038       if (x == mcEmptyElement)            \
01039          return;     /* nothing to copy */   \
01040    }
01041 
01042 void mgMathBox::CopyAsPlainText(const mcElement &sel)
01043 {
01044    mgGET_SEL(elem);
01045 
01046    wxString str(elem.io_GetInlinedExpr());
01047    str = ConvertString(str);
01048 
01049    // export to clipboard
01050    if (wxTheClipboard->Open())
01051    {
01052       // This data objects are held by the clipboard,
01053       // so do not delete them in the app.
01054       wxTheClipboard->SetData( new wxTextDataObject(str) );
01055       wxTheClipboard->Close();
01056    }
01057 }
01058 
01059 void mgMathBox::CopyAsMathML(const mcElement &sel)
01060 {
01061    mgGET_SEL(elem);
01062 
01063    wxXml2Document doc;
01064    wxStringOutputStream stream;
01065    wxXml2Node math(elem.io_GetMathML(TRUE));
01066 
01067    doc.Create();
01068    doc.SetRoot(math);
01069 
01070    if (doc.Save(stream, wxT("UTF-8"), wxXML2DOC_USE_NATIVE_NEWLINES | wxXML2DOC_USE_INDENTATION) == -1)
01071       return;
01072 
01073    math.DestroyIfUnlinked();
01074    doc.DestroyIfUnlinked();
01075 
01076    // export to clipboard
01077    if (wxTheClipboard->Open())
01078    {
01079       // This data objects are held by the clipboard,
01080       // so do not delete them in the app.
01081       wxTheClipboard->SetData( new wxTextDataObject(stream.GetStr()) );
01082       wxTheClipboard->Close();
01083    }
01084 }
01085 
01086 void mgMathBox::Paste(const mcElement &sel)
01087 {
01088    // STILL NOT WORKING
01089    wxMessageBox(wxT("Still not working..."), wxT("Sorry"));
01090    return;
01091 
01092    // check clipboard data is okay
01093    if (!wxTheClipboard->Open() ||
01094       !wxTheClipboard->IsSupported( wxDF_TEXT ))
01095       return;
01096 
01097    // import clipboard data
01098    wxTextDataObject data;
01099    wxTheClipboard->GetData( data );
01100    wxString str = data.GetText();   
01101     wxTheClipboard->Close();
01102 
01103    // import the data
01104    mcPolynomial pol;
01105    wxString err;
01106    if (!pol.io_ImportInlinedExpr(str, NULL, err)) {
01107       wxBell();
01108       return;
01109    }
01110 
01111    // insert it into the math contents
01112    mcInsertRes r(m_mathContent.gui_Insert(pol, NULL));
01113    if (r != mcINSR_OKAY) {
01114       wxBell();
01115       return;
01116    }
01117 }
01118 
01119 void mgMathBox::EmbedAsFractionNum(const mcElement &sel)
01120 {
01121    mcMathLine &current = m_mathContent.gui_GetFocusLine();
01122    mcPolynomial &pol = current.gui_GetFocusMem();
01123    pol.math_EmbedInFraction(FALSE);
01124 }
01125 
01126 void mgMathBox::EmbedAsFractionDen(const mcElement &sel)
01127 {
01128    mcMathLine &current = m_mathContent.gui_GetFocusLine();
01129    mcPolynomial &pol = current.gui_GetFocusMem();
01130    pol.math_EmbedInFraction(TRUE);
01131 }
01132 
01133 
01134 
01135 
01136 
01137 // --------------------------------------------
01138 // mgMATHBOX - IO functions
01139 // --------------------------------------------
01140 
01141 wxString mgMathBox::ConvertString(const wxString &str) const
01142 {
01143    if (!bUseNativeNewLines)
01144       return str;
01145 
01146    wxString ret(str);
01147 #if defined(__WXMSW__)
01148    ret.Replace(wxT("\n"), wxT("\r\n"));
01149 #elif defined(__WXMAC__)
01150    ret.Replace(wxT("\n"), wxT("\n\r"));
01151 #endif
01152    return ret;
01153 }
01154 
01155 bool mgMathBox::Export(bool bXHTML, const wxString &filename,
01156                  const wxString &title, bool bMathPlayer, bool bUpperTag,
01157                  bool bUseNS, const wxString &ns, const wxString &href,
01158                  int indentstep) const
01159 {
01160    wxFile f;
01161    wxString err;
01162 
01163    // create a new file with the given name in write mode,
01164    // overwrite existing if necessary
01165    mcASSERT(filename.Len() > 0, wxT("Incorrect file name"));
01166    if (f.Open(filename, wxFile::write) == FALSE) {
01167 
01168       err.Printf(wxT("Cannot overwrite %s. The file is being used by another application\n")
01169          wxT("which opened the file in exclusive mode. Close all the applications that use\n")
01170          wxT("this file and retry, or choose another file name."), filename.c_str());
01171       wxMessageBox(err, wxT("Error"), wxICON_ERROR | wxOK | wxCENTRE);
01172       return FALSE;
01173    }
01174 
01175    wxFileOutputStream stream(f);
01176    mcASSERT(stream.Ok(), wxT("Something wrong with the creation of file"));
01177 
01178    // write in the file using native line ending
01179    //wxTextOutputStream stream(fstream, wxEOL_NATIVE);
01180    return Export(bXHTML, stream, title, bMathPlayer,
01181          bUpperTag, bUseNS, ns, href, indentstep);
01182 }
01183 
01184 wxString mgMathBox::GetExportPreview(bool bXHTML, const wxString &title,
01185                            bool bMathPlayer, bool bUpperTag,
01186                            bool bUseNS, const wxString &ns,
01187                            const wxString &href, int indentstep) const
01188 {
01189    wxStringOutputStream sos;  
01190 
01191    if (Export(bXHTML, sos, title, bMathPlayer,
01192       bUpperTag, bUseNS, ns, href, indentstep) == FALSE)
01193       return wxString(wxT("CANNOT PREVIEW !!!"));
01194 
01195    // retrieve the string result
01196    return sos.GetStr();
01197 }
01198 
01199 bool mgMathBox::Export(bool bXHTML, wxOutputStream &stream,
01200                  const wxString &title, bool bMathPlayer,
01201                   bool bUpperTag, bool bUseNS, const wxString &ns,
01202                   const wxString &href, int indentstep) const
01203 {
01204    wxString err, str;
01205 
01206    //  <?xml version=wxT("1.0") encoding=wxT("UTF-8") standalone="no"?>
01207    wxXml2Document doc;
01208    doc.Create();
01209    doc.SetMathMLDTD();
01210 
01211    wxXml2Node html;
01212    html.CreateRoot(doc, wxT("html"));
01213 
01214    // create the XML header if required:
01215    //  <?xml-stylesheet type=wxT("text/xsl") href="[MathStudio folder]/xsl/mathml.xsl"?>
01216    if (!bXHTML)
01217       doc.SetStyleSheet(href);
01218 
01219    // create HTML header:
01220    //    <html xmlns=wxT("http://www.w3.org/1999/xhtml") xml:lang="en">
01221    //
01222    if (!bUseNS) {
01223 
01224       // just create an HTML decorated with XML DTD
01225       html.AddProperty(wxT("xmlns"), wxT("http://www.w3.org/1999/xhtml"));
01226 
01227    } else {
01228 
01229       // add a namespace
01230       html.AddProperty(wxT("xmlns:") + ns, wxT("http://www.w3.org/1998/Math/MathML"));
01231    }
01232 
01233    html.AddProperty(wxT("lang"), wxT("en"));
01234    html.AddProperty(wxT("xml:lang"), wxT("en"));
01235 
01236    // add the head, title & body tags:
01237    //   <HEAD><TITLE> [title] </TITLE></HEAD>
01238    //   <BODY></BODY>
01239    //
01240    html.AddContainerChild(wxT("head"));
01241    html.Get(wxT("head")).AddTextChild(wxT("title"), title);
01242    wxXml2Node body = html.AddContainerChild(wxT("body"));
01243 
01244    // and a comment:
01245    //    <!-- [MathStudio standard comment] -->.
01246    //
01247    //body.AddBreakLineChild(2);
01248    body.AddCommentChild(
01249       wxT(" MathML 2.0 exported by MathStudio - http://mathstudio.sourceforge.net - ") \
01250       wxT("MathStudio is an open source program released under GPL; please write to ") \
01251       wxT("frm@users.sourceforge.net if you encounter any problem or if you want to ") \
01252       wxT("give suggestions or advices. "));
01253    //body.AddBreakLineChild(2);
01254 
01255    // get math data
01256    wxXml2Node mathcontent(m_mathContent.io_GetMathML(TRUE));
01257 
01258    // create the MATH tag
01259    //   <MATH XMLNS:[namespace prefix if present]=
01260    //         wxT("http://www.w3.org/1998/Math/MathML") DISPLAY=wxT("block") MODE="display">
01261    //
01262    wxXml2Node math(wxXML_ELEMENT_NODE, body, wxT("math"));
01263    wxString prefix(ns);
01264 
01265    // if necessary add namespace syntax
01266    if (bUseNS) {
01267 
01268       if (bMathPlayer) {
01269 
01270          // add MathPlayer really specific lines:
01271          //    <OBJECT ID=MathPlayer CLASSID=></OBJECT>
01272          //    <?IMPORT NAMESPACE=m IMPLEMENTATION=#MathPlayer>
01273          //
01274          wxXml2Node parent(html.Get(wxT("head")));
01275          wxXml2Node obj(wxXML_TEXT_NODE, parent, wxT("object"));
01276          wxXml2Node import(wxXML_ELEMENT_NODE, parent, wxT("import"));
01277 
01278          obj.AddProperty(wxT("id"), wxT("MathPlayer"));
01279          obj.AddProperty(wxT("classid"), wxT("clsid:32F66A20-7614-11D4-BD11-00104BD3F987"));
01280 
01281          // just to force wxXml2Document to add a </OBJECT>
01282          //obj.SetChildren(new wxXml2Node(wxXML_TEXT_NODE, wxT(""), ""));
01283 
01284          import.SetType(wxXML_PI_NODE);
01285          import.SetContent(wxT("namespace=\"") + ns + wxT("\" implementation=\"#MathPlayer\""));
01286       }
01287 
01288       // this automatically adds the namespace to math (note that, even if the object
01289       // "mathns" is destroyed after the following }, the libxml2 object persists).
01290       wxXml2Namespace mathns(prefix, wxT("http://www.w3.org/1998/Math/MathML"), math);
01291 
01292    } else {
01293 
01294       // add a falsehood namespace
01295       // VERY IMPORTANT: without this, Mozilla & Netscape won't be able to
01296       // render mathML....
01297       math.AddProperty(wxT("xmlns"), wxT("http://www.w3.org/1998/Math/MathML"));
01298    }
01299 
01300    // set up MATH tag
01301    math.AddChild(mathcontent);
01302 
01303    // add some predefined attributes
01304    math.AddProperty(wxT("display"), wxT("block"));
01305    math.AddProperty(wxT("mode"), wxT("display"));
01306 
01307    // leave some space between MATH & body tag
01308    //body.AddBreakLineChild(2);
01309 
01310    // if required, make all tags uppercase
01311    if (bUpperTag) {
01312 
01313       // this will work recursively
01314       doc.GetRoot().MakeUpper();
01315    }
01316 
01317    // save document
01318    doc.Save(stream, wxT("UTF-8"), indentstep);
01319 
01320    // cleanup
01321    html.DestroyIfUnlinked();
01322    math.DestroyIfUnlinked();
01323    body.DestroyIfUnlinked();
01324    mathcontent.DestroyIfUnlinked();
01325 
01326    // last, destroy the doc
01327    doc.DestroyIfUnlinked();
01328 
01329    // close file and return OK
01330    return TRUE;
01331 }
01332 
01333 bool mgMathBox::Import(int type, const wxString &filename, wxString *pDesc)
01334 {
01335    wxXml2Document doc;
01336    wxXml2Node root, cur;
01337    wxString str, err;
01338    int n=0;
01339 
01340    // check parameters
01341    mcASSERT(filename.Len() > 0, wxT("Incorrect file name"));
01342 
01343    // load the given file
01344    wxFileInputStream def(filename);
01345    wxString file(filename);
01346    wxString tmpfilename;
01347 
01348    if (def.Ok() == FALSE) {
01349 
01350       // load error
01351       err.Printf(wxT("Cannot read %s. The file is being used by another application\n") \
01352          wxT("which opened the file in exclusive mode. Close all the applications that use\n") \
01353          wxT("this file and retry, or choose another file."), filename.c_str());
01354       wxMessageBox(err, wxT("Error"), wxICON_ERROR | wxOK | wxCENTRE);
01355       return FALSE;
01356    }
01357 
01358    // check if loaded file is an XML or an XHTML file
01359    def.Read(str.GetWriteBuf(16), 16);
01360    str.UngetWriteBuf();
01361    def.SeekI(0);
01362 
01363    if (str.CmpNoCase(wxT("<?xml")) != 0 || str.CmpNoCase(wxT("<? xml")) != 0) {
01364 
01365       // we must convert this (X)HTML file to an XML file; we will use
01366       // a temporary file
01367       tmpfilename = wxFileName::CreateTempFileName(wxT("ms"));
01368       wxFileOutputStream tmpoutstream(tmpfilename);
01369 
01370       wxString xmlhdr = wxT("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n")
01371          wxT("<?xml-stylesheet type=\"text/xsl\" href=\")") + wxGetCwd() +
01372          wxT("/XSL/mathml.xsl\"?>\n");
01373 
01374       tmpoutstream.Write(xmlhdr, xmlhdr.Len());
01375       //tmpoutstream.SeekO(0, wxFromEnd);
01376       tmpoutstream.Write(def);
01377       file = tmpfilename;
01378    }
01379 
01380    // parse the given file
01381    if (doc.Load(file, &err) == FALSE) {
01382 
01383       // parse error
01384       wxMessageBox(wxT("There was an error while parsing and the given file\n")
01385          wxT("couldn't be imported. Error description:\n\n'") + err + wxT("'"),
01386          wxT("Error"), wxICON_ERROR | wxOK | wxCENTRE);
01387       if (!tmpfilename.IsEmpty())
01388          wxRemoveFile(tmpfilename);
01389       return FALSE;
01390    }
01391 
01392    // delete the eventually created temporary file
01393    if (!tmpfilename.IsEmpty())
01394       wxRemoveFile(tmpfilename);
01395 
01396    // find MATH tags and import their contents; ignore everything else
01397    root = doc.GetRoot();
01398    cur = root.Find(wxT("math"), wxT(""), 0, FALSE);
01399 
01400    if (cur == wxXml2EmptyNode) {
01401       // we couldn't find it
01402       err.Printf(wxT("Cannot find the MathML main tag <MATH>. The file does not contain\n")
01403          wxT("any MathML information or it is corrupt."));
01404       wxMessageBox(err, wxT("Error"), wxICON_ERROR | wxOK | wxCENTRE);
01405       return FALSE;
01406    }
01407 
01408    // extract MathML content from the xml document
01409    while (cur != wxXml2EmptyNode) {
01410 
01411       wxXml2Node toparse = cur.GetChildren();
01412 
01413       while (toparse != wxXml2EmptyNode) {
01414 
01415          // be sure everything is embedded in an MROW section
01416          if (toparse.GetType() == wxXML_ELEMENT_NODE) {
01417 
01418             if (toparse.GetName() != wxT("mrow"))
01419                toparse.Encapsulate(wxT("mrow"));
01420 
01421             // add a new line and import this MATH tags in it
01422             //if (n > 0) AddLine(FALSE);
01423             m_mathContent.io_ImportPresentationMathML(toparse, err);
01424          }
01425 
01426          toparse = toparse.GetNext();
01427       }
01428 
01429       // search other MATH tags
01430       cur = root.Find(wxT("math"), wxT(""), n, FALSE);
01431    }
01432 
01433    root.DestroyIfUnlinked();
01434    cur.DestroyIfUnlinked();
01435    doc.DestroyIfUnlinked();
01436 
01437    return TRUE;
01438 }
01439 
01440 bool mgMathBox::ImportInlinedExpr(const wxString &str)
01441 {
01442    bool res = m_mathContent.io_ImportInlinedExpr(str);
01443 
01444    // update GUI
01445    m_mathContent.gui_SetFocusIdx(m_mathContent.data_GetCount()-1);
01446    m_mathContent.gui_SetCursorPos(mcCP_END);
01447    ResetGUI();
01448 
01449    return res;
01450 }
01451 
01452 
01453 
01454 
01455 
01456 // --------------------------------------------
01457 // mgRESIZEABLEBOX
01458 // --------------------------------------------
01459 
01460 IMPLEMENT_CLASS(mgResizeableBox, wxResizeableControl)
01461 BEGIN_EVENT_TABLE(mgResizeableBox, wxResizeableControl)
01462 
01463    // miscellaneous events
01464    EVT_SIZE(mgResizeableBox::OnSize)
01465    EVT_PAINT(mgResizeableBox::OnPaint)
01466    //EVT_SET_FOCUS(mgResizeableBox::OnSetFocus)
01467    EVT_KILL_FOCUS(mgResizeableBox::OnKillFocus)
01468    EVT_SET_CURSOR(mgResizeableBox::OnSetCursor)
01469 
01470    EVT_MOVE(mgResizeableBox::OnMove)
01471 
01472    // OnChildResize() handles messages sent by mgMathBox::FitContents
01473    // functions: that is, it handles messages sent on child's resize
01474    EVT_CHILD_RESIZED(wxID_ANY, mgResizeableBox::OnChildResize)
01475    //EVT_CHILD_SETFOCUS(wxID_ANY, mgResizeableBox::OnChildSetFocus)
01476    //EVT_CHILD_KILLFOCUS(wxID_ANY, mgResizeableBox::OnChildKillFocus)
01477 
01478 END_EVENT_TABLE()
01479 
01480 
01481 mgResizeableBox::mgResizeableBox(wxWindow *parent,
01482       wxWindowID id,
01483       const wxPoint &pos,
01484       const wxSize &size) :
01485          wxResizeableControl(parent, id, pos,  size, wxSIMPLE_BORDER |
01486             wxCLIP_CHILDREN | wxNO_FULL_REPAINT_ON_RESIZE, wxT("ResizeableBox"))
01487 {
01488    // set up basic values
01489    //m_bFocus = m_bChildFocus = FALSE;
01490    //SetBackgroundColour(wxColour(255, 255, 0));      // yellow
01491    SetMinBorder(wxResizeableControl::SizeXRad*2+1);
01492 
01493    // hack the wxResizeableControl focus system...
01494    //m_hasfocus = TRUE;
01495    //m_movemode = MoveWin;
01496    //SetFocus();
01497    wxMoveEvent ev(pos);
01498    //OnMove(ev);
01499    this->AddPendingEvent(ev);
01500 }
01501 
01502 mgResizeableBox::mgResizeableBox(const mgResizeableBox &tocopy) :
01503       wxResizeableControl(tocopy.GetParent(), tocopy.GetId(),
01504                      tocopy.GetPosition(), tocopy.GetClientSize(),
01505                      tocopy.GetWindowStyle(), tocopy.GetName())
01506 {
01507    // deep copies not only window attributes, also math data
01508    DeepCopy(tocopy);
01509 }
01510 
01511 void mgResizeableBox::DeepCopy(const mgResizeableBox &tocopy)
01512 {
01513    // there's not a lot of things to copy.....
01514    m_nMinBorder = tocopy.m_nMinBorder;
01515 }
01516 
01517 int mgResizeableBox::GetBorder()
01518 {
01519    // this should be a positive number, not too small (not less than
01520    // wxResizeableControl::SizeXRad, otherwise the squares positioned
01521    // on the perimeter of this window's bounding box, won't be correctly
01522    // drawn).
01523    return m_nMinBorder;
01524 }
01525 
01526 void mgResizeableBox::SetMinBorder(int n)
01527 {
01528    // set the new border
01529    m_nMinBorder = n;
01530    if (GetChild()) GetChild()->Move(GetBorder(), GetBorder());
01531 
01532    // simulate an OnSize event
01533    wxSizeEvent ev(GetClientSize());
01534    OnSize(ev);
01535 }
01536 /*
01537 void mgResizeableBox::SetFocus()
01538 {
01539    //if (GetChild()) GetChild()->SetFocus();
01540    wxFocusEvent ev(wxEVT_SET_FOCUS, GetId());
01541    OnSetFocus(ev);
01542 }*/
01543 
01544 wxString mgResizeableBox::GetDebug()
01545 {
01546    return wxT("If you want to get debug info about this resizeable box, ") \
01547       wxT("override the GetDebug() function.");
01548 }
01549 
01550 void mgResizeableBox::OnChildResize(wxCommandEvent &event)
01551 {
01552    if (GetChild()) {
01553       int w = GetChild()->GetSize().GetWidth()+GetBorder()*2+2,
01554          h = GetChild()->GetSize().GetHeight()+GetBorder()*2+2;
01555       wxSize newsz = GetSize();
01556 
01557       // check if we must expand this window to contain entirely the mathbox
01558       if (w > newsz.GetWidth()) newsz.SetWidth(w);
01559       if (h > newsz.GetHeight()) newsz.SetHeight(h);
01560       SetSize(newsz);
01561 
01562       Refresh();
01563    }
01564 }
01565 
01566 void mgResizeableBox::OnSize(wxSizeEvent &event)
01567 {
01568    if (GetChild() && m_hasfocus) {
01569 
01570       // subtract to the new size the borders
01571       event.m_size.SetWidth(event.GetSize().GetWidth()-GetBorder()*2-2);
01572       event.m_size.SetHeight(event.GetSize().GetHeight()-GetBorder()*2-2);
01573 
01574       // change event ID
01575       event.m_id = GetChild()->GetId();
01576 
01577       // resize the mathbox and then check if it is okay
01578       GetChild()->SetSize(event.GetSize());
01579    }
01580 
01581    // always recall base class event handler
01582    event.Skip();
01583 }
01584 
01585 
01586 
01587 
01588 
01589 void mgResizeableBox::OnSetFocus(wxFocusEvent &event)
01590 {
01591    // give focus to the contained window, so, cursor begins to
01592    // flash, warning the user we are ready to receive inputs
01593    //if (GetChild()) GetChild()->SetFocus();
01594    //mgLogDebug("mgResizeableBox::OnSetFocus [%d] dropped focus to child", GetId());
01595    //Show();
01596 
01597    // let wxResizeableControl believe that we now have got the focus...
01598    event.Skip();
01599 }
01600 
01601 void mgResizeableBox::OnChildSetFocus(wxCommandEvent &ev)
01602 {
01603    // draw size rect
01604    if (!m_hasfocus) {
01605       Raise();
01606       Update();
01607       m_hasfocus = true;
01608    }
01609 
01610    wxClientDC dc(this);
01611    ForceDrawSizeRect(dc);
01612 
01613    mgLogDebug(wxT("mgResizeableBox::OnChildSetFocus [%d] child has received focus"), GetId());
01614 }
01615 
01616 
01617 
01618 
01619 
01620 bool isChildren(wxWindow *parent, wxWindow *child)
01621 {
01622    for (wxWindowList::Node *tocheck = parent->GetChildren().GetFirst(); tocheck;
01623                            tocheck = tocheck->GetNext()) {
01624       if (child == tocheck->GetData() || isChildren(tocheck->GetData(), child))
01625          return TRUE;
01626    }
01627 
01628    return FALSE;
01629 }
01630 
01631 void mgResizeableBox::OnKillFocus(wxFocusEvent &event)
01632 {
01633    /*mgLogDebug(wxT("mgResizeableBox::OnKillFocus [%d] lost ") \
01634       wxT("focus by resizeable control; done nothing"), GetId()); */
01635    //Hide();
01636    event.Skip();
01637 }
01638 
01639 void mgResizeableBox::OnChildKillFocus(wxCommandEvent &event)
01640 {
01641    wxWindow *focused = FindFocus();
01642    if (!isChildren(this, focused) && focused != this) {
01643 
01644       // erase size rect
01645       m_hasfocus = false;
01646       wxClientDC dc(this);
01647       EraseSizeRect(dc);
01648 
01649       //SetSize(GetChild()->GetSize());
01650       //GetChild()->Move(0, 0);
01651 
01652       mgLogDebug(wxT("mgResizeableBox::OnChildKillFocus [%d] focus ") \
01653          wxT("has been definetely lost"), GetId());
01654 
01655    } else {
01656 
01657       mgLogDebug(wxT("mgResizeableBox::OnChildKillFocus [%d] focus has ") \
01658          wxT("been set on the resizeable control or one of its children"), GetId());
01659    }
01660 }
01661 
01662 
01663 
01664 
01665 void mgResizeableBox::OnMove(wxMoveEvent &ev)
01666 {
01667    /*if (m_hasfocus) { //FindFocus() == this) {
01668       wxPaintDC dc(this);
01669 
01670       // if required, draw the 8 squares that the user can use
01671       // to resize this (resizeable !!) window
01672       DrawSizeRect(dc);
01673    }*/
01674    if (GetChild())
01675       GetChild()->Move(ev.GetPosition().x+GetBorder(), ev.GetPosition().y+GetBorder());
01676 
01677    //if (GetChild())
01678    // GetChild()->Refresh();
01679 }
01680 
01681 void mgResizeableBox::OnPaint(wxPaintEvent &ev)
01682 {
01683    if (m_hasfocus) { //FindFocus() == this) {
01684       wxPaintDC dc(this);
01685 
01686       wxBrush brsh(wxColour(0, 0, 0), wxBDIAGONAL_HATCH   );
01687       dc.SetBrush(brsh);
01688       dc.DrawRectangle(wxPoint(0, 0), GetClientSize());
01689 
01690       // if required, draw the 8 squares that the user can use
01691       // to resize this (resizeable !!) window
01692       DrawSizeRect(dc);
01693    }
01694 
01695    //if (GetChild())
01696    // GetChild()->Refresh();
01697 }
01698 /*
01699 void mgResizeableBox::Refresh(bool eraseBackground, const wxRect* rect)
01700 {
01701    if (GetChild()) GetChild()->Refresh();
01702    wxWindow::Refresh(eraseBackground, rect);
01703 }
01704 */
01705 void mgResizeableBox::OnSetCursor(wxSetCursorEvent &ev)
01706 {
01707    // recall wxResizeableControl SetCursor event handler only if the
01708    // cursor is inside this window, but outside the contained math box
01709    if (!GetChild() || !GetChild()->GetRect().Inside(wxPoint(ev.GetX(), ev.GetY())))
01710       ev.Skip();
01711 }
01712 
01713 
01714 
01715 
01716 
01718 // mcRESIZEABLEMATHBOX
01719 IMPLEMENT_CLASS(mgResizeableMathBox, mgResizeableBox)
01720 BEGIN_EVENT_TABLE(mgResizeableMathBox, mgResizeableBox)
01721 
01722    // miscellaneous events
01723    /*EVT_SIZE(mgResizeableMathBox::OnSize)*/
01724 
01725 END_EVENT_TABLE()
01726 
01727 
01728 mgResizeableMathBox::mgResizeableMathBox(wxWindow *parent,
01729       wxWindowID id, const wxPoint &pos, const wxSize &size) :
01730          mgResizeableBox(parent, id, pos,  size)//,   m_mathBox(this)
01731 {
01732    m_pMathBox = new mgMathBox(this);
01733    SetMinBorder(wxResizeableControl::SizeXRad*2+1);
01734    //SetFocus();
01735 
01736    //wxMouseEvent ev(wxEVT_LEFT_DOWN);
01737    //OnLButtonDown(ev);
01738    //wxFocusEvent ev(wxEVT_SET_FOCUS, GetId());
01739    //OnSetFocus(ev);
01740 }
01741 
01742 mgResizeableMathBox::mgResizeableMathBox(const mgResizeableMathBox &tocopy) :
01743       mgResizeableBox(tocopy.GetParent(), tocopy.GetId(), tocopy.GetPosition(),
01744          tocopy.GetClientSize())//, m_mathBox(tocopy.m_mathBox)
01745 {
01746    m_pMathBox = new mgMathBox(*tocopy.m_pMathBox);
01747 
01748    // deep copies not only window attributes, also math data
01749    DeepCopy(tocopy);
01750 }
01751 
01752 void mgResizeableMathBox::DeepCopy(const mgResizeableMathBox &tocopy)
01753 {
01754    mgResizeableBox::DeepCopy(tocopy);
01755 
01756    // deep copy the math data contained
01757    m_pMathBox->DeepCopy(*tocopy.m_pMathBox);
01758 }
01759 
01760 wxString mgResizeableMathBox::GetDebug()
01761 {
01762    return m_pMathBox->GetDebug();
01763 }
01764 
01765 // mcRESIZEABLEMATHBOX event handlers
01766 /*
01767 void mgResizeableMathBox::OnSize(wxSizeEvent &event)
01768 {
01769    mgResizeableBox::OnSize(event);
01770    m_pMathBox->FitContents();
01771 }*/
01772 
01773 
01774 
01775 
01776 
01777 
01778 
01779 
01781 // mcRESIZEABLEMATHBOX
01782 IMPLEMENT_CLASS(mgResizeableTextBox, mgResizeableBox)
01783 BEGIN_EVENT_TABLE(mgResizeableTextBox, mgResizeableBox)
01784 
01785 END_EVENT_TABLE()
01786 
01787 
01788 mgResizeableTextBox::mgResizeableTextBox(
01789       wxWindow *parent,
01790       wxWindowID id,
01791       const wxPoint &pos,
01792       const wxSize &size) :
01793          //wxTextCtrl(this, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE),
01794          mgResizeableBox(parent, id, pos, size)
01795 {
01796    // default size & position will be modified as soon as we set the min
01797    // border of this window
01798    m_pTextCtrl = new wxTextCtrl(parent, -1, wxT(""), wxDefaultPosition,
01799       wxDefaultSize, wxTE_MULTILINE);
01800    //m_pTextCtrl->SetWindowStyle(m_pTextCtrl->GetWindowStyle() & (~wxVSCROLL));
01801 
01802    // set some default properties
01803    //SetBackgroundColour(wxColour(0, 255, 0));
01804    SetMinBorder(wxResizeableControl::SizeXRad*2+1);
01805 }
01806 /*
01807 mgResizeableTextBox::mgResizeableTextBox(const mgResizeableTextBox &tocopy) :
01808       mgResizeableBox(tocopy.GetParent(), tocopy.GetId(),
01809                      tocopy.GetPosition(), tocopy.GetClientSize())
01810 {
01811    m_pTextCtrl = new wxTextCtrl(this, -1, wxT(""), wxDefaultPosition,
01812       wxDefaultSize, wxTE_MULTILINE);
01813 
01814    // deep copies not only window attributes, also math data
01815    DeepCopy(tocopy);
01816 }
01817 
01818 void mgResizeableTextBox::DeepCopy(const mgResizeableTextBox &tocopy)
01819 {
01820    mgResizeableBox::DeepCopy(tocopy);
01821 
01822    // deep copy the math data contained
01823    m_pTextCtrl->Clear();
01824    m_pTextCtrl->WriteText(tocopy.m_pTextCtrl->GetValue());
01825 }
01826 */
01827 wxString mgResizeableTextBox::GetDebug()
01828 {
01829    return wxT("Resizeable TEXT box content: ") + m_pTextCtrl->GetValue();
01830 }
01831 
01832 
01833 
01834 
01835 
01836 
01837 
01838 
01839 
01840 
01841 
01842 
01843 /*
01844 mgResizeableBox2::mgResizeableBox2()
01845 {
01846    // set up basic values
01847    //m_bFocus = m_bChildFocus = FALSE;
01848    SetBackgroundColour(wxColour(255, 255, 0));     // yellow
01849    SetMinBorder(wxResizeableControl::SizeXRad*2+1);
01850 
01851    // hack the wxResizeableControl focus system...
01852    //m_hasfocus = TRUE;
01853    //m_movemode = MoveWin;
01854    //SetFocus();
01855 }
01856 /*
01857 mgResizeableBox2::mgResizeableBox2(const mgResizeableBox2 &tocopy) :
01858       wxResizeableControl(tocopy.GetParent(), tocopy.GetId(),
01859                      tocopy.GetPosition(), tocopy.GetClientSize(),
01860                      tocopy.GetWindowStyle(), tocopy.GetName())
01861 {
01862    // deep copies not only window attributes, also math data
01863    DeepCopy(tocopy);
01864 }
01865 
01866 void mgResizeableBox2::DeepCopy(const mgResizeableBox2 &tocopy)
01867 {
01868    // there's not a lot of things to copy.....
01869    m_nMinBorder = tocopy.m_nMinBorder;
01870 }*/
01871 /*
01872 int mgResizeableBox2::GetBorder()
01873 {
01874    // this should be a positive number, not too small (not less than
01875    // wxResizeableControl::SizeXRad, otherwise the squares positioned
01876    // on the perimeter of this window's bounding box, won't be correctly
01877    // drawn).
01878    return m_nMinBorder;
01879 }
01880 
01881 void mgResizeableBox2::SetMinBorder(int n)
01882 {
01883    // set the new border
01884    m_nMinBorder = n;
01885    if (GetChild()) GetChild()->Move(GetBorder(), GetBorder());
01886 
01887    // simulate an OnSize event
01888    //wxSizeEvent ev(GetClientSize());
01889    //OnSize(ev);
01890 }
01891 /*
01892 void mgResizeableBox2::SetFocus()
01893 {
01894    //if (GetChild()) GetChild()->SetFocus();
01895    wxFocusEvent ev(wxEVT_SET_FOCUS, GetId());
01896    OnSetFocus(ev);
01897 }*/
01898 /*
01899 wxString mgResizeableBox2::GetDebug()
01900 {
01901    return wxT("If you want to get debug info about this resizeable box, ") \
01902       wxT("override the GetDebug() function.");
01903 }
01904 /*
01905 void mgResizeableBox2::OnChildResize(wxCommandEvent &event)
01906 {
01907    if (GetChild()) {
01908       int w = GetChild()->GetSize().GetWidth()+GetBorder()*2+2,
01909          h = GetChild()->GetSize().GetHeight()+GetBorder()*2+2;
01910       wxSize newsz = GetSize();
01911 
01912       // check if we must expand this window to contain entirely the mathbox
01913       if (w > newsz.GetWidth()) newsz.SetWidth(w);
01914       if (h > newsz.GetHeight()) newsz.SetHeight(h);
01915       SetSize(newsz);
01916 
01917       Refresh();
01918    }
01919 }*/
01920 /*
01921 void mgResizeableBox2::OnSize(wxSizeEvent &event)
01922 {
01923    /*if (GetChild() && m_hasfocus) {
01924 
01925       // subtract to the new size the borders
01926       event.m_size.SetWidth(event.GetSize().GetWidth()-GetBorder()*2-2);
01927       event.m_size.SetHeight(event.GetSize().GetHeight()-GetBorder()*2-2);
01928 
01929       // change event ID
01930       event.m_id = GetChild()->GetId();
01931 
01932       // resize the mathbox and then check if it is okay
01933       GetChild()->SetSize(event.GetSize());
01934    }*/
01935 /*
01936    // always recall base class event handler
01937    event.Skip();
01938 }
01939 
01940 
01941 
01942 
01943 /*
01944 void mgResizeableBox2::OnSetFocus(wxFocusEvent &event)
01945 {
01946    // give focus to the contained window, so, cursor begins to
01947    // flash, warning the user we are ready to receive inputs
01948    if (GetChild()) GetChild()->SetFocus();
01949    mgLogDebug(wxT("mgResizeableBox2::OnSetFocus [%d] dropped focus to child"), GetId());
01950 
01951    // let wxResizeableControl believe that we now have got the focus...
01952    //event.Skip();
01953 }
01954 
01955 void mgResizeableBox2::OnChildSetFocus(wxCommandEvent &ev)
01956 {
01957    // draw size rect
01958    if (!m_hasfocus) {
01959       Raise();
01960       Update();
01961       m_hasfocus = true;
01962    }
01963 
01964    wxClientDC dc(this);
01965    ForceDrawSizeRect(dc);
01966 
01967    mgLogDebug(wxT("mgResizeableBox2::OnChildSetFocus [%d] child has received focus"), GetId());
01968 }
01969 
01970 */
01971 
01972 
01973 /*
01974 bool isChildren(wxWindow *parent, wxWindow *child)
01975 {
01976    for (wxWindowList::Node *tocheck = parent->GetChildren().GetFirst(); tocheck;
01977                            tocheck = tocheck->GetNext()) {
01978       if (child == tocheck->GetData() || isChildren(tocheck->GetData(), child))
01979          return TRUE;
01980    }
01981 
01982    return FALSE;
01983 }
01984 
01985 void mgResizeableBox2::OnKillFocus(wxFocusEvent &event)
01986 {
01987    mgLogDebug(wxT("mgResizeableBox2::OnKillFocus [%d] lost ") \
01988       wxT("focus by resizeable control; done nothing"), GetId());
01989 }
01990 
01991 void mgResizeableBox2::OnChildKillFocus(wxCommandEvent &event)
01992 {
01993    wxWindow *focused = FindFocus();
01994    if (!isChildren(this, focused) && focused != this) {
01995 
01996       // erase size rect
01997       m_hasfocus = false;
01998       wxClientDC dc(this);
01999       EraseSizeRect(dc);
02000 
02001       //SetSize(GetChild()->GetSize());
02002       //GetChild()->Move(0, 0);
02003 
02004       mgLogDebug(wxT("mgResizeableBox2::OnChildKillFocus [%d] focus ") \
02005          wxT("has been definetely lost"), GetId());
02006 
02007    } else {
02008 
02009       mgLogDebug(wxT("mgResizeableBox2::OnChildKillFocus [%d] focus has ") \
02010          wxT("been set on the resizeable control or one of its children"), GetId());
02011    }
02012 }
02013 
02014 
02015 */
02016 
02017 /*
02018 void mgResizeableBox2::OnPaint(wxPaintEvent &ev)
02019 {
02020    if (m_hasfocus) { //FindFocus() == this) {
02021       //wxPaintDC dc(this);
02022 
02023       // if required, draw the 8 squares that the user can use
02024       // to resize this (resizeable !!) window
02025       //DrawSizeRect(dc);
02026    }
02027 /*
02028    if (GetChild())
02029       GetChild()->Refresh();*//*
02030 }
02031 /*
02032 void mgResizeableBox2::Refresh(bool eraseBackground, const wxRect* rect)
02033 {
02034    if (GetChild()) GetChild()->Refresh();
02035    wxWindow::Refresh(eraseBackground, rect);
02036 }*//*
02037 
02038 void mgResizeableBox2::OnSetCursor(wxSetCursorEvent &ev)
02039 {
02040    // recall wxResizeableControl SetCursor event handler only if the
02041    // cursor is inside this window, but outside the contained math box
02042    if (!GetChild() || !GetChild()->GetRect().Inside(wxPoint(ev.GetX(), ev.GetY())))
02043       ev.Skip();
02044 }
02045 
02046 */
02047 
02048 
02049 
02050 
02051 


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

[ Top ]