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