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