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