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