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