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