don't override GetMinWidth/Height() which are non-virtual any more, override GetMinSi...
[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 wxSize wxTopLevelWindow::GetMinSize() const
307 {
308 wxSize size = wxTopLevelWindowNative::GetMinSize();
309 if ( !m_usingNativeDecorations )
310 {
311 size.IncTo(m_renderer->GetFrameMinSize(GetDecorationsStyle()));
312 }
313
314 return size;
315 }
316
317 // ----------------------------------------------------------------------------
318 // icons
319 // ----------------------------------------------------------------------------
320
321 void wxTopLevelWindow::SetIcons(const wxIconBundle& icons)
322 {
323 wxTopLevelWindowNative::SetIcons(icons);
324
325 if ( !m_usingNativeDecorations && m_renderer )
326 {
327 wxSize size = m_renderer->GetFrameIconSize();
328 const wxIcon& icon = icons.GetIcon( size );
329
330 if ( !icon.Ok() || size.x == wxDefaultCoord )
331 m_titlebarIcon = icon;
332 else
333 {
334 wxBitmap bmp1;
335 bmp1.CopyFromIcon(icon);
336 if ( !bmp1.Ok() )
337 m_titlebarIcon = wxNullIcon;
338 else if ( bmp1.GetWidth() == size.x && bmp1.GetHeight() == size.y )
339 m_titlebarIcon = icon;
340 #if wxUSE_IMAGE
341 else
342 {
343 wxImage img = bmp1.ConvertToImage();
344 img.Rescale(size.x, size.y);
345 m_titlebarIcon.CopyFromBitmap(wxBitmap(img));
346 }
347 #endif // wxUSE_IMAGE
348 }
349 }
350 }
351
352 // ----------------------------------------------------------------------------
353 // interactive manipulation
354 // ----------------------------------------------------------------------------
355
356
357 static bool wxGetResizingCursor(long hitTestResult, wxCursor& cursor)
358 {
359 if ( hitTestResult & wxHT_TOPLEVEL_ANY_BORDER )
360 {
361 switch (hitTestResult)
362 {
363 case wxHT_TOPLEVEL_BORDER_N:
364 case wxHT_TOPLEVEL_BORDER_S:
365 cursor = wxCursor(wxCURSOR_SIZENS);
366 break;
367 case wxHT_TOPLEVEL_BORDER_W:
368 case wxHT_TOPLEVEL_BORDER_E:
369 cursor = wxCursor(wxCURSOR_SIZEWE);
370 break;
371 case wxHT_TOPLEVEL_BORDER_NE:
372 case wxHT_TOPLEVEL_BORDER_SW:
373 cursor = wxCursor(wxCURSOR_SIZENESW);
374 break;
375 case wxHT_TOPLEVEL_BORDER_NW:
376 case wxHT_TOPLEVEL_BORDER_SE:
377 cursor = wxCursor(wxCURSOR_SIZENWSE);
378 break;
379 default:
380 return false;
381 }
382 return true;
383 }
384
385 return false;
386 }
387
388 #define wxINTERACTIVE_RESIZE_DIR \
389 (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E | \
390 wxINTERACTIVE_RESIZE_S | wxINTERACTIVE_RESIZE_N)
391
392 struct wxInteractiveMoveData
393 {
394 wxTopLevelWindow *m_window;
395 wxEventLoop *m_evtLoop;
396 int m_flags;
397 wxRect m_rect;
398 wxRect m_rectOrig;
399 wxPoint m_pos;
400 wxSize m_minSize, m_maxSize;
401 bool m_sizingCursor;
402 };
403
404 class wxInteractiveMoveHandler : public wxEvtHandler
405 {
406 public:
407 wxInteractiveMoveHandler(wxInteractiveMoveData& data) : m_data(data) {}
408
409 private:
410 DECLARE_EVENT_TABLE()
411 void OnMouseMove(wxMouseEvent& event);
412 void OnMouseDown(wxMouseEvent& event);
413 void OnMouseUp(wxMouseEvent& event);
414 void OnKeyDown(wxKeyEvent& event);
415
416 wxInteractiveMoveData& m_data;
417 };
418
419 BEGIN_EVENT_TABLE(wxInteractiveMoveHandler, wxEvtHandler)
420 EVT_MOTION(wxInteractiveMoveHandler::OnMouseMove)
421 EVT_LEFT_DOWN(wxInteractiveMoveHandler::OnMouseDown)
422 EVT_LEFT_UP(wxInteractiveMoveHandler::OnMouseUp)
423 EVT_KEY_DOWN(wxInteractiveMoveHandler::OnKeyDown)
424 END_EVENT_TABLE()
425
426
427 static inline LINKAGEMODE
428 void wxApplyResize(wxInteractiveMoveData& data, const wxPoint& diff)
429 {
430 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
431 {
432 data.m_rect.x += diff.x;
433 data.m_rect.width -= diff.x;
434 }
435 else if ( data.m_flags & wxINTERACTIVE_RESIZE_E )
436 {
437 data.m_rect.width += diff.x;
438 }
439 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
440 {
441 data.m_rect.y += diff.y;
442 data.m_rect.height -= diff.y;
443 }
444 else if ( data.m_flags & wxINTERACTIVE_RESIZE_S )
445 {
446 data.m_rect.height += diff.y;
447 }
448
449 if ( data.m_minSize.x != wxDefaultCoord && data.m_rect.width < data.m_minSize.x )
450 {
451 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
452 data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
453 data.m_rect.width = data.m_minSize.x;
454 }
455 if ( data.m_maxSize.x != wxDefaultCoord && data.m_rect.width > data.m_maxSize.x )
456 {
457 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
458 data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
459 data.m_rect.width = data.m_maxSize.x;
460 }
461 if ( data.m_minSize.y != wxDefaultCoord && data.m_rect.height < data.m_minSize.y )
462 {
463 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
464 data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
465 data.m_rect.height = data.m_minSize.y;
466 }
467 if ( data.m_maxSize.y != wxDefaultCoord && data.m_rect.height > data.m_maxSize.y )
468 {
469 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
470 data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
471 data.m_rect.height = data.m_maxSize.y;
472 }
473 }
474
475 void wxInteractiveMoveHandler::OnMouseMove(wxMouseEvent& event)
476 {
477 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
478 event.Skip();
479
480 else if ( m_data.m_flags & wxINTERACTIVE_MOVE )
481 {
482 wxPoint diff = wxGetMousePosition() - m_data.m_pos;
483 m_data.m_rect = m_data.m_rectOrig;
484 m_data.m_rect.Offset(diff);
485 m_data.m_window->Move(m_data.m_rect.GetPosition());
486 }
487
488 else if ( m_data.m_flags & wxINTERACTIVE_RESIZE )
489 {
490 wxPoint diff = wxGetMousePosition() - m_data.m_pos;
491 m_data.m_rect = m_data.m_rectOrig;
492 wxApplyResize(m_data, diff);
493 m_data.m_window->SetSize(m_data.m_rect);
494 }
495 }
496
497 void wxInteractiveMoveHandler::OnMouseDown(wxMouseEvent& WXUNUSED(event))
498 {
499 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
500 {
501 m_data.m_evtLoop->Exit();
502 }
503 }
504
505 void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent& event)
506 {
507 wxPoint diff(wxDefaultCoord,wxDefaultCoord);
508
509 switch ( event.GetKeyCode() )
510 {
511 case WXK_UP: diff = wxPoint(0, -16); break;
512 case WXK_DOWN: diff = wxPoint(0, 16); break;
513 case WXK_LEFT: diff = wxPoint(-16, 0); break;
514 case WXK_RIGHT: diff = wxPoint(16, 0); break;
515 case WXK_ESCAPE:
516 m_data.m_window->SetSize(m_data.m_rectOrig);
517 m_data.m_evtLoop->Exit();
518 return;
519 case WXK_RETURN:
520 m_data.m_evtLoop->Exit();
521 return;
522 }
523
524 if ( diff.x != wxDefaultCoord )
525 {
526 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
527 {
528 m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
529 if ( m_data.m_sizingCursor )
530 {
531 wxEndBusyCursor();
532 m_data.m_sizingCursor = false;
533 }
534
535 if ( m_data.m_flags & wxINTERACTIVE_MOVE )
536 {
537 m_data.m_pos = m_data.m_window->GetPosition() +
538 wxPoint(m_data.m_window->GetSize().x/2, 8);
539 }
540 }
541
542 wxPoint warp;
543 bool changeCur = false;
544
545 if ( m_data.m_flags & wxINTERACTIVE_MOVE )
546 {
547 m_data.m_rect.Offset(diff);
548 m_data.m_window->Move(m_data.m_rect.GetPosition());
549 warp = wxPoint(m_data.m_window->GetSize().x/2, 8);
550 }
551 else /* wxINTERACTIVE_RESIZE */
552 {
553 if ( !(m_data.m_flags &
554 (wxINTERACTIVE_RESIZE_N | wxINTERACTIVE_RESIZE_S)) )
555 {
556 if ( diff.y < 0 )
557 {
558 m_data.m_flags |= wxINTERACTIVE_RESIZE_N;
559 m_data.m_pos.y = m_data.m_window->GetPosition().y;
560 changeCur = true;
561 }
562 else if ( diff.y > 0 )
563 {
564 m_data.m_flags |= wxINTERACTIVE_RESIZE_S;
565 m_data.m_pos.y = m_data.m_window->GetPosition().y +
566 m_data.m_window->GetSize().y;
567 changeCur = true;
568 }
569 }
570 if ( !(m_data.m_flags &
571 (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E)) )
572 {
573 if ( diff.x < 0 )
574 {
575 m_data.m_flags |= wxINTERACTIVE_RESIZE_W;
576 m_data.m_pos.x = m_data.m_window->GetPosition().x;
577 changeCur = true;
578 }
579 else if ( diff.x > 0 )
580 {
581 m_data.m_flags |= wxINTERACTIVE_RESIZE_E;
582 m_data.m_pos.x = m_data.m_window->GetPosition().x +
583 m_data.m_window->GetSize().x;
584 changeCur = true;
585 }
586 }
587
588 wxApplyResize(m_data, diff);
589 m_data.m_window->SetSize(m_data.m_rect);
590
591 if ( m_data.m_flags & wxINTERACTIVE_RESIZE_W )
592 warp.x = 0;
593 else if ( m_data.m_flags & wxINTERACTIVE_RESIZE_E )
594 warp.x = m_data.m_window->GetSize().x-1;
595 else
596 warp.x = wxGetMousePosition().x - m_data.m_window->GetPosition().x;
597
598 if ( m_data.m_flags & wxINTERACTIVE_RESIZE_N )
599 warp.y = 0;
600 else if ( m_data.m_flags & wxINTERACTIVE_RESIZE_S )
601 warp.y = m_data.m_window->GetSize().y-1;
602 else
603 warp.y = wxGetMousePosition().y - m_data.m_window->GetPosition().y;
604 }
605
606 warp -= m_data.m_window->GetClientAreaOrigin();
607 m_data.m_window->WarpPointer(warp.x, warp.y);
608
609 if ( changeCur )
610 {
611 long hit = m_data.m_window->HitTest(warp);
612 wxCursor cur;
613 if ( wxGetResizingCursor(hit, cur) )
614 {
615 if ( m_data.m_sizingCursor )
616 wxEndBusyCursor();
617 wxBeginBusyCursor(&cur);
618 m_data.m_sizingCursor = true;
619 }
620 }
621 }
622 }
623
624 void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent& WXUNUSED(event))
625 {
626 m_data.m_evtLoop->Exit();
627 }
628
629
630 void wxTopLevelWindow::InteractiveMove(int flags)
631 {
632 wxASSERT_MSG( !((flags & wxINTERACTIVE_MOVE) && (flags & wxINTERACTIVE_RESIZE)),
633 wxT("can't move and resize window at the same time") );
634
635 wxASSERT_MSG( !(flags & wxINTERACTIVE_RESIZE) ||
636 (flags & wxINTERACTIVE_WAIT_FOR_INPUT) ||
637 (flags & wxINTERACTIVE_RESIZE_DIR),
638 wxT("direction of resizing not specified") );
639
640 wxInteractiveMoveData data;
641 wxEventLoop loop;
642
643 SetFocus();
644
645 #ifndef __WXGTK__
646 if ( flags & wxINTERACTIVE_WAIT_FOR_INPUT )
647 {
648 wxCursor sizingCursor(wxCURSOR_SIZING);
649 wxBeginBusyCursor(&sizingCursor);
650 data.m_sizingCursor = true;
651 }
652 else
653 #endif
654 data.m_sizingCursor = false;
655
656 data.m_window = this;
657 data.m_evtLoop = &loop;
658 data.m_flags = flags;
659 data.m_rect = data.m_rectOrig = GetRect();
660 data.m_pos = wxGetMousePosition();
661 data.m_minSize = wxSize(GetMinWidth(), GetMinHeight());
662 data.m_maxSize = wxSize(GetMaxWidth(), GetMaxHeight());
663
664 wxEvtHandler *handler = new wxInteractiveMoveHandler(data);
665 this->PushEventHandler(handler);
666
667 CaptureMouse();
668 loop.Run();
669 ReleaseMouse();
670
671 this->RemoveEventHandler(handler);
672 delete handler;
673
674 if ( data.m_sizingCursor )
675 wxEndBusyCursor();
676 }
677
678 // ----------------------------------------------------------------------------
679 // actions
680 // ----------------------------------------------------------------------------
681
682 void wxTopLevelWindow::ClickTitleBarButton(long button)
683 {
684 switch ( button )
685 {
686 case wxTOPLEVEL_BUTTON_CLOSE:
687 Close();
688 break;
689
690 case wxTOPLEVEL_BUTTON_ICONIZE:
691 Iconize();
692 break;
693
694 case wxTOPLEVEL_BUTTON_MAXIMIZE:
695 Maximize();
696 break;
697
698 case wxTOPLEVEL_BUTTON_RESTORE:
699 Restore();
700 break;
701
702 case wxTOPLEVEL_BUTTON_HELP:
703 #if wxUSE_HELP
704 {
705 wxContextHelp contextHelp(this);
706 }
707 #endif
708 break;
709
710 default:
711 wxFAIL_MSG(wxT("incorrect button specification"));
712 }
713 }
714
715 bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
716 long numArg,
717 const wxString& WXUNUSED(strArg))
718 {
719 bool isActive = numArg != 0;
720
721 if ( action == wxACTION_TOPLEVEL_ACTIVATE )
722 {
723 if ( m_isActive != isActive )
724 {
725 m_isActive = isActive;
726 RefreshTitleBar();
727 }
728 return true;
729 }
730
731 else if ( action == wxACTION_TOPLEVEL_BUTTON_PRESS )
732 {
733 m_pressedButton = numArg;
734 RefreshTitleBar();
735 return true;
736 }
737
738 else if ( action == wxACTION_TOPLEVEL_BUTTON_RELEASE )
739 {
740 m_pressedButton = 0;
741 RefreshTitleBar();
742 return true;
743 }
744
745 else if ( action == wxACTION_TOPLEVEL_BUTTON_CLICK )
746 {
747 m_pressedButton = 0;
748 RefreshTitleBar();
749 ClickTitleBarButton(numArg);
750 return true;
751 }
752
753 else if ( action == wxACTION_TOPLEVEL_MOVE )
754 {
755 InteractiveMove(wxINTERACTIVE_MOVE);
756 return true;
757 }
758
759 else if ( action == wxACTION_TOPLEVEL_RESIZE )
760 {
761 int flags = wxINTERACTIVE_RESIZE;
762 if ( numArg & wxHT_TOPLEVEL_BORDER_N )
763 flags |= wxINTERACTIVE_RESIZE_N;
764 if ( numArg & wxHT_TOPLEVEL_BORDER_S )
765 flags |= wxINTERACTIVE_RESIZE_S;
766 if ( numArg & wxHT_TOPLEVEL_BORDER_W )
767 flags |= wxINTERACTIVE_RESIZE_W;
768 if ( numArg & wxHT_TOPLEVEL_BORDER_E )
769 flags |= wxINTERACTIVE_RESIZE_E;
770 InteractiveMove(flags);
771 return true;
772 }
773
774 else
775 return false;
776 }
777
778 void wxTopLevelWindow::OnSystemMenu(wxCommandEvent& event)
779 {
780 bool ret = true;
781
782 switch (event.GetId())
783 {
784 case wxID_CLOSE_FRAME:
785 ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
786 wxTOPLEVEL_BUTTON_CLOSE);
787 break;
788 case wxID_MOVE_FRAME:
789 InteractiveMove(wxINTERACTIVE_MOVE | wxINTERACTIVE_WAIT_FOR_INPUT);
790 break;
791 case wxID_RESIZE_FRAME:
792 InteractiveMove(wxINTERACTIVE_RESIZE | wxINTERACTIVE_WAIT_FOR_INPUT);
793 break;
794 case wxID_MAXIMIZE_FRAME:
795 ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
796 wxTOPLEVEL_BUTTON_MAXIMIZE);
797 break;
798 case wxID_ICONIZE_FRAME:
799 ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
800 wxTOPLEVEL_BUTTON_ICONIZE);
801 break;
802 case wxID_RESTORE_FRAME:
803 ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
804 wxTOPLEVEL_BUTTON_RESTORE);
805 break;
806
807 default:
808 ret = false;
809 }
810
811 if ( !ret )
812 event.Skip();
813 }
814
815 /* static */
816 wxInputHandler *
817 wxTopLevelWindow::GetStdInputHandler(wxInputHandler *handlerDef)
818 {
819 static wxStdTLWInputHandler s_handler(handlerDef);
820
821 return &s_handler;
822 }
823
824 // ============================================================================
825 // wxStdTLWInputHandler: handles focus, resizing and titlebar buttons clicks
826 // ============================================================================
827
828 wxStdTLWInputHandler::wxStdTLWInputHandler(wxInputHandler *inphand)
829 : wxStdInputHandler(inphand)
830 {
831 m_winCapture = NULL;
832 m_winHitTest = 0;
833 m_winPressed = 0;
834 m_borderCursorOn = false;
835 }
836
837 bool wxStdTLWInputHandler::HandleMouse(wxInputConsumer *consumer,
838 const wxMouseEvent& event)
839 {
840 // the button has 2 states: pressed and normal with the following
841 // transitions between them:
842 //
843 // normal -> left down -> capture mouse and go to pressed state
844 // pressed -> left up inside -> generate click -> go to normal
845 // outside ------------------>
846 //
847 // the other mouse buttons are ignored
848 if ( event.Button(1) )
849 {
850 if ( event.ButtonDown(1) )
851 {
852 wxTopLevelWindow *w = wxStaticCast(consumer->GetInputWindow(), wxTopLevelWindow);
853 long hit = w->HitTest(event.GetPosition());
854
855 if ( hit & wxHT_TOPLEVEL_ANY_BUTTON )
856 {
857 m_winCapture = w;
858 m_winCapture->CaptureMouse();
859 m_winHitTest = hit;
860 m_winPressed = hit;
861 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
862 return true;
863 }
864 else if ( (hit & wxHT_TOPLEVEL_TITLEBAR) && !w->IsMaximized() )
865 {
866 consumer->PerformAction(wxACTION_TOPLEVEL_MOVE);
867 return true;
868 }
869 else if ( (consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER)
870 && (hit & wxHT_TOPLEVEL_ANY_BORDER) )
871 {
872 consumer->PerformAction(wxACTION_TOPLEVEL_RESIZE, hit);
873 return true;
874 }
875 }
876
877 else // up
878 {
879 if ( m_winCapture )
880 {
881 m_winCapture->ReleaseMouse();
882 m_winCapture = NULL;
883
884 if ( m_winHitTest == m_winPressed )
885 {
886 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK, m_winPressed);
887 return true;
888 }
889 }
890 //else: the mouse was released outside the window, this doesn't
891 // count as a click
892 }
893 }
894
895 return wxStdInputHandler::HandleMouse(consumer, event);
896 }
897
898 bool wxStdTLWInputHandler::HandleMouseMove(wxInputConsumer *consumer,
899 const wxMouseEvent& event)
900 {
901 if ( event.GetEventObject() == m_winCapture )
902 {
903 long hit = m_winCapture->HitTest(event.GetPosition());
904
905 if ( hit != m_winHitTest )
906 {
907 if ( hit != m_winPressed )
908 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_RELEASE, m_winPressed);
909 else
910 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
911
912 m_winHitTest = hit;
913 return true;
914 }
915 }
916 else if ( consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER )
917 {
918 wxTopLevelWindow *win = wxStaticCast(consumer->GetInputWindow(),
919 wxTopLevelWindow);
920 long hit = win->HitTest(event.GetPosition());
921
922 if ( hit != m_winHitTest )
923 {
924 m_winHitTest = hit;
925
926 if ( m_borderCursorOn )
927 {
928 m_borderCursorOn = false;
929 win->SetCursor(m_origCursor);
930 }
931
932 if ( hit & wxHT_TOPLEVEL_ANY_BORDER )
933 {
934 wxCursor cur;
935
936 m_borderCursorOn = wxGetResizingCursor(hit, cur);
937 if ( m_borderCursorOn )
938 {
939 m_origCursor = win->GetCursor();
940 win->SetCursor(cur);
941 }
942 }
943 }
944 }
945
946 return wxStdInputHandler::HandleMouseMove(consumer, event);
947 }
948
949 bool wxStdTLWInputHandler::HandleActivation(wxInputConsumer *consumer,
950 bool activated)
951 {
952 if ( m_borderCursorOn )
953 {
954 consumer->GetInputWindow()->SetCursor(m_origCursor);
955 m_borderCursorOn = false;
956 }
957 consumer->PerformAction(wxACTION_TOPLEVEL_ACTIVATE, activated);
958 return false;
959 }