Remove all lines containing cvs/svn "$Id$" keyword.
[wxWidgets.git] / src / univ / topluniv.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/topluniv.cpp
3 // Author: Vaclav Slavik
4 // Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
5 // Licence: wxWindows licence
6 /////////////////////////////////////////////////////////////////////////////
7
8 // ============================================================================
9 // declarations
10 // ============================================================================
11
12 // ----------------------------------------------------------------------------
13 // headers
14 // ----------------------------------------------------------------------------
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #include "wx/toplevel.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/dcclient.h"
27 #include "wx/settings.h"
28 #include "wx/bitmap.h"
29 #include "wx/image.h"
30 #include "wx/frame.h"
31 #endif
32
33 #include "wx/univ/renderer.h"
34 #include "wx/cshelp.h"
35 #include "wx/evtloop.h"
36
37 // ----------------------------------------------------------------------------
38 // wxStdTLWInputHandler: handles focus, resizing and titlebar buttons clicks
39 // ----------------------------------------------------------------------------
40
41 class WXDLLEXPORT wxStdTLWInputHandler : public wxStdInputHandler
42 {
43 public:
44 wxStdTLWInputHandler(wxInputHandler *inphand);
45
46 virtual bool HandleMouse(wxInputConsumer *consumer,
47 const wxMouseEvent& event);
48 virtual bool HandleMouseMove(wxInputConsumer *consumer, const wxMouseEvent& event);
49 virtual bool HandleActivation(wxInputConsumer *consumer, bool activated);
50
51 private:
52 // the window (button) which has capture or NULL and the last hittest result
53 wxTopLevelWindow *m_winCapture;
54 long m_winHitTest;
55 long m_winPressed;
56 bool m_borderCursorOn;
57 wxCursor m_origCursor;
58 };
59
60
61 // ----------------------------------------------------------------------------
62 // event tables
63 // ----------------------------------------------------------------------------
64
65 BEGIN_EVENT_TABLE(wxTopLevelWindow, wxTopLevelWindowNative)
66 WX_EVENT_TABLE_INPUT_CONSUMER(wxTopLevelWindow)
67 EVT_NC_PAINT(wxTopLevelWindow::OnNcPaint)
68 EVT_MENU_RANGE(wxID_CLOSE_FRAME, wxID_RESTORE_FRAME, wxTopLevelWindow::OnSystemMenu)
69 END_EVENT_TABLE()
70
71 WX_FORWARD_TO_INPUT_CONSUMER(wxTopLevelWindow)
72
73 // ============================================================================
74 // implementation
75 // ============================================================================
76
77 int wxTopLevelWindow::ms_drawDecorations = -1;
78 int wxTopLevelWindow::ms_canIconize = -1;
79
80 void wxTopLevelWindow::Init()
81 {
82 // once-only ms_drawDecorations initialization
83 if ( ms_drawDecorations == -1 )
84 {
85 ms_drawDecorations =
86 !wxSystemSettings::HasFeature(wxSYS_CAN_DRAW_FRAME_DECORATIONS) ||
87 wxGetEnv(wxT("WXDECOR"), NULL);
88 }
89
90 m_usingNativeDecorations = ms_drawDecorations == 0;
91 m_isActive = false;
92 m_windowStyle = 0;
93 m_pressedButton = 0;
94 }
95
96 bool wxTopLevelWindow::Create(wxWindow *parent,
97 wxWindowID id,
98 const wxString& title,
99 const wxPoint& pos,
100 const wxSize& size,
101 long style,
102 const wxString &name)
103 {
104 // init them to avoid compiler warnings
105 long styleOrig = 0,
106 exstyleOrig = 0;
107
108 if ( !m_usingNativeDecorations )
109 {
110 CreateInputHandler(wxINP_HANDLER_TOPLEVEL);
111
112 styleOrig = style;
113 exstyleOrig = GetExtraStyle();
114 style &= ~(wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX |
115 wxSYSTEM_MENU | wxFRAME_TOOL_WINDOW | wxRESIZE_BORDER);
116 style |= wxBORDER_NONE;
117 SetExtraStyle(exstyleOrig & ~wxWS_EX_CONTEXTHELP);
118 }
119
120 if ( !wxTopLevelWindowNative::Create(parent, id, title, pos,
121 size, style, name) )
122 return false;
123
124 if ( !m_usingNativeDecorations )
125 {
126 m_windowStyle = styleOrig;
127 m_exStyle = exstyleOrig;
128 }
129
130 return true;
131 }
132
133 bool wxTopLevelWindow::ShowFullScreen(bool show, long style)
134 {
135 if ( show == IsFullScreen() ) return false;
136
137 if ( !m_usingNativeDecorations )
138 {
139 if ( show )
140 {
141 m_fsSavedStyle = m_windowStyle;
142 if ( style & wxFULLSCREEN_NOBORDER )
143 m_windowStyle |= wxSIMPLE_BORDER;
144 if ( style & wxFULLSCREEN_NOCAPTION )
145 m_windowStyle &= ~wxCAPTION;
146 }
147 else
148 {
149 m_windowStyle = m_fsSavedStyle;
150 }
151 }
152
153 return wxTopLevelWindowNative::ShowFullScreen(show, style);
154 }
155
156 /* static */
157 void wxTopLevelWindow::UseNativeDecorationsByDefault(bool native)
158 {
159 ms_drawDecorations = !native;
160 }
161
162 void wxTopLevelWindow::UseNativeDecorations(bool native)
163 {
164 wxASSERT_MSG( !m_windowStyle, wxT("must be called before Create()") );
165
166 m_usingNativeDecorations = native;
167 }
168
169 bool wxTopLevelWindow::IsUsingNativeDecorations() const
170 {
171 return m_usingNativeDecorations;
172 }
173
174 long wxTopLevelWindow::GetDecorationsStyle() const
175 {
176 long style = 0;
177
178 if ( m_windowStyle & wxCAPTION )
179 {
180 if ( ms_canIconize == -1 )
181 {
182 ms_canIconize = wxSystemSettings::HasFeature(wxSYS_CAN_ICONIZE_FRAME);
183 }
184
185 style |= wxTOPLEVEL_TITLEBAR;
186 if ( m_windowStyle & wxCLOSE_BOX )
187 style |= 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 )
205 style |= wxTOPLEVEL_RESIZEABLE;
206
207 if ( IsMaximized() )
208 style |= wxTOPLEVEL_MAXIMIZED;
209 if ( GetIcon().IsOk() )
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.IsOk() || size.x == wxDefaultCoord )
331 m_titlebarIcon = icon;
332 else
333 {
334 wxBitmap bmp1;
335 bmp1.CopyFromIcon(icon);
336 if ( !bmp1.IsOk() )
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 }