]> git.saurik.com Git - wxWidgets.git/blob - src/univ/topluniv.cpp
avoiding nesting dcs on the same window concurrently
[wxWidgets.git] / src / univ / topluniv.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/topluniv.cpp
3 // Author: Vaclav Slavik
4 // Id: $Id$
5 // Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8
9 // ============================================================================
10 // declarations
11 // ============================================================================
12
13 // ----------------------------------------------------------------------------
14 // headers
15 // ----------------------------------------------------------------------------
16
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #include "wx/toplevel.h"
25
26 #ifndef WX_PRECOMP
27 #include "wx/dcclient.h"
28 #include "wx/settings.h"
29 #include "wx/bitmap.h"
30 #include "wx/image.h"
31 #include "wx/frame.h"
32 #endif
33
34 #include "wx/univ/renderer.h"
35 #include "wx/cshelp.h"
36 #include "wx/evtloop.h"
37
38 // ----------------------------------------------------------------------------
39 // wxStdTLWInputHandler: handles focus, resizing and titlebar buttons clicks
40 // ----------------------------------------------------------------------------
41
42 class WXDLLEXPORT wxStdTLWInputHandler : public wxStdInputHandler
43 {
44 public:
45 wxStdTLWInputHandler(wxInputHandler *inphand);
46
47 virtual bool HandleMouse(wxInputConsumer *consumer,
48 const wxMouseEvent& event);
49 virtual bool HandleMouseMove(wxInputConsumer *consumer, const wxMouseEvent& event);
50 virtual bool HandleActivation(wxInputConsumer *consumer, bool activated);
51
52 private:
53 // the window (button) which has capture or NULL and the last hittest result
54 wxTopLevelWindow *m_winCapture;
55 long m_winHitTest;
56 long m_winPressed;
57 bool m_borderCursorOn;
58 wxCursor m_origCursor;
59 };
60
61
62 // ----------------------------------------------------------------------------
63 // event tables
64 // ----------------------------------------------------------------------------
65
66 BEGIN_EVENT_TABLE(wxTopLevelWindow, wxTopLevelWindowNative)
67 WX_EVENT_TABLE_INPUT_CONSUMER(wxTopLevelWindow)
68 EVT_NC_PAINT(wxTopLevelWindow::OnNcPaint)
69 EVT_MENU_RANGE(wxID_CLOSE_FRAME, wxID_RESTORE_FRAME, wxTopLevelWindow::OnSystemMenu)
70 END_EVENT_TABLE()
71
72 WX_FORWARD_TO_INPUT_CONSUMER(wxTopLevelWindow)
73
74 // ============================================================================
75 // implementation
76 // ============================================================================
77
78 int wxTopLevelWindow::ms_drawDecorations = -1;
79 int wxTopLevelWindow::ms_canIconize = -1;
80
81 void wxTopLevelWindow::Init()
82 {
83 // once-only ms_drawDecorations initialization
84 if ( ms_drawDecorations == -1 )
85 {
86 ms_drawDecorations =
87 !wxSystemSettings::HasFeature(wxSYS_CAN_DRAW_FRAME_DECORATIONS) ||
88 wxGetEnv(wxT("WXDECOR"), NULL);
89 }
90
91 m_usingNativeDecorations = ms_drawDecorations == 0;
92 m_isActive = false;
93 m_windowStyle = 0;
94 m_pressedButton = 0;
95 }
96
97 bool wxTopLevelWindow::Create(wxWindow *parent,
98 wxWindowID id,
99 const wxString& title,
100 const wxPoint& pos,
101 const wxSize& size,
102 long style,
103 const wxString &name)
104 {
105 // init them to avoid compiler warnings
106 long styleOrig = 0,
107 exstyleOrig = 0;
108
109 if ( !m_usingNativeDecorations )
110 {
111 CreateInputHandler(wxINP_HANDLER_TOPLEVEL);
112
113 styleOrig = style;
114 exstyleOrig = GetExtraStyle();
115 style &= ~(wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX |
116 wxSYSTEM_MENU | wxRESIZE_BORDER | wxFRAME_TOOL_WINDOW |
117 wxRESIZE_BORDER);
118 style |= wxBORDER_NONE;
119 SetExtraStyle(exstyleOrig & ~wxWS_EX_CONTEXTHELP);
120 }
121
122 if ( !wxTopLevelWindowNative::Create(parent, id, title, pos,
123 size, style, name) )
124 return false;
125
126 if ( !m_usingNativeDecorations )
127 {
128 m_windowStyle = styleOrig;
129 m_exStyle = exstyleOrig;
130 }
131
132 return true;
133 }
134
135 bool wxTopLevelWindow::ShowFullScreen(bool show, long style)
136 {
137 if ( show == IsFullScreen() ) return false;
138
139 if ( !m_usingNativeDecorations )
140 {
141 if ( show )
142 {
143 m_fsSavedStyle = m_windowStyle;
144 if ( style & wxFULLSCREEN_NOBORDER )
145 m_windowStyle |= wxSIMPLE_BORDER;
146 if ( style & wxFULLSCREEN_NOCAPTION )
147 m_windowStyle &= ~wxCAPTION;
148 }
149 else
150 {
151 m_windowStyle = m_fsSavedStyle;
152 }
153 }
154
155 return wxTopLevelWindowNative::ShowFullScreen(show, style);
156 }
157
158 /* static */
159 void wxTopLevelWindow::UseNativeDecorationsByDefault(bool native)
160 {
161 ms_drawDecorations = !native;
162 }
163
164 void wxTopLevelWindow::UseNativeDecorations(bool native)
165 {
166 wxASSERT_MSG( !m_windowStyle, _T("must be called before Create()") );
167
168 m_usingNativeDecorations = native;
169 }
170
171 bool wxTopLevelWindow::IsUsingNativeDecorations() const
172 {
173 return m_usingNativeDecorations;
174 }
175
176 long wxTopLevelWindow::GetDecorationsStyle() const
177 {
178 long style = 0;
179
180 if ( m_windowStyle & wxCAPTION )
181 {
182 if ( ms_canIconize == -1 )
183 {
184 ms_canIconize = wxSystemSettings::HasFeature(wxSYS_CAN_ICONIZE_FRAME);
185 }
186
187 style |= wxTOPLEVEL_TITLEBAR | wxTOPLEVEL_BUTTON_CLOSE;
188 if ( (m_windowStyle & wxMINIMIZE_BOX) && ms_canIconize )
189 style |= wxTOPLEVEL_BUTTON_ICONIZE;
190 if ( m_windowStyle & wxMAXIMIZE_BOX )
191 {
192 if ( IsMaximized() )
193 style |= wxTOPLEVEL_BUTTON_RESTORE;
194 else
195 style |= wxTOPLEVEL_BUTTON_MAXIMIZE;
196 }
197 #if wxUSE_HELP
198 if ( m_exStyle & wxWS_EX_CONTEXTHELP)
199 style |= wxTOPLEVEL_BUTTON_HELP;
200 #endif
201 }
202 if ( (m_windowStyle & (wxSIMPLE_BORDER | wxNO_BORDER)) == 0 )
203 style |= wxTOPLEVEL_BORDER;
204 if ( m_windowStyle & (wxRESIZE_BORDER | wxRESIZE_BORDER) )
205 style |= wxTOPLEVEL_RESIZEABLE;
206
207 if ( IsMaximized() )
208 style |= wxTOPLEVEL_MAXIMIZED;
209 if ( GetIcon().Ok() )
210 style |= wxTOPLEVEL_ICON;
211 if ( m_isActive )
212 style |= wxTOPLEVEL_ACTIVE;
213
214 return style;
215 }
216
217 void wxTopLevelWindow::RefreshTitleBar()
218 {
219 wxNcPaintEvent event(GetId());
220 event.SetEventObject(this);
221 GetEventHandler()->ProcessEvent(event);
222 }
223
224 // ----------------------------------------------------------------------------
225 // client area handling
226 // ----------------------------------------------------------------------------
227
228 wxPoint wxTopLevelWindow::GetClientAreaOrigin() const
229 {
230 if ( !m_usingNativeDecorations )
231 {
232 int w, h;
233 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
234 wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
235 wxSize(w, h));
236 rect = m_renderer->GetFrameClientArea(rect,
237 GetDecorationsStyle());
238 return rect.GetPosition();
239 }
240 else
241 {
242 return wxTopLevelWindowNative::GetClientAreaOrigin();
243 }
244 }
245
246 void wxTopLevelWindow::DoGetClientSize(int *width, int *height) const
247 {
248 if ( !m_usingNativeDecorations )
249 {
250 int w, h;
251 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
252 wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
253 wxSize(w, h));
254 rect = m_renderer->GetFrameClientArea(rect,
255 GetDecorationsStyle());
256 if ( width )
257 *width = rect.width;
258 if ( height )
259 *height = rect.height;
260 }
261 else
262 wxTopLevelWindowNative::DoGetClientSize(width, height);
263 }
264
265 void wxTopLevelWindow::DoSetClientSize(int width, int height)
266 {
267 if ( !m_usingNativeDecorations )
268 {
269 wxSize size = m_renderer->GetFrameTotalSize(wxSize(width, height),
270 GetDecorationsStyle());
271 wxTopLevelWindowNative::DoSetClientSize(size.x, size.y);
272 }
273 else
274 wxTopLevelWindowNative::DoSetClientSize(width, height);
275 }
276
277 void wxTopLevelWindow::OnNcPaint(wxNcPaintEvent& event)
278 {
279 if ( m_usingNativeDecorations || !m_renderer )
280 {
281 event.Skip();
282 }
283 else // we're drawing the decorations ourselves
284 {
285 // get the window rect
286 wxRect rect(GetSize());
287
288 wxWindowDC dc(this);
289 m_renderer->DrawFrameTitleBar(dc, rect,
290 GetTitle(), m_titlebarIcon,
291 GetDecorationsStyle(),
292 m_pressedButton,
293 wxCONTROL_PRESSED);
294 }
295 }
296
297 long wxTopLevelWindow::HitTest(const wxPoint& pt) const
298 {
299 int w, h;
300 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
301 wxRect rect(wxTopLevelWindowNative::GetClientAreaOrigin(), wxSize(w, h));
302
303 return m_renderer->HitTestFrame(rect, pt+GetClientAreaOrigin(), GetDecorationsStyle());
304 }
305
306 int wxTopLevelWindow::GetMinWidth() const
307 {
308 if ( !m_usingNativeDecorations )
309 {
310 return wxMax(wxTopLevelWindowNative::GetMinWidth(),
311 m_renderer->GetFrameMinSize(GetDecorationsStyle()).x);
312 }
313 else
314 return wxTopLevelWindowNative::GetMinWidth();
315 }
316
317 int wxTopLevelWindow::GetMinHeight() const
318 {
319 if ( !m_usingNativeDecorations )
320 {
321 return wxMax(wxTopLevelWindowNative::GetMinHeight(),
322 m_renderer->GetFrameMinSize(GetDecorationsStyle()).y);
323 }
324 else
325 return wxTopLevelWindowNative::GetMinHeight();
326 }
327
328 // ----------------------------------------------------------------------------
329 // icons
330 // ----------------------------------------------------------------------------
331
332 void wxTopLevelWindow::SetIcons(const wxIconBundle& icons)
333 {
334 wxTopLevelWindowNative::SetIcons(icons);
335
336 if ( !m_usingNativeDecorations && m_renderer )
337 {
338 wxSize size = m_renderer->GetFrameIconSize();
339 const wxIcon& icon = icons.GetIcon( size );
340
341 if ( !icon.Ok() || size.x == wxDefaultCoord )
342 m_titlebarIcon = icon;
343 else
344 {
345 wxBitmap bmp1;
346 bmp1.CopyFromIcon(icon);
347 if ( !bmp1.Ok() )
348 m_titlebarIcon = wxNullIcon;
349 else if ( bmp1.GetWidth() == size.x && bmp1.GetHeight() == size.y )
350 m_titlebarIcon = icon;
351 #if wxUSE_IMAGE
352 else
353 {
354 wxImage img = bmp1.ConvertToImage();
355 img.Rescale(size.x, size.y);
356 m_titlebarIcon.CopyFromBitmap(wxBitmap(img));
357 }
358 #endif // wxUSE_IMAGE
359 }
360 }
361 }
362
363 // ----------------------------------------------------------------------------
364 // interactive manipulation
365 // ----------------------------------------------------------------------------
366
367
368 static bool wxGetResizingCursor(long hitTestResult, wxCursor& cursor)
369 {
370 if ( hitTestResult & wxHT_TOPLEVEL_ANY_BORDER )
371 {
372 switch (hitTestResult)
373 {
374 case wxHT_TOPLEVEL_BORDER_N:
375 case wxHT_TOPLEVEL_BORDER_S:
376 cursor = wxCursor(wxCURSOR_SIZENS);
377 break;
378 case wxHT_TOPLEVEL_BORDER_W:
379 case wxHT_TOPLEVEL_BORDER_E:
380 cursor = wxCursor(wxCURSOR_SIZEWE);
381 break;
382 case wxHT_TOPLEVEL_BORDER_NE:
383 case wxHT_TOPLEVEL_BORDER_SW:
384 cursor = wxCursor(wxCURSOR_SIZENESW);
385 break;
386 case wxHT_TOPLEVEL_BORDER_NW:
387 case wxHT_TOPLEVEL_BORDER_SE:
388 cursor = wxCursor(wxCURSOR_SIZENWSE);
389 break;
390 default:
391 return false;
392 }
393 return true;
394 }
395
396 return false;
397 }
398
399 #define wxINTERACTIVE_RESIZE_DIR \
400 (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E | \
401 wxINTERACTIVE_RESIZE_S | wxINTERACTIVE_RESIZE_N)
402
403 struct wxInteractiveMoveData
404 {
405 wxTopLevelWindow *m_window;
406 wxEventLoop *m_evtLoop;
407 int m_flags;
408 wxRect m_rect;
409 wxRect m_rectOrig;
410 wxPoint m_pos;
411 wxSize m_minSize, m_maxSize;
412 bool m_sizingCursor;
413 };
414
415 class wxInteractiveMoveHandler : public wxEvtHandler
416 {
417 public:
418 wxInteractiveMoveHandler(wxInteractiveMoveData& data) : m_data(data) {}
419
420 private:
421 DECLARE_EVENT_TABLE()
422 void OnMouseMove(wxMouseEvent& event);
423 void OnMouseDown(wxMouseEvent& event);
424 void OnMouseUp(wxMouseEvent& event);
425 void OnKeyDown(wxKeyEvent& event);
426
427 wxInteractiveMoveData& m_data;
428 };
429
430 BEGIN_EVENT_TABLE(wxInteractiveMoveHandler, wxEvtHandler)
431 EVT_MOTION(wxInteractiveMoveHandler::OnMouseMove)
432 EVT_LEFT_DOWN(wxInteractiveMoveHandler::OnMouseDown)
433 EVT_LEFT_UP(wxInteractiveMoveHandler::OnMouseUp)
434 EVT_KEY_DOWN(wxInteractiveMoveHandler::OnKeyDown)
435 END_EVENT_TABLE()
436
437
438 static inline LINKAGEMODE
439 void wxApplyResize(wxInteractiveMoveData& data, const wxPoint& diff)
440 {
441 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
442 {
443 data.m_rect.x += diff.x;
444 data.m_rect.width -= diff.x;
445 }
446 else if ( data.m_flags & wxINTERACTIVE_RESIZE_E )
447 {
448 data.m_rect.width += diff.x;
449 }
450 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
451 {
452 data.m_rect.y += diff.y;
453 data.m_rect.height -= diff.y;
454 }
455 else if ( data.m_flags & wxINTERACTIVE_RESIZE_S )
456 {
457 data.m_rect.height += diff.y;
458 }
459
460 if ( data.m_minSize.x != wxDefaultCoord && data.m_rect.width < data.m_minSize.x )
461 {
462 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
463 data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
464 data.m_rect.width = data.m_minSize.x;
465 }
466 if ( data.m_maxSize.x != wxDefaultCoord && data.m_rect.width > data.m_maxSize.x )
467 {
468 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
469 data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
470 data.m_rect.width = data.m_maxSize.x;
471 }
472 if ( data.m_minSize.y != wxDefaultCoord && data.m_rect.height < data.m_minSize.y )
473 {
474 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
475 data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
476 data.m_rect.height = data.m_minSize.y;
477 }
478 if ( data.m_maxSize.y != wxDefaultCoord && data.m_rect.height > data.m_maxSize.y )
479 {
480 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
481 data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
482 data.m_rect.height = data.m_maxSize.y;
483 }
484 }
485
486 void wxInteractiveMoveHandler::OnMouseMove(wxMouseEvent& event)
487 {
488 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
489 event.Skip();
490
491 else if ( m_data.m_flags & wxINTERACTIVE_MOVE )
492 {
493 wxPoint diff = wxGetMousePosition() - m_data.m_pos;
494 m_data.m_rect = m_data.m_rectOrig;
495 m_data.m_rect.Offset(diff);
496 m_data.m_window->Move(m_data.m_rect.GetPosition());
497 }
498
499 else if ( m_data.m_flags & wxINTERACTIVE_RESIZE )
500 {
501 wxPoint diff = wxGetMousePosition() - m_data.m_pos;
502 m_data.m_rect = m_data.m_rectOrig;
503 wxApplyResize(m_data, diff);
504 m_data.m_window->SetSize(m_data.m_rect);
505 }
506 }
507
508 void wxInteractiveMoveHandler::OnMouseDown(wxMouseEvent& WXUNUSED(event))
509 {
510 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
511 {
512 m_data.m_evtLoop->Exit();
513 }
514 }
515
516 void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent& event)
517 {
518 wxPoint diff(wxDefaultCoord,wxDefaultCoord);
519
520 switch ( event.GetKeyCode() )
521 {
522 case WXK_UP: diff = wxPoint(0, -16); break;
523 case WXK_DOWN: diff = wxPoint(0, 16); break;
524 case WXK_LEFT: diff = wxPoint(-16, 0); break;
525 case WXK_RIGHT: diff = wxPoint(16, 0); break;
526 case WXK_ESCAPE:
527 m_data.m_window->SetSize(m_data.m_rectOrig);
528 m_data.m_evtLoop->Exit();
529 return;
530 case WXK_RETURN:
531 m_data.m_evtLoop->Exit();
532 return;
533 }
534
535 if ( diff.x != wxDefaultCoord )
536 {
537 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
538 {
539 m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
540 if ( m_data.m_sizingCursor )
541 {
542 wxEndBusyCursor();
543 m_data.m_sizingCursor = false;
544 }
545
546 if ( m_data.m_flags & wxINTERACTIVE_MOVE )
547 {
548 m_data.m_pos = m_data.m_window->GetPosition() +
549 wxPoint(m_data.m_window->GetSize().x/2, 8);
550 }
551 }
552
553 wxPoint warp;
554 bool changeCur = false;
555
556 if ( m_data.m_flags & wxINTERACTIVE_MOVE )
557 {
558 m_data.m_rect.Offset(diff);
559 m_data.m_window->Move(m_data.m_rect.GetPosition());
560 warp = wxPoint(m_data.m_window->GetSize().x/2, 8);
561 }
562 else /* wxINTERACTIVE_RESIZE */
563 {
564 if ( !(m_data.m_flags &
565 (wxINTERACTIVE_RESIZE_N | wxINTERACTIVE_RESIZE_S)) )
566 {
567 if ( diff.y < 0 )
568 {
569 m_data.m_flags |= wxINTERACTIVE_RESIZE_N;
570 m_data.m_pos.y = m_data.m_window->GetPosition().y;
571 changeCur = true;
572 }
573 else if ( diff.y > 0 )
574 {
575 m_data.m_flags |= wxINTERACTIVE_RESIZE_S;
576 m_data.m_pos.y = m_data.m_window->GetPosition().y +
577 m_data.m_window->GetSize().y;
578 changeCur = true;
579 }
580 }
581 if ( !(m_data.m_flags &
582 (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E)) )
583 {
584 if ( diff.x < 0 )
585 {
586 m_data.m_flags |= wxINTERACTIVE_RESIZE_W;
587 m_data.m_pos.x = m_data.m_window->GetPosition().x;
588 changeCur = true;
589 }
590 else if ( diff.x > 0 )
591 {
592 m_data.m_flags |= wxINTERACTIVE_RESIZE_E;
593 m_data.m_pos.x = m_data.m_window->GetPosition().x +
594 m_data.m_window->GetSize().x;
595 changeCur = true;
596 }
597 }
598
599 wxApplyResize(m_data, diff);
600 m_data.m_window->SetSize(m_data.m_rect);
601
602 if ( m_data.m_flags & wxINTERACTIVE_RESIZE_W )
603 warp.x = 0;
604 else if ( m_data.m_flags & wxINTERACTIVE_RESIZE_E )
605 warp.x = m_data.m_window->GetSize().x-1;
606 else
607 warp.x = wxGetMousePosition().x - m_data.m_window->GetPosition().x;
608
609 if ( m_data.m_flags & wxINTERACTIVE_RESIZE_N )
610 warp.y = 0;
611 else if ( m_data.m_flags & wxINTERACTIVE_RESIZE_S )
612 warp.y = m_data.m_window->GetSize().y-1;
613 else
614 warp.y = wxGetMousePosition().y - m_data.m_window->GetPosition().y;
615 }
616
617 warp -= m_data.m_window->GetClientAreaOrigin();
618 m_data.m_window->WarpPointer(warp.x, warp.y);
619
620 if ( changeCur )
621 {
622 long hit = m_data.m_window->HitTest(warp);
623 wxCursor cur;
624 if ( wxGetResizingCursor(hit, cur) )
625 {
626 if ( m_data.m_sizingCursor )
627 wxEndBusyCursor();
628 wxBeginBusyCursor(&cur);
629 m_data.m_sizingCursor = true;
630 }
631 }
632 }
633 }
634
635 void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent& WXUNUSED(event))
636 {
637 m_data.m_evtLoop->Exit();
638 }
639
640
641 void wxTopLevelWindow::InteractiveMove(int flags)
642 {
643 wxASSERT_MSG( !((flags & wxINTERACTIVE_MOVE) && (flags & wxINTERACTIVE_RESIZE)),
644 wxT("can't move and resize window at the same time") );
645
646 wxASSERT_MSG( !(flags & wxINTERACTIVE_RESIZE) ||
647 (flags & wxINTERACTIVE_WAIT_FOR_INPUT) ||
648 (flags & wxINTERACTIVE_RESIZE_DIR),
649 wxT("direction of resizing not specified") );
650
651 wxInteractiveMoveData data;
652 wxEventLoop loop;
653
654 SetFocus();
655
656 #ifndef __WXGTK__
657 if ( flags & wxINTERACTIVE_WAIT_FOR_INPUT )
658 {
659 wxCursor sizingCursor(wxCURSOR_SIZING);
660 wxBeginBusyCursor(&sizingCursor);
661 data.m_sizingCursor = true;
662 }
663 else
664 #endif
665 data.m_sizingCursor = false;
666
667 data.m_window = this;
668 data.m_evtLoop = &loop;
669 data.m_flags = flags;
670 data.m_rect = data.m_rectOrig = GetRect();
671 data.m_pos = wxGetMousePosition();
672 data.m_minSize = wxSize(GetMinWidth(), GetMinHeight());
673 data.m_maxSize = wxSize(GetMaxWidth(), GetMaxHeight());
674
675 wxEvtHandler *handler = new wxInteractiveMoveHandler(data);
676 this->PushEventHandler(handler);
677
678 CaptureMouse();
679 loop.Run();
680 ReleaseMouse();
681
682 this->RemoveEventHandler(handler);
683 delete handler;
684
685 if ( data.m_sizingCursor )
686 wxEndBusyCursor();
687 }
688
689 // ----------------------------------------------------------------------------
690 // actions
691 // ----------------------------------------------------------------------------
692
693 void wxTopLevelWindow::ClickTitleBarButton(long button)
694 {
695 switch ( button )
696 {
697 case wxTOPLEVEL_BUTTON_CLOSE:
698 Close();
699 break;
700
701 case wxTOPLEVEL_BUTTON_ICONIZE:
702 Iconize();
703 break;
704
705 case wxTOPLEVEL_BUTTON_MAXIMIZE:
706 Maximize();
707 break;
708
709 case wxTOPLEVEL_BUTTON_RESTORE:
710 Restore();
711 break;
712
713 case wxTOPLEVEL_BUTTON_HELP:
714 #if wxUSE_HELP
715 {
716 wxContextHelp contextHelp(this);
717 }
718 #endif
719 break;
720
721 default:
722 wxFAIL_MSG(wxT("incorrect button specification"));
723 }
724 }
725
726 bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
727 long numArg,
728 const wxString& WXUNUSED(strArg))
729 {
730 bool isActive = numArg != 0;
731
732 if ( action == wxACTION_TOPLEVEL_ACTIVATE )
733 {
734 if ( m_isActive != isActive )
735 {
736 m_isActive = isActive;
737 RefreshTitleBar();
738 }
739 return true;
740 }
741
742 else if ( action == wxACTION_TOPLEVEL_BUTTON_PRESS )
743 {
744 m_pressedButton = numArg;
745 RefreshTitleBar();
746 return true;
747 }
748
749 else if ( action == wxACTION_TOPLEVEL_BUTTON_RELEASE )
750 {
751 m_pressedButton = 0;
752 RefreshTitleBar();
753 return true;
754 }
755
756 else if ( action == wxACTION_TOPLEVEL_BUTTON_CLICK )
757 {
758 m_pressedButton = 0;
759 RefreshTitleBar();
760 ClickTitleBarButton(numArg);
761 return true;
762 }
763
764 else if ( action == wxACTION_TOPLEVEL_MOVE )
765 {
766 InteractiveMove(wxINTERACTIVE_MOVE);
767 return true;
768 }
769
770 else if ( action == wxACTION_TOPLEVEL_RESIZE )
771 {
772 int flags = wxINTERACTIVE_RESIZE;
773 if ( numArg & wxHT_TOPLEVEL_BORDER_N )
774 flags |= wxINTERACTIVE_RESIZE_N;
775 if ( numArg & wxHT_TOPLEVEL_BORDER_S )
776 flags |= wxINTERACTIVE_RESIZE_S;
777 if ( numArg & wxHT_TOPLEVEL_BORDER_W )
778 flags |= wxINTERACTIVE_RESIZE_W;
779 if ( numArg & wxHT_TOPLEVEL_BORDER_E )
780 flags |= wxINTERACTIVE_RESIZE_E;
781 InteractiveMove(flags);
782 return true;
783 }
784
785 else
786 return false;
787 }
788
789 void wxTopLevelWindow::OnSystemMenu(wxCommandEvent& event)
790 {
791 bool ret = true;
792
793 switch (event.GetId())
794 {
795 case wxID_CLOSE_FRAME:
796 ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
797 wxTOPLEVEL_BUTTON_CLOSE);
798 break;
799 case wxID_MOVE_FRAME:
800 InteractiveMove(wxINTERACTIVE_MOVE | wxINTERACTIVE_WAIT_FOR_INPUT);
801 break;
802 case wxID_RESIZE_FRAME:
803 InteractiveMove(wxINTERACTIVE_RESIZE | wxINTERACTIVE_WAIT_FOR_INPUT);
804 break;
805 case wxID_MAXIMIZE_FRAME:
806 ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
807 wxTOPLEVEL_BUTTON_MAXIMIZE);
808 break;
809 case wxID_ICONIZE_FRAME:
810 ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
811 wxTOPLEVEL_BUTTON_ICONIZE);
812 break;
813 case wxID_RESTORE_FRAME:
814 ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
815 wxTOPLEVEL_BUTTON_RESTORE);
816 break;
817
818 default:
819 ret = false;
820 }
821
822 if ( !ret )
823 event.Skip();
824 }
825
826 /* static */
827 wxInputHandler *
828 wxTopLevelWindow::GetStdInputHandler(wxInputHandler *handlerDef)
829 {
830 static wxStdTLWInputHandler s_handler(handlerDef);
831
832 return &s_handler;
833 }
834
835 // ============================================================================
836 // wxStdTLWInputHandler: handles focus, resizing and titlebar buttons clicks
837 // ============================================================================
838
839 wxStdTLWInputHandler::wxStdTLWInputHandler(wxInputHandler *inphand)
840 : wxStdInputHandler(inphand)
841 {
842 m_winCapture = NULL;
843 m_winHitTest = 0;
844 m_winPressed = 0;
845 m_borderCursorOn = false;
846 }
847
848 bool wxStdTLWInputHandler::HandleMouse(wxInputConsumer *consumer,
849 const wxMouseEvent& event)
850 {
851 // the button has 2 states: pressed and normal with the following
852 // transitions between them:
853 //
854 // normal -> left down -> capture mouse and go to pressed state
855 // pressed -> left up inside -> generate click -> go to normal
856 // outside ------------------>
857 //
858 // the other mouse buttons are ignored
859 if ( event.Button(1) )
860 {
861 if ( event.ButtonDown(1) )
862 {
863 wxTopLevelWindow *w = wxStaticCast(consumer->GetInputWindow(), wxTopLevelWindow);
864 long hit = w->HitTest(event.GetPosition());
865
866 if ( hit & wxHT_TOPLEVEL_ANY_BUTTON )
867 {
868 m_winCapture = w;
869 m_winCapture->CaptureMouse();
870 m_winHitTest = hit;
871 m_winPressed = hit;
872 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
873 return true;
874 }
875 else if ( (hit & wxHT_TOPLEVEL_TITLEBAR) && !w->IsMaximized() )
876 {
877 consumer->PerformAction(wxACTION_TOPLEVEL_MOVE);
878 return true;
879 }
880 else if ( (consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER)
881 && (hit & wxHT_TOPLEVEL_ANY_BORDER) )
882 {
883 consumer->PerformAction(wxACTION_TOPLEVEL_RESIZE, hit);
884 return true;
885 }
886 }
887
888 else // up
889 {
890 if ( m_winCapture )
891 {
892 m_winCapture->ReleaseMouse();
893 m_winCapture = NULL;
894
895 if ( m_winHitTest == m_winPressed )
896 {
897 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK, m_winPressed);
898 return true;
899 }
900 }
901 //else: the mouse was released outside the window, this doesn't
902 // count as a click
903 }
904 }
905
906 return wxStdInputHandler::HandleMouse(consumer, event);
907 }
908
909 bool wxStdTLWInputHandler::HandleMouseMove(wxInputConsumer *consumer,
910 const wxMouseEvent& event)
911 {
912 if ( event.GetEventObject() == m_winCapture )
913 {
914 long hit = m_winCapture->HitTest(event.GetPosition());
915
916 if ( hit != m_winHitTest )
917 {
918 if ( hit != m_winPressed )
919 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_RELEASE, m_winPressed);
920 else
921 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
922
923 m_winHitTest = hit;
924 return true;
925 }
926 }
927 else if ( consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER )
928 {
929 wxTopLevelWindow *win = wxStaticCast(consumer->GetInputWindow(),
930 wxTopLevelWindow);
931 long hit = win->HitTest(event.GetPosition());
932
933 if ( hit != m_winHitTest )
934 {
935 m_winHitTest = hit;
936
937 if ( m_borderCursorOn )
938 {
939 m_borderCursorOn = false;
940 win->SetCursor(m_origCursor);
941 }
942
943 if ( hit & wxHT_TOPLEVEL_ANY_BORDER )
944 {
945 wxCursor cur;
946
947 m_borderCursorOn = wxGetResizingCursor(hit, cur);
948 if ( m_borderCursorOn )
949 {
950 m_origCursor = win->GetCursor();
951 win->SetCursor(cur);
952 }
953 }
954 }
955 }
956
957 return wxStdInputHandler::HandleMouseMove(consumer, event);
958 }
959
960 bool wxStdTLWInputHandler::HandleActivation(wxInputConsumer *consumer,
961 bool activated)
962 {
963 if ( m_borderCursorOn )
964 {
965 consumer->GetInputWindow()->SetCursor(m_origCursor);
966 m_borderCursorOn = false;
967 }
968 consumer->PerformAction(wxACTION_TOPLEVEL_ACTIVATE, activated);
969 return false;
970 }