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