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