1 /////////////////////////////////////////////////////////////////////////////
3 // Author: Vaclav Slavik
5 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
9 // ============================================================================
11 // ============================================================================
13 // ----------------------------------------------------------------------------
15 // ----------------------------------------------------------------------------
18 #pragma implementation "univtoplevel.h"
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
31 #include "wx/dcclient.h"
32 #include "wx/settings.h"
35 #include "wx/toplevel.h"
36 #include "wx/univ/renderer.h"
37 #include "wx/bitmap.h"
39 #include "wx/cshelp.h"
40 #include "wx/evtloop.h"
43 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
47 BEGIN_EVENT_TABLE(wxTopLevelWindow
, wxTopLevelWindowNative
)
48 WX_EVENT_TABLE_INPUT_CONSUMER(wxTopLevelWindow
)
49 EVT_NC_PAINT(wxTopLevelWindow::OnNcPaint
)
52 WX_FORWARD_TO_INPUT_CONSUMER(wxTopLevelWindow
)
54 // ============================================================================
56 // ============================================================================
58 int wxTopLevelWindow::ms_drawDecorations
= -1;
59 int wxTopLevelWindow::ms_canIconize
= -1;
61 void wxTopLevelWindow::Init()
68 bool wxTopLevelWindow::Create(wxWindow
*parent
,
70 const wxString
& title
,
76 // init them to avoid compiler warnings
80 if ( ms_drawDecorations
== -1 )
83 !wxSystemSettings::HasFeature(wxSYS_CAN_DRAW_FRAME_DECORATIONS
)
84 || wxGetEnv(wxT("WXDECOR"), NULL
);
85 // FIXME -- wxUniv should provide a way to force non-native decorations!
86 // $WXDECOR is just a hack in absence of better wxUniv solution
89 if ( ms_canIconize
== -1 )
91 ms_canIconize
= wxSystemSettings::HasFeature(wxSYS_CAN_ICONIZE_FRAME
);
94 if ( ms_drawDecorations
)
96 CreateInputHandler(wxINP_HANDLER_TOPLEVEL
);
99 exstyleOrig
= GetExtraStyle();
100 style
&= ~(wxCAPTION
| wxMINIMIZE_BOX
| wxMAXIMIZE_BOX
|
101 wxSYSTEM_MENU
| wxRESIZE_BORDER
| wxFRAME_TOOL_WINDOW
|
103 style
= wxSIMPLE_BORDER
;
104 SetExtraStyle(exstyleOrig
&
105 ~(wxFRAME_EX_CONTEXTHELP
| wxDIALOG_EX_CONTEXTHELP
));
108 if ( !wxTopLevelWindowNative::Create(parent
, id
, title
, pos
,
112 if ( ms_drawDecorations
)
114 m_windowStyle
= styleOrig
;
115 m_exStyle
= exstyleOrig
;
121 bool wxTopLevelWindow::ShowFullScreen(bool show
, long style
)
123 if ( show
== IsFullScreen() ) return FALSE
;
125 if ( ms_drawDecorations
)
129 m_fsSavedStyle
= m_windowStyle
;
130 if ( style
& wxFULLSCREEN_NOBORDER
)
131 m_windowStyle
|= wxSIMPLE_BORDER
;
132 if ( style
& wxFULLSCREEN_NOCAPTION
)
133 m_windowStyle
&= ~wxCAPTION
;
137 m_windowStyle
= m_fsSavedStyle
;
141 return wxTopLevelWindowNative::ShowFullScreen(show
, style
);
144 long wxTopLevelWindow::GetDecorationsStyle() const
148 if ( m_windowStyle
& wxCAPTION
)
150 style
|= wxTOPLEVEL_TITLEBAR
| wxTOPLEVEL_BUTTON_CLOSE
;
151 if ( (m_windowStyle
& wxMINIMIZE_BOX
) && ms_canIconize
)
152 style
|= wxTOPLEVEL_BUTTON_ICONIZE
;
153 if ( m_windowStyle
& wxMAXIMIZE_BOX
)
156 style
|= wxTOPLEVEL_BUTTON_RESTORE
;
158 style
|= wxTOPLEVEL_BUTTON_MAXIMIZE
;
161 if ( m_exStyle
& (wxFRAME_EX_CONTEXTHELP
| wxDIALOG_EX_CONTEXTHELP
))
162 style
|= wxTOPLEVEL_BUTTON_HELP
;
165 if ( (m_windowStyle
& (wxSIMPLE_BORDER
| wxNO_BORDER
)) == 0 )
166 style
|= wxTOPLEVEL_BORDER
;
167 if ( m_windowStyle
& (wxRESIZE_BORDER
| wxTHICK_FRAME
) )
168 style
|= wxTOPLEVEL_RESIZEABLE
;
171 style
|= wxTOPLEVEL_MAXIMIZED
;
172 if ( GetIcon().Ok() )
173 style
|= wxTOPLEVEL_ICON
;
175 style
|= wxTOPLEVEL_ACTIVE
;
180 void wxTopLevelWindow::RefreshTitleBar()
182 wxNcPaintEvent
event(GetId());
183 event
.SetEventObject(this);
184 GetEventHandler()->ProcessEvent(event
);
187 // ----------------------------------------------------------------------------
188 // client area handling
189 // ----------------------------------------------------------------------------
191 wxPoint
wxTopLevelWindow::GetClientAreaOrigin() const
193 if ( ms_drawDecorations
)
196 wxTopLevelWindowNative::DoGetClientSize(&w
, &h
);
197 wxRect rect
= wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
199 rect
= m_renderer
->GetFrameClientArea(rect
,
200 GetDecorationsStyle());
201 return rect
.GetPosition();
205 return wxTopLevelWindowNative::GetClientAreaOrigin();
209 void wxTopLevelWindow::DoGetClientSize(int *width
, int *height
) const
211 if ( ms_drawDecorations
)
214 wxTopLevelWindowNative::DoGetClientSize(&w
, &h
);
215 wxRect rect
= wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
217 rect
= m_renderer
->GetFrameClientArea(rect
,
218 GetDecorationsStyle());
222 *height
= rect
.height
;
225 wxTopLevelWindowNative::DoGetClientSize(width
, height
);
228 void wxTopLevelWindow::DoSetClientSize(int width
, int height
)
230 if ( ms_drawDecorations
)
232 wxSize size
= m_renderer
->GetFrameTotalSize(wxSize(width
, height
),
233 GetDecorationsStyle());
234 wxTopLevelWindowNative::DoSetClientSize(size
.x
, size
.y
);
237 wxTopLevelWindowNative::DoSetClientSize(width
, height
);
240 void wxTopLevelWindow::OnNcPaint(wxPaintEvent
& event
)
242 if ( !ms_drawDecorations
|| !m_renderer
)
246 // get the window rect
248 wxSize size
= GetSize();
252 rect
.height
= size
.y
;
255 m_renderer
->DrawFrameTitleBar(dc
, rect
,
256 GetTitle(), m_titlebarIcon
,
257 GetDecorationsStyle(),
263 long wxTopLevelWindow::HitTest(const wxPoint
& pt
) const
266 wxTopLevelWindowNative::DoGetClientSize(&w
, &h
);
267 wxRect
rect(wxTopLevelWindowNative::GetClientAreaOrigin(), wxSize(w
, h
));
269 return m_renderer
->HitTestFrame(rect
, pt
+GetClientAreaOrigin(), GetDecorationsStyle());
272 int wxTopLevelWindow::GetMinWidth() const
274 if ( ms_drawDecorations
)
276 return wxMax(wxTopLevelWindowNative::GetMinWidth(),
277 m_renderer
->GetFrameMinSize(GetDecorationsStyle()).x
);
280 return wxTopLevelWindowNative::GetMinWidth();
283 int wxTopLevelWindow::GetMinHeight() const
285 if ( ms_drawDecorations
)
287 return wxMax(wxTopLevelWindowNative::GetMinHeight(),
288 m_renderer
->GetFrameMinSize(GetDecorationsStyle()).y
);
291 return wxTopLevelWindowNative::GetMinHeight();
294 // ----------------------------------------------------------------------------
296 // ----------------------------------------------------------------------------
298 void wxTopLevelWindow::SetIcon(const wxIcon
& icon
)
300 wxTopLevelWindowNative::SetIcon(icon
);
302 if ( ms_drawDecorations
&& m_renderer
)
304 wxSize size
= m_renderer
->GetFrameIconSize();
306 if ( !icon
.Ok() || size
.x
== -1 )
307 m_titlebarIcon
= icon
;
311 bmp1
.CopyFromIcon(icon
);
313 m_titlebarIcon
= wxNullIcon
;
314 else if ( bmp1
.GetWidth() == size
.x
&& bmp1
.GetHeight() == size
.y
)
315 m_titlebarIcon
= icon
;
318 wxImage img
= bmp1
.ConvertToImage();
319 img
.Rescale(size
.x
, size
.y
);
320 m_titlebarIcon
.CopyFromBitmap(wxBitmap(img
));
326 // ----------------------------------------------------------------------------
327 // interactive manipulation
328 // ----------------------------------------------------------------------------
330 #define wxINTERACTIVE_RESIZE_DIR \
331 (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E | \
332 wxINTERACTIVE_RESIZE_S | wxINTERACTIVE_RESIZE_N)
334 struct wxInteractiveMoveData
336 wxTopLevelWindowBase
*m_window
;
337 wxEventLoop
*m_evtLoop
;
342 wxSize m_minSize
, m_maxSize
;
345 class wxInteractiveMoveHandler
: public wxEvtHandler
348 wxInteractiveMoveHandler(wxInteractiveMoveData
& data
) : m_data(data
) {}
351 DECLARE_EVENT_TABLE()
352 void OnMouseMove(wxMouseEvent
& event
);
353 void OnMouseDown(wxMouseEvent
& event
);
354 void OnMouseUp(wxMouseEvent
& event
);
355 void OnKeyDown(wxKeyEvent
& event
);
357 wxInteractiveMoveData
& m_data
;
360 BEGIN_EVENT_TABLE(wxInteractiveMoveHandler
, wxEvtHandler
)
361 EVT_MOTION(wxInteractiveMoveHandler::OnMouseMove
)
362 EVT_LEFT_DOWN(wxInteractiveMoveHandler::OnMouseDown
)
363 EVT_LEFT_UP(wxInteractiveMoveHandler::OnMouseUp
)
364 EVT_KEY_DOWN(wxInteractiveMoveHandler::OnKeyDown
)
368 static inline LINKAGEMODE
369 void wxApplyResize(wxInteractiveMoveData
& data
, const wxPoint
& diff
)
371 if ( data
.m_flags
& wxINTERACTIVE_RESIZE_W
)
373 data
.m_rect
.x
+= diff
.x
;
374 data
.m_rect
.width
-= diff
.x
;
376 else if ( data
.m_flags
& wxINTERACTIVE_RESIZE_E
)
378 data
.m_rect
.width
+= diff
.x
;
380 if ( data
.m_flags
& wxINTERACTIVE_RESIZE_N
)
382 data
.m_rect
.y
+= diff
.y
;
383 data
.m_rect
.height
-= diff
.y
;
385 else if ( data
.m_flags
& wxINTERACTIVE_RESIZE_S
)
387 data
.m_rect
.height
+= diff
.y
;
390 if ( data
.m_minSize
.x
!= -1 && data
.m_rect
.width
< data
.m_minSize
.x
)
392 if ( data
.m_flags
& wxINTERACTIVE_RESIZE_W
)
393 data
.m_rect
.x
-= data
.m_minSize
.x
- data
.m_rect
.width
;
394 data
.m_rect
.width
= data
.m_minSize
.x
;
396 if ( data
.m_maxSize
.x
!= -1 && data
.m_rect
.width
> data
.m_maxSize
.x
)
398 if ( data
.m_flags
& wxINTERACTIVE_RESIZE_W
)
399 data
.m_rect
.x
-= data
.m_minSize
.x
- data
.m_rect
.width
;
400 data
.m_rect
.width
= data
.m_maxSize
.x
;
402 if ( data
.m_minSize
.y
!= -1 && data
.m_rect
.height
< data
.m_minSize
.y
)
404 if ( data
.m_flags
& wxINTERACTIVE_RESIZE_N
)
405 data
.m_rect
.y
-= data
.m_minSize
.y
- data
.m_rect
.height
;
406 data
.m_rect
.height
= data
.m_minSize
.y
;
408 if ( data
.m_maxSize
.y
!= -1 && data
.m_rect
.height
> data
.m_maxSize
.y
)
410 if ( data
.m_flags
& wxINTERACTIVE_RESIZE_N
)
411 data
.m_rect
.y
-= data
.m_minSize
.y
- data
.m_rect
.height
;
412 data
.m_rect
.height
= data
.m_maxSize
.y
;
416 void wxInteractiveMoveHandler::OnMouseMove(wxMouseEvent
& event
)
418 if ( m_data
.m_flags
& wxINTERACTIVE_WAIT_FOR_INPUT
)
421 else if ( m_data
.m_flags
& wxINTERACTIVE_MOVE
)
423 wxPoint diff
= wxGetMousePosition() - m_data
.m_pos
;
424 m_data
.m_rect
= m_data
.m_rectOrig
;
425 m_data
.m_rect
.Offset(diff
);
426 m_data
.m_window
->Move(m_data
.m_rect
.GetPosition());
429 else if ( m_data
.m_flags
& wxINTERACTIVE_RESIZE
)
431 wxPoint diff
= wxGetMousePosition() - m_data
.m_pos
;
432 m_data
.m_rect
= m_data
.m_rectOrig
;
433 wxApplyResize(m_data
, diff
);
434 m_data
.m_window
->SetSize(m_data
.m_rect
);
438 void wxInteractiveMoveHandler::OnMouseDown(wxMouseEvent
& event
)
440 if ( m_data
.m_flags
& wxINTERACTIVE_WAIT_FOR_INPUT
)
442 m_data
.m_flags
&= ~wxINTERACTIVE_WAIT_FOR_INPUT
;
443 m_data
.m_pos
= wxGetMousePosition();
447 void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent
& event
)
449 if ( m_data
.m_flags
& wxINTERACTIVE_WAIT_FOR_INPUT
)
451 m_data
.m_flags
&= ~wxINTERACTIVE_WAIT_FOR_INPUT
;
452 m_data
.m_pos
= wxGetMousePosition();
457 switch ( event
.GetKeyCode() )
459 case WXK_UP
: diff
= wxPoint(0, -16); break;
460 case WXK_DOWN
: diff
= wxPoint(0, 16); break;
461 case WXK_LEFT
: diff
= wxPoint(-16, 0); break;
462 case WXK_RIGHT
: diff
= wxPoint(16, 0); break;
464 m_data
.m_window
->SetSize(m_data
.m_rectOrig
);
465 m_data
.m_evtLoop
->Exit();
468 m_data
.m_evtLoop
->Exit();
474 if ( m_data
.m_flags
& wxINTERACTIVE_MOVE
)
476 m_data
.m_rect
.Offset(diff
);
477 m_data
.m_window
->Move(m_data
.m_rect
.GetPosition());
479 else /* wxINTERACTIVE_RESIZE */
481 if ( !(m_data
.m_flags
& wxINTERACTIVE_RESIZE_DIR
) )
484 m_data
.m_flags
|= wxINTERACTIVE_RESIZE_N
;
485 else if ( diff
.y
> 0 )
486 m_data
.m_flags
|= wxINTERACTIVE_RESIZE_S
;
488 m_data
.m_flags
|= wxINTERACTIVE_RESIZE_W
;
489 else if ( diff
.x
> 0 )
490 m_data
.m_flags
|= wxINTERACTIVE_RESIZE_E
;
493 wxApplyResize(m_data
, diff
);
494 m_data
.m_window
->SetSize(m_data
.m_rect
);
499 void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent
& event
)
501 m_data
.m_evtLoop
->Exit();
505 void wxTopLevelWindow::InteractiveMove(int flags
)
507 wxASSERT_MSG( !((flags
& wxINTERACTIVE_MOVE
) && (flags
& wxINTERACTIVE_RESIZE
)),
508 wxT("can't move and resize window at the same time") );
510 wxASSERT_MSG( !(flags
& wxINTERACTIVE_RESIZE
) ||
511 (flags
& wxINTERACTIVE_WAIT_FOR_INPUT
) ||
512 (flags
& wxINTERACTIVE_RESIZE_DIR
),
513 wxT("direction of resizing not specified") );
515 wxInteractiveMoveData data
;
517 wxWindow
*focus
= FindFocus();
519 // FIXME - display resize cursor if waiting for initial input
521 data
.m_window
= this;
522 data
.m_evtLoop
= &loop
;
523 data
.m_flags
= flags
;
524 data
.m_rect
= data
.m_rectOrig
= GetRect();
525 data
.m_pos
= wxGetMousePosition();
526 data
.m_minSize
= wxSize(GetMinWidth(), GetMinHeight());
527 data
.m_maxSize
= wxSize(GetMaxWidth(), GetMaxHeight());
529 this->PushEventHandler(new wxInteractiveMoveHandler(data
));
531 focus
->PushEventHandler(new wxInteractiveMoveHandler(data
));
537 this->PopEventHandler(TRUE
/*delete*/);
539 focus
->PopEventHandler(TRUE
/*delete*/);
542 // ----------------------------------------------------------------------------
544 // ----------------------------------------------------------------------------
546 void wxTopLevelWindow::ClickTitleBarButton(long button
)
550 case wxTOPLEVEL_BUTTON_CLOSE
:
554 case wxTOPLEVEL_BUTTON_ICONIZE
:
558 case wxTOPLEVEL_BUTTON_MAXIMIZE
:
562 case wxTOPLEVEL_BUTTON_RESTORE
:
566 case wxTOPLEVEL_BUTTON_HELP
:
569 wxContextHelp
contextHelp(this);
575 wxFAIL_MSG(wxT("incorrect button specification"));
579 bool wxTopLevelWindow::PerformAction(const wxControlAction
& action
,
581 const wxString
& strArg
)
583 bool isActive
= numArg
!= 0;
585 if ( action
== wxACTION_TOPLEVEL_ACTIVATE
)
587 if ( m_isActive
!= isActive
)
589 m_isActive
= isActive
;
595 else if ( action
== wxACTION_TOPLEVEL_BUTTON_PRESS
)
597 m_pressedButton
= numArg
;
602 else if ( action
== wxACTION_TOPLEVEL_BUTTON_RELEASE
)
609 else if ( action
== wxACTION_TOPLEVEL_BUTTON_CLICK
)
613 ClickTitleBarButton(numArg
);
617 else if ( action
== wxACTION_TOPLEVEL_MOVE
)
619 InteractiveMove(wxINTERACTIVE_MOVE
);
623 else if ( action
== wxACTION_TOPLEVEL_RESIZE
)
625 int flags
= wxINTERACTIVE_RESIZE
;
626 if ( numArg
& wxHT_TOPLEVEL_BORDER_N
)
627 flags
|= wxINTERACTIVE_RESIZE_N
;
628 if ( numArg
& wxHT_TOPLEVEL_BORDER_S
)
629 flags
|= wxINTERACTIVE_RESIZE_S
;
630 if ( numArg
& wxHT_TOPLEVEL_BORDER_W
)
631 flags
|= wxINTERACTIVE_RESIZE_W
;
632 if ( numArg
& wxHT_TOPLEVEL_BORDER_E
)
633 flags
|= wxINTERACTIVE_RESIZE_E
;
634 InteractiveMove(flags
);
643 // ============================================================================
644 // wxStdFrameInputHandler: handles focus, resizing and titlebar buttons clicks
645 // ============================================================================
647 wxStdFrameInputHandler::wxStdFrameInputHandler(wxInputHandler
*inphand
)
648 : wxStdInputHandler(inphand
)
653 m_borderCursorOn
= FALSE
;
656 bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer
*consumer
,
657 const wxMouseEvent
& event
)
659 // the button has 2 states: pressed and normal with the following
660 // transitions between them:
662 // normal -> left down -> capture mouse and go to pressed state
663 // pressed -> left up inside -> generate click -> go to normal
664 // outside ------------------>
666 // the other mouse buttons are ignored
667 if ( event
.Button(1) )
669 if ( event
.ButtonDown(1) )
671 wxTopLevelWindow
*w
= wxStaticCast(consumer
->GetInputWindow(), wxTopLevelWindow
);
672 long hit
= w
->HitTest(event
.GetPosition());
674 if ( hit
& wxHT_TOPLEVEL_ANY_BUTTON
)
677 m_winCapture
->CaptureMouse();
680 consumer
->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS
, m_winPressed
);
683 else if ( (hit
& wxHT_TOPLEVEL_TITLEBAR
) && !w
->IsMaximized() )
685 consumer
->PerformAction(wxACTION_TOPLEVEL_MOVE
);
688 else if ( (consumer
->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER
)
689 && (hit
& wxHT_TOPLEVEL_ANY_BORDER
) )
691 consumer
->PerformAction(wxACTION_TOPLEVEL_RESIZE
, hit
);
700 m_winCapture
->ReleaseMouse();
703 if ( m_winHitTest
== m_winPressed
)
705 consumer
->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK
, m_winPressed
);
709 //else: the mouse was released outside the window, this doesn't
714 return wxStdInputHandler::HandleMouse(consumer
, event
);
717 bool wxStdFrameInputHandler::HandleMouseMove(wxInputConsumer
*consumer
,
718 const wxMouseEvent
& event
)
720 if ( event
.GetEventObject() == m_winCapture
)
722 long hit
= m_winCapture
->HitTest(event
.GetPosition());
724 if ( hit
!= m_winHitTest
)
726 if ( hit
!= m_winPressed
)
727 consumer
->PerformAction(wxACTION_TOPLEVEL_BUTTON_RELEASE
, m_winPressed
);
729 consumer
->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS
, m_winPressed
);
735 else if ( consumer
->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER
)
737 wxTopLevelWindow
*win
= wxStaticCast(consumer
->GetInputWindow(),
739 long hit
= win
->HitTest(event
.GetPosition());
741 if ( hit
!= m_winHitTest
)
745 if ( m_borderCursorOn
)
747 m_borderCursorOn
= FALSE
;
748 win
->SetCursor(m_origCursor
);
751 if ( hit
& wxHT_TOPLEVEL_ANY_BORDER
)
753 m_borderCursorOn
= TRUE
;
758 case wxHT_TOPLEVEL_BORDER_N
:
759 case wxHT_TOPLEVEL_BORDER_S
:
760 cur
= wxCursor(wxCURSOR_SIZENS
);
762 case wxHT_TOPLEVEL_BORDER_W
:
763 case wxHT_TOPLEVEL_BORDER_E
:
764 cur
= wxCursor(wxCURSOR_SIZEWE
);
766 case wxHT_TOPLEVEL_BORDER_NE
:
767 case wxHT_TOPLEVEL_BORDER_SW
:
768 cur
= wxCursor(wxCURSOR_SIZENESW
);
770 case wxHT_TOPLEVEL_BORDER_NW
:
771 case wxHT_TOPLEVEL_BORDER_SE
:
772 cur
= wxCursor(wxCURSOR_SIZENWSE
);
775 m_borderCursorOn
= FALSE
;
778 if ( m_borderCursorOn
)
780 m_origCursor
= win
->GetCursor();
787 return wxStdInputHandler::HandleMouseMove(consumer
, event
);
790 bool wxStdFrameInputHandler::HandleActivation(wxInputConsumer
*consumer
,
793 if ( m_borderCursorOn
)
795 consumer
->GetInputWindow()->SetCursor(m_origCursor
);
796 m_borderCursorOn
= FALSE
;
798 consumer
->PerformAction(wxACTION_TOPLEVEL_ACTIVATE
, activated
);