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