]> git.saurik.com Git - wxWidgets.git/blame - src/univ/topluniv.cpp
wxRegion fixes (off by one)
[wxWidgets.git] / src / univ / topluniv.cpp
CommitLineData
0f1bf77d
VS
1/////////////////////////////////////////////////////////////////////////////
2// Name: topluniv.cpp
3// Author: Vaclav Slavik
4// Id: $Id$
5// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
6// Licence: wxWindows licence
7/////////////////////////////////////////////////////////////////////////////
8
9// ============================================================================
10// declarations
11// ============================================================================
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
17#ifdef __GNUG__
18 #pragma implementation "univtoplevel.h"
19#endif
20
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25#pragma hdrstop
26#endif
27
28#include "wx/defs.h"
f8e3449c
VS
29
30#ifndef WX_PRECOMP
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
33#endif
34
0f1bf77d 35#include "wx/toplevel.h"
24a23c35 36#include "wx/univ/renderer.h"
24a23c35
VS
37#include "wx/bitmap.h"
38#include "wx/image.h"
813edf09 39#include "wx/cshelp.h"
0f1bf77d
VS
40
41
42// ----------------------------------------------------------------------------
43// event tables
44// ----------------------------------------------------------------------------
45
24a23c35 46BEGIN_EVENT_TABLE(wxTopLevelWindow, wxTopLevelWindowNative)
ea1b0d6c 47 WX_EVENT_TABLE_INPUT_CONSUMER(wxTopLevelWindow)
24a23c35
VS
48 EVT_NC_PAINT(wxTopLevelWindow::OnNcPaint)
49END_EVENT_TABLE()
50
ea1b0d6c
VS
51WX_FORWARD_TO_INPUT_CONSUMER(wxTopLevelWindow)
52
0f1bf77d
VS
53// ============================================================================
54// implementation
55// ============================================================================
56
24a23c35
VS
57int wxTopLevelWindow::ms_drawDecorations = -1;
58
0f1bf77d
VS
59void wxTopLevelWindow::Init()
60{
24a23c35 61 m_isActive = FALSE;
ea1b0d6c 62 m_windowStyle = 0;
813edf09 63 m_pressedButton = 0;
0f1bf77d
VS
64}
65
66bool wxTopLevelWindow::Create(wxWindow *parent,
67 wxWindowID id,
68 const wxString& title,
69 const wxPoint& pos,
7ee7c43f 70 const wxSize& size,
0f1bf77d
VS
71 long style,
72 const wxString &name)
73{
2e9f62da
VZ
74 // init them to avoid compiler warnings
75 long styleOrig = 0,
76 exstyleOrig = 0;
24a23c35
VS
77
78 if ( ms_drawDecorations == -1 )
4c785218
VS
79 ms_drawDecorations = !wxSystemSettings::HasFrameDecorations() ||
80 wxGetEnv(wxT("WXDECOR"), NULL);
81 // FIXME -- wxUniv should provide a way to force non-native decorations!
82 // $WXDECOR is just a hack in absence of better wxUniv solution
24a23c35
VS
83
84 if ( ms_drawDecorations )
85 {
ea1b0d6c
VS
86 CreateInputHandler(wxINP_HANDLER_TOPLEVEL);
87
24a23c35
VS
88 styleOrig = style;
89 exstyleOrig = GetExtraStyle();
7ee7c43f
VZ
90 style &= ~(wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX |
91 wxSYSTEM_MENU | wxRESIZE_BORDER | wxFRAME_TOOL_WINDOW |
813edf09
VS
92 wxTHICK_FRAME);
93 style = wxSIMPLE_BORDER;
7ee7c43f 94 SetExtraStyle(exstyleOrig &
813edf09 95 ~(wxFRAME_EX_CONTEXTHELP | wxDIALOG_EX_CONTEXTHELP));
24a23c35
VS
96 }
97
7ee7c43f
VZ
98 if ( !wxTopLevelWindowNative::Create(parent, id, title, pos,
99 size, style, name) )
100 return FALSE;
101
24a23c35
VS
102 if ( ms_drawDecorations )
103 {
104 m_windowStyle = styleOrig;
105 m_exStyle = exstyleOrig;
106 }
7ee7c43f 107
0f1bf77d
VS
108 return TRUE;
109}
110
111bool wxTopLevelWindow::ShowFullScreen(bool show, long style)
112{
113 if ( show == IsFullScreen() ) return FALSE;
7ee7c43f 114
ea1b0d6c
VS
115 if ( ms_drawDecorations )
116 {
117 if ( show )
118 {
119 m_fsSavedStyle = m_windowStyle;
120 if ( style & wxFULLSCREEN_NOBORDER )
121 m_windowStyle |= wxSIMPLE_BORDER;
122 if ( style & wxFULLSCREEN_NOCAPTION )
123 m_windowStyle &= ~wxCAPTION;
124 }
125 else
126 {
127 m_windowStyle = m_fsSavedStyle;
128 }
129 }
2e9f62da 130
ea1b0d6c 131 return wxTopLevelWindowNative::ShowFullScreen(show, style);
0f1bf77d
VS
132}
133
24a23c35
VS
134long wxTopLevelWindow::GetDecorationsStyle() const
135{
136 long style = 0;
137
138 if ( m_windowStyle & wxCAPTION )
139 {
ea1b0d6c 140 style |= wxTOPLEVEL_TITLEBAR | wxTOPLEVEL_BUTTON_CLOSE;
24a23c35 141 if ( m_windowStyle & wxMINIMIZE_BOX )
813edf09 142 style |= wxTOPLEVEL_BUTTON_ICONIZE;
24a23c35 143 if ( m_windowStyle & wxMAXIMIZE_BOX )
15678bec
VS
144 {
145 if ( IsMaximized() )
146 style |= wxTOPLEVEL_BUTTON_RESTORE;
147 else
148 style |= wxTOPLEVEL_BUTTON_MAXIMIZE;
149 }
813edf09 150#if wxUSE_HELP
24a23c35 151 if ( m_exStyle & (wxFRAME_EX_CONTEXTHELP | wxDIALOG_EX_CONTEXTHELP))
ea1b0d6c 152 style |= wxTOPLEVEL_BUTTON_HELP;
813edf09 153#endif
24a23c35
VS
154 }
155 if ( (m_windowStyle & (wxSIMPLE_BORDER | wxNO_BORDER)) == 0 )
156 style |= wxTOPLEVEL_BORDER;
157 if ( m_windowStyle & (wxRESIZE_BORDER | wxTHICK_FRAME) )
158 style |= wxTOPLEVEL_RESIZEABLE;
7ee7c43f 159
24a23c35
VS
160 if ( IsMaximized() )
161 style |= wxTOPLEVEL_MAXIMIZED;
162 if ( GetIcon().Ok() )
163 style |= wxTOPLEVEL_ICON;
ea1b0d6c 164 if ( m_isActive )
24a23c35
VS
165 style |= wxTOPLEVEL_ACTIVE;
166
167 return style;
168}
169
813edf09
VS
170void wxTopLevelWindow::RefreshTitleBar()
171{
172 wxNcPaintEvent event(GetId());
173 event.SetEventObject(this);
174 GetEventHandler()->ProcessEvent(event);
175}
176
24a23c35
VS
177// ----------------------------------------------------------------------------
178// client area handling
179// ----------------------------------------------------------------------------
180
181wxPoint wxTopLevelWindow::GetClientAreaOrigin() const
182{
183 if ( ms_drawDecorations )
184 {
185 int w, h;
186 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
187 wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
188 wxSize(w, h));
7ee7c43f 189 rect = m_renderer->GetFrameClientArea(rect,
24a23c35
VS
190 GetDecorationsStyle());
191 return rect.GetPosition();
192 }
193 else
194 {
195 return wxTopLevelWindowNative::GetClientAreaOrigin();
196 }
197}
198
199void wxTopLevelWindow::DoGetClientSize(int *width, int *height) const
200{
201 if ( ms_drawDecorations )
202 {
203 int w, h;
204 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
205 wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
206 wxSize(w, h));
7ee7c43f 207 rect = m_renderer->GetFrameClientArea(rect,
24a23c35
VS
208 GetDecorationsStyle());
209 if ( width )
210 *width = rect.width;
211 if ( height )
212 *height = rect.height;
213 }
214 else
215 wxTopLevelWindowNative::DoGetClientSize(width, height);
216}
217
218void wxTopLevelWindow::DoSetClientSize(int width, int height)
219{
220 if ( ms_drawDecorations )
221 {
7ee7c43f 222 wxSize size = m_renderer->GetFrameTotalSize(wxSize(width, height),
24a23c35
VS
223 GetDecorationsStyle());
224 wxTopLevelWindowNative::DoSetClientSize(size.x, size.y);
225 }
226 else
227 wxTopLevelWindowNative::DoSetClientSize(width, height);
228}
229
230void wxTopLevelWindow::OnNcPaint(wxPaintEvent& event)
231{
232 if ( !ms_drawDecorations || !m_renderer )
233 event.Skip();
234 else
235 {
236 // get the window rect
237 wxRect rect;
238 wxSize size = GetSize();
239 rect.x =
240 rect.y = 0;
241 rect.width = size.x;
242 rect.height = size.y;
243
244 wxWindowDC dc(this);
7ee7c43f 245 m_renderer->DrawFrameTitleBar(dc, rect,
24a23c35 246 GetTitle(), m_titlebarIcon,
813edf09
VS
247 GetDecorationsStyle(),
248 m_pressedButton,
249 wxCONTROL_PRESSED);
24a23c35
VS
250 }
251}
252
813edf09
VS
253long wxTopLevelWindow::HitTest(const wxPoint& pt) const
254{
255 int w, h;
256 wxTopLevelWindowNative::DoGetClientSize(&w, &h);
257 wxRect rect(wxTopLevelWindowNative::GetClientAreaOrigin(), wxSize(w, h));
7ee7c43f 258
813edf09
VS
259 return m_renderer->HitTestFrame(rect, pt, GetDecorationsStyle());
260}
261
24a23c35
VS
262// ----------------------------------------------------------------------------
263// icons
264// ----------------------------------------------------------------------------
265
266void wxTopLevelWindow::SetIcon(const wxIcon& icon)
267{
268 wxTopLevelWindowNative::SetIcon(icon);
24a23c35 269
15678bec 270 if ( ms_drawDecorations && m_renderer )
24a23c35 271 {
15678bec
VS
272 wxSize size = m_renderer->GetFrameIconSize();
273
274 if ( !icon.Ok() || size.x == -1 )
24a23c35
VS
275 m_titlebarIcon = icon;
276 else
277 {
15678bec
VS
278 wxBitmap bmp1;
279 bmp1.CopyFromIcon(icon);
280 if ( !bmp1.Ok() )
281 m_titlebarIcon = wxNullIcon;
282 else if ( bmp1.GetWidth() == size.x && bmp1.GetHeight() == size.y )
283 m_titlebarIcon = icon;
284 else
285 {
286 wxImage img = bmp1.ConvertToImage();
287 img.Rescale(size.x, size.y);
288 m_titlebarIcon.CopyFromBitmap(wxBitmap(img));
289 }
24a23c35
VS
290 }
291 }
292}
ea1b0d6c
VS
293
294// ----------------------------------------------------------------------------
295// actions
296// ----------------------------------------------------------------------------
297
813edf09
VS
298void wxTopLevelWindow::ClickTitleBarButton(long button)
299{
300 switch ( button )
301 {
302 case wxTOPLEVEL_BUTTON_CLOSE:
303 Close();
304 break;
305
306 case wxTOPLEVEL_BUTTON_ICONIZE:
307 Iconize();
308 break;
309
310 case wxTOPLEVEL_BUTTON_MAXIMIZE:
311 Maximize();
312 break;
313
314 case wxTOPLEVEL_BUTTON_RESTORE:
315 Restore();
316 break;
317
318 case wxTOPLEVEL_BUTTON_HELP:
319#if wxUSE_HELP
320 {
321 wxContextHelp contextHelp(this);
322 }
323#endif
324 break;
7ee7c43f 325
813edf09
VS
326 default:
327 wxFAIL_MSG(wxT("incorrect button specification"));
328 }
329}
330
ea1b0d6c
VS
331bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
332 long numArg,
333 const wxString& strArg)
334{
7ee7c43f
VZ
335 bool isActive = numArg != 0;
336
ea1b0d6c
VS
337 if ( action == wxACTION_TOPLEVEL_ACTIVATE )
338 {
7ee7c43f 339 if ( m_isActive != isActive )
ea1b0d6c 340 {
7ee7c43f 341 m_isActive = isActive;
b22d16ad 342 RefreshTitleBar();
ea1b0d6c
VS
343 }
344 return TRUE;
345 }
7ee7c43f 346
813edf09
VS
347 else if ( action == wxACTION_TOPLEVEL_BUTTON_PRESS )
348 {
349 m_pressedButton = numArg;
350 RefreshTitleBar();
351 return TRUE;
352 }
7ee7c43f 353
813edf09
VS
354 else if ( action == wxACTION_TOPLEVEL_BUTTON_RELEASE )
355 {
356 m_pressedButton = 0;
357 RefreshTitleBar();
358 return TRUE;
359 }
7ee7c43f 360
813edf09
VS
361 else if ( action == wxACTION_TOPLEVEL_BUTTON_CLICK )
362 {
363 m_pressedButton = 0;
364 RefreshTitleBar();
365 ClickTitleBarButton(numArg);
366 return TRUE;
367 }
71e03035 368
b22d16ad
VS
369 else if ( action == wxACTION_TOPLEVEL_MOVE )
370 {
371 InteractiveMove(wxINTERACTIVE_MOVE);
372 return TRUE;
373 }
71e03035 374
b22d16ad
VS
375 else if ( action == wxACTION_TOPLEVEL_RESIZE )
376 {
377 int flags = wxINTERACTIVE_RESIZE;
378 if ( numArg & wxHT_TOPLEVEL_BORDER_N )
379 flags |= wxINTERACTIVE_RESIZE_N;
380 if ( numArg & wxHT_TOPLEVEL_BORDER_S )
381 flags |= wxINTERACTIVE_RESIZE_S;
382 if ( numArg & wxHT_TOPLEVEL_BORDER_W )
383 flags |= wxINTERACTIVE_RESIZE_W;
384 if ( numArg & wxHT_TOPLEVEL_BORDER_E )
385 flags |= wxINTERACTIVE_RESIZE_E;
386 InteractiveMove(flags);
387 return TRUE;
388 }
71e03035 389
ea1b0d6c
VS
390 else
391 return FALSE;
392}
393
394
395// ============================================================================
396// wxStdFrameInputHandler: handles focus, resizing and titlebar buttons clicks
397// ============================================================================
398
399wxStdFrameInputHandler::wxStdFrameInputHandler(wxInputHandler *inphand)
400 : wxStdInputHandler(inphand)
401{
813edf09
VS
402 m_winCapture = NULL;
403 m_winHitTest = 0;
404 m_winPressed = 0;
b22d16ad 405 m_borderCursorOn = FALSE;
ea1b0d6c
VS
406}
407
408bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer *consumer,
409 const wxMouseEvent& event)
410{
813edf09
VS
411 // the button has 2 states: pressed and normal with the following
412 // transitions between them:
413 //
414 // normal -> left down -> capture mouse and go to pressed state
415 // pressed -> left up inside -> generate click -> go to normal
416 // outside ------------------>
417 //
418 // the other mouse buttons are ignored
419 if ( event.Button(1) )
420 {
421 if ( event.ButtonDown(1) )
422 {
423 wxTopLevelWindow *w = wxStaticCast(consumer->GetInputWindow(), wxTopLevelWindow);
424 long hit = w->HitTest(event.GetPosition());
7ee7c43f 425
813edf09
VS
426 if ( hit & wxHT_TOPLEVEL_ANY_BUTTON )
427 {
428 m_winCapture = w;
429 m_winCapture->CaptureMouse();
430 m_winHitTest = hit;
431 m_winPressed = hit;
432 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
433 return TRUE;
434 }
b22d16ad
VS
435 else if ( hit & wxHT_TOPLEVEL_TITLEBAR )
436 {
437 consumer->PerformAction(wxACTION_TOPLEVEL_MOVE);
438 return TRUE;
439 }
440 else if ( (consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER)
441 && (hit & wxHT_TOPLEVEL_ANY_BORDER) )
442 {
443 consumer->PerformAction(wxACTION_TOPLEVEL_RESIZE, hit);
444 return TRUE;
445 }
813edf09
VS
446 }
447
448 else // up
449 {
450 if ( m_winCapture )
451 {
452 m_winCapture->ReleaseMouse();
453 m_winCapture = NULL;
454
455 if ( m_winHitTest == m_winPressed )
456 {
457 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK, m_winPressed);
458 return TRUE;
459 }
460 }
461 //else: the mouse was released outside the window, this doesn't
462 // count as a click
463 }
464 }
465
ea1b0d6c
VS
466 return wxStdInputHandler::HandleMouse(consumer, event);
467}
468
7ee7c43f 469bool wxStdFrameInputHandler::HandleMouseMove(wxInputConsumer *consumer,
ea1b0d6c
VS
470 const wxMouseEvent& event)
471{
813edf09
VS
472 if ( event.GetEventObject() == m_winCapture )
473 {
474 long hit = m_winCapture->HitTest(event.GetPosition());
475
476 if ( hit != m_winHitTest )
477 {
478 if ( hit != m_winPressed )
479 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_RELEASE, m_winPressed);
480 else
481 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
7ee7c43f 482
813edf09
VS
483 m_winHitTest = hit;
484 return TRUE;
485 }
486 }
b22d16ad
VS
487 else if ( consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER )
488 {
71e03035 489 wxTopLevelWindow *win = wxStaticCast(consumer->GetInputWindow(),
b22d16ad
VS
490 wxTopLevelWindow);
491 long hit = win->HitTest(event.GetPosition());
71e03035 492
b22d16ad
VS
493 if ( hit != m_winHitTest )
494 {
495 m_winHitTest = hit;
71e03035 496
b22d16ad
VS
497 if ( m_borderCursorOn )
498 {
499 m_borderCursorOn = FALSE;
500 win->SetCursor(m_origCursor);
501 }
71e03035 502
b22d16ad
VS
503 if ( hit & wxHT_TOPLEVEL_ANY_BORDER )
504 {
505 m_borderCursorOn = TRUE;
506 wxCursor cur;
71e03035 507
b22d16ad
VS
508 switch (hit)
509 {
510 case wxHT_TOPLEVEL_BORDER_N:
511 case wxHT_TOPLEVEL_BORDER_S:
512 cur = wxCursor(wxCURSOR_SIZENS);
513 break;
514 case wxHT_TOPLEVEL_BORDER_W:
515 case wxHT_TOPLEVEL_BORDER_E:
516 cur = wxCursor(wxCURSOR_SIZEWE);
517 break;
518 case wxHT_TOPLEVEL_BORDER_NE:
519 case wxHT_TOPLEVEL_BORDER_SW:
520 cur = wxCursor(wxCURSOR_SIZENESW);
521 break;
522 case wxHT_TOPLEVEL_BORDER_NW:
523 case wxHT_TOPLEVEL_BORDER_SE:
524 cur = wxCursor(wxCURSOR_SIZENWSE);
525 break;
526 default:
527 m_borderCursorOn = FALSE;
528 break;
529 }
530 if ( m_borderCursorOn )
531 {
532 m_origCursor = win->GetCursor();
533 win->SetCursor(cur);
534 }
535 }
536 }
537 }
813edf09 538
ea1b0d6c
VS
539 return wxStdInputHandler::HandleMouseMove(consumer, event);
540}
541
7ee7c43f 542bool wxStdFrameInputHandler::HandleActivation(wxInputConsumer *consumer,
ea1b0d6c
VS
543 bool activated)
544{
b22d16ad
VS
545 if ( m_borderCursorOn )
546 {
547 consumer->GetInputWindow()->SetCursor(m_origCursor);
548 m_borderCursorOn = FALSE;
549 }
ea1b0d6c
VS
550 consumer->PerformAction(wxACTION_TOPLEVEL_ACTIVATE, activated);
551 return FALSE;
552}