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 ¤t = 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 ¤t = 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
[ Top ] |