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