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