]> git.saurik.com Git - wxWidgets.git/blob - src/mgl/window.cpp
Fixed project files for regex.lib, taking the regex C files out of the main wxvc.dsp
[wxWidgets.git] / src / mgl / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/mgl/window.cpp
3 // Purpose: wxWindow
4 // Author: Vaclav Slavik
5 // (based on GTK & MSW implementations)
6 // RCS-ID: $Id$
7 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
8 // Licence: wxWindows license
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ===========================================================================
12 // declarations
13 // ===========================================================================
14
15 // ---------------------------------------------------------------------------
16 // headers
17 // ---------------------------------------------------------------------------
18
19 #ifdef __GNUG__
20 #pragma implementation "window.h"
21 #endif
22
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #ifndef WX_PRECOMP
31 #include "wx/window.h"
32 #include "wx/accel.h"
33 #include "wx/setup.h"
34 #include "wx/dc.h"
35 #include "wx/dcclient.h"
36 #include "wx/utils.h"
37 #include "wx/app.h"
38 #include "wx/panel.h"
39 #include "wx/caret.h"
40 #endif
41
42 #if wxUSE_DRAG_AND_DROP
43 #include "wx/dnd.h"
44 #endif
45
46 #include "wx/log.h"
47 #include "wx/sysopt.h"
48 #include "wx/mgl/private.h"
49 #include "wx/intl.h"
50 #include "wx/dcscreen.h"
51
52 #include <mgraph.hpp>
53
54 #if wxUSE_TOOLTIPS
55 #include "wx/tooltip.h"
56 #endif
57
58 // ---------------------------------------------------------------------------
59 // global variables
60 // ---------------------------------------------------------------------------
61
62 // MGL window manager and associated DC.
63 winmng_t *g_winMng = NULL;
64 MGLDevCtx *g_displayDC = NULL;
65
66 extern wxList WXDLLEXPORT wxPendingDelete;
67 // FIXME_MGL -- ???
68
69 // the window that has keyboard+joystick focus:
70 static wxWindowMGL *g_focusedWindow = NULL;
71 // the window that is currently under mouse cursor:
72 static wxWindowMGL *g_windowUnderMouse = NULL;
73
74 // ---------------------------------------------------------------------------
75 // constants
76 // ---------------------------------------------------------------------------
77
78 // Custom identifiers used to distinguish between various event handlers
79 // and capture handlers passed to MGL_wm
80 enum
81 {
82 wxMGL_CAPTURE_MOUSE = 1,
83 wxMGL_CAPTURE_KEYB = 2
84 };
85
86
87 // ---------------------------------------------------------------------------
88 // private functions
89 // ---------------------------------------------------------------------------
90
91 // wxCreateMGL_WM creates MGL display DC and associates it with winmng_t
92 // structure. Dimensions and depth of the DC are fetched from wxSystemOptions
93 // object.
94 // This function is *not* called from wxApp's initialization but rather at
95 // the time when WM is needed, i.e. when first wxWindow is created. This
96 // has two important effects:
97 // a) it is possible to write windowless wxMGL apps
98 // b) the app has plenty of time in wxApp::OnInit to feed wxSystemOptions
99 // with desired settings
100
101 bool wxCreateMGL_WM()
102 {
103 int mode;
104 int width = 640, height = 480, depth = 16;
105 int refresh = MGL_DEFAULT_REFRESH;
106
107 #if wxUSE_SYSTEM_OPTIONS
108 if ( wxSystemOptions::HasOption(wxT("mgl.screen-width") )
109 width = wxSystemOptions::GetOptionInt(wxT("mgl.screen-width"));
110 if ( wxSystemOptions::HasOption(wxT("mgl.screen-height") )
111 height = wxSystemOptions::GetOptionInt(wxT("mgl.screen-height"));
112 if ( wxSystemOptions::HasOption(wxT("mgl.screen-depth") )
113 depth = wxSystemOptions::GetOptionInt(wxT("mgl.screen-depth"));
114 if ( wxSystemOptions::HasOption(wxT("mgl.screen-refresh") )
115 refresh = wxSystemOptions::GetOptionInt(wxT("mgl.screen-refresh"));
116 #endif
117
118 mode = MGL_findMode(width, height, depth);
119 if ( mode == -1 )
120 {
121 wxLogWarning(_("Mode %ix%i-%i not available, falling back to default mode."), width, height, depth);
122 mode = 0; // always available
123 }
124 g_displayDC = new MGLDisplayDC(mode, 1, refresh);
125 if ( !g_displayDC->isValid() )
126 {
127 delete g_displayDC;
128 g_displayDC = NULL;
129 return FALSE;
130 }
131
132 g_winMng = MGL_wmCreate(g_displayDC->getDC());
133 if (!g_winMng)
134 return FALSE;
135
136 return TRUE;
137 }
138
139 void wxDestroyMGL_WM()
140 {
141 if ( g_winMng )
142 {
143 MGL_wmDestroy(g_winMng);
144 g_winMng = NULL;
145 }
146 if ( g_displayDC )
147 {
148 delete g_displayDC;
149 g_displayDC = NULL;
150 }
151 }
152
153 // ---------------------------------------------------------------------------
154 // MGL_WM hooks:
155 // ---------------------------------------------------------------------------
156
157 static void wxWindowPainter(window_t *wnd, MGLDC *dc)
158 {
159 wxWindowMGL *w = (wxWindow*) wnd->userData;
160 if (w)
161 {
162 MGLDevCtx ctx(dc);
163 w->HandlePaint(&ctx);
164 }
165 }
166
167 // ---------------------------------------------------------------------------
168 // event tables
169 // ---------------------------------------------------------------------------
170
171 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
172 // method
173 IMPLEMENT_ABSTRACT_CLASS(wxWindowMGL, wxWindowBase)
174
175 BEGIN_EVENT_TABLE(wxWindowMGL, wxWindowBase)
176 END_EVENT_TABLE()
177
178 // ===========================================================================
179 // implementation
180 // ===========================================================================
181
182 // ----------------------------------------------------------------------------
183 // constructors and such
184 // ----------------------------------------------------------------------------
185
186 void wxWindowMGL::Init()
187 {
188 // generic:
189 InitBase();
190
191 // mgl specific:
192 if ( !g_winMng && !wxCreateMGL_WM() )
193 wxFatalError(_T("Can't initalize MGL, aborting!"));
194
195 m_wnd = NULL;
196 m_isShown = TRUE;
197 m_isBeingDeleted = FALSE;
198 m_isEnabled = TRUE;
199 m_frozen = FALSE;
200 m_paintMGLDC = NULL;
201 }
202
203 // Destructor
204 wxWindowMGL::~wxWindowMGL()
205 {
206 m_isBeingDeleted = TRUE;
207
208 if ( g_focusedWindow == this )
209 KillFocus();
210
211 #if 0 // -- fixme - do we need this?
212 // VS: make sure there's no wxFrame with last focus set to us:
213 for (wxWindow *win = GetParent(); win; win = win->GetParent())
214 {
215 wxFrame *frame = wxDynamicCast(win, wxFrame);
216 if ( frame )
217 {
218 if ( frame->GetLastFocus() == this )
219 frame->SetLastFocus((wxWindow*)NULL);
220 break;
221 }
222 }
223 #endif
224
225 // VS: destroy children first and _then_ detach *this from its parent.
226 // If we'd do it the other way around, children wouldn't be able
227 // find their parent frame (see above).
228 DestroyChildren();
229
230 if ( m_parent )
231 m_parent->RemoveChild(this);
232
233 if ( m_wnd )
234 MGL_wmDestroyWindow(m_wnd);
235 }
236
237 // real construction (Init() must have been called before!)
238 bool wxWindowMGL::Create(wxWindow *parent,
239 wxWindowID id,
240 const wxPoint& pos,
241 const wxSize& size,
242 long style,
243 const wxString& name)
244 {
245 // FIXME_MGL -- temporary!
246 //wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
247
248 if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
249 return FALSE;
250
251 if ( parent ) // FIXME_MGL temporary
252 parent->AddChild(this);
253 else
254 m_isShown=FALSE;// FIXME_MGL -- temporary, simulates wxTLW/wxFrame
255
256 if ( style & wxPOPUP_WINDOW )
257 {
258 // it is created hidden as other top level windows
259 m_isShown = FALSE;
260 }
261
262 m_wnd = MGL_wmCreateWindow(g_winMng,
263 parent ? parent->GetHandle() : NULL,
264 pos.x, pos.y, size.x, size.y);
265 MGL_wmSetWindowUserData(m_wnd, (void*) this);
266 MGL_wmSetWindowPainter(m_wnd, wxWindowPainter);
267 return TRUE;
268 }
269
270 // ---------------------------------------------------------------------------
271 // basic operations
272 // ---------------------------------------------------------------------------
273
274 void wxWindowMGL::SetFocus()
275 {
276 if (g_focusedWindow)
277 g_focusedWindow->KillFocus();
278
279 g_focusedWindow = this;
280
281 MGL_wmCaptureEvents(GetHandle(), EVT_KEYEVT | EVT_JOYEVT, wxMGL_CAPTURE_KEYB);
282
283 #if wxUSE_CARET
284 // caret needs to be informed about focus change
285 wxCaret *caret = GetCaret();
286 if (caret)
287 caret->OnSetFocus();
288 #endif // wxUSE_CARET
289
290 if (IsTopLevel())
291 {
292 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, GetId());
293 event.SetEventObject(this);
294 GetEventHandler()->ProcessEvent(event);
295 }
296
297 wxFocusEvent event(wxEVT_SET_FOCUS, GetId());
298 event.SetEventObject(this);
299 GetEventHandler()->ProcessEvent(event);
300 }
301
302 void wxWindowMGL::KillFocus()
303 {
304 if ( g_focusedWindow != this ) return;
305 g_focusedWindow = NULL;
306
307 if ( m_isBeingDeleted ) return;
308
309 MGL_wmUncaptureEvents(GetHandle(), wxMGL_CAPTURE_KEYB);
310
311 #if wxUSE_CARET
312 // caret needs to be informed about focus change
313 wxCaret *caret = GetCaret();
314 if ( caret )
315 caret->OnKillFocus();
316 #endif // wxUSE_CARET
317
318 if ( IsTopLevel() )
319 {
320 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, GetId());
321 event.SetEventObject(this);
322 GetEventHandler()->ProcessEvent(event);
323 }
324
325 wxFocusEvent event(wxEVT_KILL_FOCUS, GetId());
326 event.SetEventObject(this);
327 GetEventHandler()->ProcessEvent(event);
328 }
329
330 // ----------------------------------------------------------------------------
331 // this wxWindowBase function is implemented here (in platform-specific file)
332 // because it is static and so couldn't be made virtual
333 // ----------------------------------------------------------------------------
334 wxWindow *wxWindowBase::FindFocus()
335 {
336 return (wxWindow*)g_focusedWindow;
337 }
338
339 bool wxWindowMGL::Show(bool show)
340 {
341 if ( !wxWindowBase::Show(show) )
342 return FALSE;
343
344 MGL_wmShowWindow(m_wnd, show);
345 return TRUE;
346 }
347
348 // Raise the window to the top of the Z order
349 void wxWindowMGL::Raise()
350 {
351 MGL_wmRaiseWindow(m_wnd);
352 }
353
354 // Lower the window to the bottom of the Z order
355 void wxWindowMGL::Lower()
356 {
357 MGL_wmLowerWindow(m_wnd);
358 }
359
360 void wxWindowMGL::CaptureMouse()
361 {
362 MGL_wmCaptureEvents(m_wnd, EVT_MOUSEEVT, wxMGL_CAPTURE_MOUSE);
363 }
364
365 void wxWindowMGL::ReleaseMouse()
366 {
367 MGL_wmUncaptureEvents(m_wnd, wxMGL_CAPTURE_MOUSE);
368 }
369
370 /* static */ wxWindow *wxWindowBase::GetCapture()
371 {
372 for (captureentry_t *c = g_winMng->capturedEvents; c; c = c->next)
373 {
374 if ( c->id == wxMGL_CAPTURE_MOUSE )
375 return (wxWindow*)c->wnd->userData;
376 }
377 return NULL;
378 }
379
380 bool wxWindowMGL::SetCursor(const wxCursor& cursor)
381 {
382 if ( !wxWindowBase::SetCursor(cursor) )
383 {
384 // no change
385 return FALSE;
386 }
387
388 if ( m_cursor.Ok() )
389 MGL_wmSetWindowCursor(m_wnd, *m_cursor.GetMGLCursor());
390
391 return TRUE;
392 }
393
394 void wxWindowMGL::WarpPointer(int x, int y)
395 {
396 ClientToScreen(&x, &y);
397 EVT_setMousePos(x, y);
398 }
399
400 #if WXWIN_COMPATIBILITY
401 // If nothing defined for this, try the parent.
402 // E.g. we may be a button loaded from a resource, with no callback function
403 // defined.
404 void wxWindowMGL::OnCommand(wxWindow& win, wxCommandEvent& event)
405 {
406 if ( GetEventHandler()->ProcessEvent(event) )
407 return;
408 if ( m_parent )
409 m_parent->GetEventHandler()->OnCommand(win, event);
410 }
411 #endif // WXWIN_COMPATIBILITY_2
412
413 #if WXWIN_COMPATIBILITY
414 wxObject* wxWindowMGL::GetChild(int number) const
415 {
416 // Return a pointer to the Nth object in the Panel
417 wxNode *node = GetChildren().First();
418 int n = number;
419 while (node && n--)
420 node = node->Next();
421 if ( node )
422 {
423 wxObject *obj = (wxObject *)node->Data();
424 return(obj);
425 }
426 else
427 return NULL;
428 }
429 #endif // WXWIN_COMPATIBILITY
430
431 // Set this window to be the child of 'parent'.
432 bool wxWindowMGL::Reparent(wxWindowBase *parent)
433 {
434 if ( !wxWindowBase::Reparent(parent) )
435 return FALSE;
436
437 MGL_wmReparentWindow(m_wnd, parent->GetHandle());
438
439 return TRUE;
440 }
441
442
443 // ---------------------------------------------------------------------------
444 // drag and drop
445 // ---------------------------------------------------------------------------
446
447 #if wxUSE_DRAG_AND_DROP
448
449 void wxWindowMGL::SetDropTarget(wxDropTarget *pDropTarget)
450 {
451 if ( m_dropTarget != 0 ) {
452 m_dropTarget->Revoke(m_hWnd);
453 delete m_dropTarget;
454 }
455
456 m_dropTarget = pDropTarget;
457 if ( m_dropTarget != 0 )
458 m_dropTarget->Register(m_hWnd);
459 }
460 // FIXME_MGL
461 #endif // wxUSE_DRAG_AND_DROP
462
463 // old style file-manager drag&drop support: we retain the old-style
464 // DragAcceptFiles in parallel with SetDropTarget.
465 void wxWindowMGL::DragAcceptFiles(bool accept)
466 {
467 #if 0 // FIXME_MGL
468 HWND hWnd = GetHwnd();
469 if ( hWnd )
470 ::DragAcceptFiles(hWnd, (BOOL)accept);
471 #endif
472 }
473
474 // ---------------------------------------------------------------------------
475 // moving and resizing
476 // ---------------------------------------------------------------------------
477
478 // Get total size
479 void wxWindowMGL::DoGetSize(int *x, int *y) const
480 {
481 if (x) *x = m_wnd->width;
482 if (y) *y = m_wnd->height;
483 }
484
485 void wxWindowMGL::DoGetPosition(int *x, int *y) const
486 {
487 if (x) *x = m_wnd->x;
488 if (y) *y = m_wnd->y;
489 }
490
491 void wxWindowMGL::DoScreenToClient(int *x, int *y) const
492 {
493 int ax, ay;
494 wxPoint co = GetClientAreaOrigin();
495
496 MGL_wmCoordGlobalToLocal(m_wnd, m_wnd->x, m_wnd->y, &ax, &ay);
497 ax -= co.x;
498 ay -= co.y;
499 if (x)
500 *x = ax;
501 if (y)
502 *y = ay;
503 }
504
505 void wxWindowMGL::DoClientToScreen(int *x, int *y) const
506 {
507 int ax, ay;
508 wxPoint co = GetClientAreaOrigin();
509
510 MGL_wmCoordGlobalToLocal(m_wnd, m_wnd->x+co.x, m_wnd->y+co.y, &ax, &ay);
511 if (x)
512 *x = ax;
513 if (y)
514 *y = ay;
515 }
516
517 // Get size *available for subwindows* i.e. excluding menu bar etc.
518 void wxWindowMGL::DoGetClientSize(int *x, int *y) const
519 {
520 DoGetSize(x, y);
521 }
522
523 void wxWindowMGL::DoMoveWindow(int x, int y, int width, int height)
524 {
525 MGL_wmSetWindowPosition(GetHandle(), x, y, width, height);
526 }
527
528 // set the size of the window: if the dimensions are positive, just use them,
529 // but if any of them is equal to -1, it means that we must find the value for
530 // it ourselves (unless sizeFlags contains wxSIZE_ALLOW_MINUS_ONE flag, in
531 // which case -1 is a valid value for x and y)
532 //
533 // If sizeFlags contains wxSIZE_AUTO_WIDTH/HEIGHT flags (default), we calculate
534 // the width/height to best suit our contents, otherwise we reuse the current
535 // width/height
536 void wxWindowMGL::DoSetSize(int x, int y, int width, int height, int sizeFlags)
537 {
538 // get the current size and position...
539 int currentX, currentY;
540 GetPosition(&currentX, &currentY);
541 int currentW,currentH;
542 GetSize(&currentW, &currentH);
543
544 // ... and don't do anything (avoiding flicker) if it's already ok
545 if ( x == currentX && y == currentY &&
546 width == currentW && height == currentH )
547 {
548 return;
549 }
550
551 if ( x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
552 x = currentX;
553 if ( y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE) )
554 y = currentY;
555
556 #if 0 // FIXME_MGL -- what's this good for?
557 AdjustForParentClientOrigin(x, y, sizeFlags);
558 #endif
559
560 wxSize size(-1, -1);
561 if ( width == -1 )
562 {
563 if ( sizeFlags & wxSIZE_AUTO_WIDTH )
564 {
565 size = DoGetBestSize();
566 width = size.x;
567 }
568 else
569 {
570 // just take the current one
571 width = currentW;
572 }
573 }
574
575 if ( height == -1 )
576 {
577 if ( sizeFlags & wxSIZE_AUTO_HEIGHT )
578 {
579 if ( size.x == -1 )
580 {
581 size = DoGetBestSize();
582 }
583 //else: already called DoGetBestSize() above
584
585 height = size.y;
586 }
587 else
588 {
589 // just take the current one
590 height = currentH;
591 }
592 }
593
594 DoMoveWindow(x, y, width, height);
595
596 wxSizeEvent event(wxSize(width, height), GetId());
597 event.SetEventObject(this);
598 GetEventHandler()->ProcessEvent(event);
599 }
600
601 void wxWindowMGL::DoSetClientSize(int width, int height)
602 {
603 SetSize(width, height);
604 }
605
606 // ---------------------------------------------------------------------------
607 // text metrics
608 // ---------------------------------------------------------------------------
609
610 int wxWindowMGL::GetCharHeight() const
611 {
612 wxScreenDC dc;
613 dc.SetFont(m_font);
614 return dc.GetCharHeight();
615 }
616
617 int wxWindowMGL::GetCharWidth() const
618 {
619 wxScreenDC dc;
620 dc.SetFont(m_font);
621 return dc.GetCharWidth();
622 }
623
624 void wxWindowMGL::GetTextExtent(const wxString& string,
625 int *x, int *y,
626 int *descent, int *externalLeading,
627 const wxFont *theFont) const
628 {
629 wxScreenDC dc;
630 if (!theFont)
631 theFont = &m_font;
632 dc.GetTextExtent(string, x, y, descent, externalLeading, (wxFont*)theFont);
633 }
634
635 #if wxUSE_CARET && WXWIN_COMPATIBILITY
636 // ---------------------------------------------------------------------------
637 // Caret manipulation
638 // ---------------------------------------------------------------------------
639
640 void wxWindowMGL::CreateCaret(int w, int h)
641 {
642 SetCaret(new wxCaret(this, w, h));
643 }
644
645 void wxWindowMGL::CreateCaret(const wxBitmap *WXUNUSED(bitmap))
646 {
647 wxFAIL_MSG("not implemented");
648 }
649
650 void wxWindowMGL::ShowCaret(bool show)
651 {
652 wxCHECK_RET( m_caret, "no caret to show" );
653
654 m_caret->Show(show);
655 }
656
657 void wxWindowMGL::DestroyCaret()
658 {
659 SetCaret(NULL);
660 }
661
662 void wxWindowMGL::SetCaretPos(int x, int y)
663 {
664 wxCHECK_RET( m_caret, "no caret to move" );
665
666 m_caret->Move(x, y);
667 }
668
669 void wxWindowMGL::GetCaretPos(int *x, int *y) const
670 {
671 wxCHECK_RET( m_caret, "no caret to get position of" );
672
673 m_caret->GetPosition(x, y);
674 }
675 #endif // wxUSE_CARET
676
677
678 // ---------------------------------------------------------------------------
679 // painting
680 // ---------------------------------------------------------------------------
681
682 void wxWindowMGL::Clear()
683 {
684 wxClientDC dc((wxWindow *)this);
685 wxBrush brush(GetBackgroundColour(), wxSOLID);
686 dc.SetBackground(brush);
687 dc.Clear();
688 }
689
690 void wxWindowMGL::Refresh(bool WXUNUSED(eraseBack), const wxRect *rect)
691 {
692 if ( rect )
693 {
694 rect_t r;
695 r.left = rect->GetLeft(), r.right = rect->GetRight();
696 r.top = rect->GetTop(), r.bottom = rect->GetBottom();
697 MGL_wmInvalidateWindowRect(GetHandle(), &r);
698 }
699 else
700 MGL_wmInvalidateWindow(GetHandle());
701 }
702
703 void wxWindowMGL::Update()
704 {
705 Refresh();
706 if ( !m_frozen )
707 MGL_wmUpdateDC(g_winMng);
708 }
709
710 void wxWindowMGL::Freeze()
711 {
712 m_frozen = TRUE;
713 m_refreshAfterThaw = FALSE;
714 }
715
716 void wxWindowMGL::Thaw()
717 {
718 m_frozen = FALSE;
719 if ( m_refreshAfterThaw )
720 Refresh();
721 }
722
723 void wxWindowMGL::HandlePaint(MGLDevCtx *dc)
724 {
725 if ( m_frozen )
726 {
727 // Don't paint anything if the window is frozen.
728 return;
729 }
730
731 region_t clip;
732 MGL_getClipRegionDC(*dc, &clip);
733 m_updateRegion = wxRegion(MGLRegion(&clip));
734 m_paintMGLDC = dc;
735
736 {
737 wxWindowDC dc((wxWindow*)this);
738 wxEraseEvent eventEr(m_windowId, &dc);
739 eventEr.SetEventObject(this);
740 GetEventHandler()->ProcessEvent(eventEr);
741 }
742
743 wxNcPaintEvent eventNc(GetId());
744 eventNc.SetEventObject(this);
745 GetEventHandler()->ProcessEvent(eventNc);
746
747 wxPaintEvent eventPt(GetId());
748 eventPt.SetEventObject(this);
749 GetEventHandler()->ProcessEvent(eventPt);
750
751 m_paintMGLDC = NULL;
752 }
753
754
755 // Find the wxWindow at the current mouse position, returning the mouse
756 // position.
757 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
758 {
759 return wxFindWindowAtPoint(pt = wxGetMousePosition());
760 }
761
762 wxWindow* wxFindWindowAtPoint(const wxPoint& pt)
763 {
764 window_t *wnd = MGL_wmGetWindowAtPosition(g_winMng, pt.x, pt.y);
765 return (wxWindow*)wnd->userData;
766 }