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