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