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