/////////////////////////////////////////////////////////////////////////////
-// Name: topluniv.cpp
+// Name: src/univ/topluniv.cpp
// Author: Vaclav Slavik
// Id: $Id$
-// Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
+// Copyright: (c) 2001-2002 SciTech Software, Inc. (www.scitechsoft.com)
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// headers
// ----------------------------------------------------------------------------
-#ifdef __GNUG__
- #pragma implementation "univtoplevel.h"
-#endif
-
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
-#pragma hdrstop
+ #pragma hdrstop
#endif
-#include "wx/defs.h"
#include "wx/toplevel.h"
+#ifndef WX_PRECOMP
+ #include "wx/dcclient.h"
+ #include "wx/settings.h"
+ #include "wx/bitmap.h"
+ #include "wx/image.h"
+ #include "wx/frame.h"
+#endif
+
+#include "wx/univ/renderer.h"
+#include "wx/cshelp.h"
+#include "wx/evtloop.h"
+
+// ----------------------------------------------------------------------------
+// wxStdTLWInputHandler: handles focus, resizing and titlebar buttons clicks
+// ----------------------------------------------------------------------------
+
+class WXDLLEXPORT wxStdTLWInputHandler : public wxStdInputHandler
+{
+public:
+ wxStdTLWInputHandler(wxInputHandler *inphand);
+
+ virtual bool HandleMouse(wxInputConsumer *consumer,
+ const wxMouseEvent& event);
+ virtual bool HandleMouseMove(wxInputConsumer *consumer, const wxMouseEvent& event);
+ virtual bool HandleActivation(wxInputConsumer *consumer, bool activated);
+
+private:
+ // the window (button) which has capture or NULL and the last hittest result
+ wxTopLevelWindow *m_winCapture;
+ long m_winHitTest;
+ long m_winPressed;
+ bool m_borderCursorOn;
+ wxCursor m_origCursor;
+};
+
// ----------------------------------------------------------------------------
// event tables
// ----------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxTopLevelWindow, wxWindow)
+BEGIN_EVENT_TABLE(wxTopLevelWindow, wxTopLevelWindowNative)
+ WX_EVENT_TABLE_INPUT_CONSUMER(wxTopLevelWindow)
+ EVT_NC_PAINT(wxTopLevelWindow::OnNcPaint)
+ EVT_MENU_RANGE(wxID_CLOSE_FRAME, wxID_RESTORE_FRAME, wxTopLevelWindow::OnSystemMenu)
+END_EVENT_TABLE()
+WX_FORWARD_TO_INPUT_CONSUMER(wxTopLevelWindow)
// ============================================================================
// implementation
// ============================================================================
+int wxTopLevelWindow::ms_drawDecorations = -1;
+int wxTopLevelWindow::ms_canIconize = -1;
+
void wxTopLevelWindow::Init()
{
+ // once-only ms_drawDecorations initialization
+ if ( ms_drawDecorations == -1 )
+ {
+ ms_drawDecorations =
+ !wxSystemSettings::HasFeature(wxSYS_CAN_DRAW_FRAME_DECORATIONS) ||
+ wxGetEnv(wxT("WXDECOR"), NULL);
+ }
+
+ m_usingNativeDecorations = ms_drawDecorations == 0;
+ m_isActive = false;
+ m_windowStyle = 0;
+ m_pressedButton = 0;
}
bool wxTopLevelWindow::Create(wxWindow *parent,
wxWindowID id,
const wxString& title,
const wxPoint& pos,
- const wxSize& sizeOrig,
+ const wxSize& size,
long style,
const wxString &name)
{
- if ( !wxTopLevelWindowNative::Create(parent, id, title, pos,
- sizeOrig, style, name) )
- return FALSE;
-
- // FIXME_MGL -- this is temporary; we assume for now that native TLW
- // can do decorations, which is not true for MGL
+ // init them to avoid compiler warnings
+ long styleOrig = 0,
+ exstyleOrig = 0;
+
+ if ( !m_usingNativeDecorations )
+ {
+ CreateInputHandler(wxINP_HANDLER_TOPLEVEL);
+
+ styleOrig = style;
+ exstyleOrig = GetExtraStyle();
+ style &= ~(wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX |
+ wxSYSTEM_MENU | wxRESIZE_BORDER | wxFRAME_TOOL_WINDOW |
+ wxRESIZE_BORDER);
+ style |= wxBORDER_NONE;
+ SetExtraStyle(exstyleOrig & ~wxWS_EX_CONTEXTHELP);
+ }
+
+ if ( !wxTopLevelWindowNative::Create(parent, id, title, pos,
+ size, style, name) )
+ return false;
+
+ if ( !m_usingNativeDecorations )
+ {
+ m_windowStyle = styleOrig;
+ m_exStyle = exstyleOrig;
+ }
- return TRUE;
+ return true;
}
bool wxTopLevelWindow::ShowFullScreen(bool show, long style)
{
- if ( show == IsFullScreen() ) return FALSE;
-
+ if ( show == IsFullScreen() ) return false;
+
+ if ( !m_usingNativeDecorations )
+ {
+ if ( show )
+ {
+ m_fsSavedStyle = m_windowStyle;
+ if ( style & wxFULLSCREEN_NOBORDER )
+ m_windowStyle |= wxSIMPLE_BORDER;
+ if ( style & wxFULLSCREEN_NOCAPTION )
+ m_windowStyle &= ~wxCAPTION;
+ }
+ else
+ {
+ m_windowStyle = m_fsSavedStyle;
+ }
+ }
+
return wxTopLevelWindowNative::ShowFullScreen(show, style);
-
- // FIXME_MGL -- must handle caption hiding here if not in
- // native decorations mode
}
+/* static */
+void wxTopLevelWindow::UseNativeDecorationsByDefault(bool native)
+{
+ ms_drawDecorations = !native;
+}
+
+void wxTopLevelWindow::UseNativeDecorations(bool native)
+{
+ wxASSERT_MSG( !m_windowStyle, wxT("must be called before Create()") );
+
+ m_usingNativeDecorations = native;
+}
+
+bool wxTopLevelWindow::IsUsingNativeDecorations() const
+{
+ return m_usingNativeDecorations;
+}
+
+long wxTopLevelWindow::GetDecorationsStyle() const
+{
+ long style = 0;
+
+ if ( m_windowStyle & wxCAPTION )
+ {
+ if ( ms_canIconize == -1 )
+ {
+ ms_canIconize = wxSystemSettings::HasFeature(wxSYS_CAN_ICONIZE_FRAME);
+ }
+
+ style |= wxTOPLEVEL_TITLEBAR;
+ if ( m_windowStyle & wxCLOSE_BOX )
+ style |= wxTOPLEVEL_BUTTON_CLOSE;
+ if ( (m_windowStyle & wxMINIMIZE_BOX) && ms_canIconize )
+ style |= wxTOPLEVEL_BUTTON_ICONIZE;
+ if ( m_windowStyle & wxMAXIMIZE_BOX )
+ {
+ if ( IsMaximized() )
+ style |= wxTOPLEVEL_BUTTON_RESTORE;
+ else
+ style |= wxTOPLEVEL_BUTTON_MAXIMIZE;
+ }
+#if wxUSE_HELP
+ if ( m_exStyle & wxWS_EX_CONTEXTHELP)
+ style |= wxTOPLEVEL_BUTTON_HELP;
+#endif
+ }
+ if ( (m_windowStyle & (wxSIMPLE_BORDER | wxNO_BORDER)) == 0 )
+ style |= wxTOPLEVEL_BORDER;
+ if ( m_windowStyle & (wxRESIZE_BORDER | wxRESIZE_BORDER) )
+ style |= wxTOPLEVEL_RESIZEABLE;
+
+ if ( IsMaximized() )
+ style |= wxTOPLEVEL_MAXIMIZED;
+ if ( GetIcon().Ok() )
+ style |= wxTOPLEVEL_ICON;
+ if ( m_isActive )
+ style |= wxTOPLEVEL_ACTIVE;
+
+ return style;
+}
+
+void wxTopLevelWindow::RefreshTitleBar()
+{
+ wxNcPaintEvent event(GetId());
+ event.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(event);
+}
+
+// ----------------------------------------------------------------------------
+// client area handling
+// ----------------------------------------------------------------------------
+
+wxPoint wxTopLevelWindow::GetClientAreaOrigin() const
+{
+ if ( !m_usingNativeDecorations )
+ {
+ int w, h;
+ wxTopLevelWindowNative::DoGetClientSize(&w, &h);
+ wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
+ wxSize(w, h));
+ rect = m_renderer->GetFrameClientArea(rect,
+ GetDecorationsStyle());
+ return rect.GetPosition();
+ }
+ else
+ {
+ return wxTopLevelWindowNative::GetClientAreaOrigin();
+ }
+}
+
+void wxTopLevelWindow::DoGetClientSize(int *width, int *height) const
+{
+ if ( !m_usingNativeDecorations )
+ {
+ int w, h;
+ wxTopLevelWindowNative::DoGetClientSize(&w, &h);
+ wxRect rect = wxRect(wxTopLevelWindowNative::GetClientAreaOrigin(),
+ wxSize(w, h));
+ rect = m_renderer->GetFrameClientArea(rect,
+ GetDecorationsStyle());
+ if ( width )
+ *width = rect.width;
+ if ( height )
+ *height = rect.height;
+ }
+ else
+ wxTopLevelWindowNative::DoGetClientSize(width, height);
+}
+
+void wxTopLevelWindow::DoSetClientSize(int width, int height)
+{
+ if ( !m_usingNativeDecorations )
+ {
+ wxSize size = m_renderer->GetFrameTotalSize(wxSize(width, height),
+ GetDecorationsStyle());
+ wxTopLevelWindowNative::DoSetClientSize(size.x, size.y);
+ }
+ else
+ wxTopLevelWindowNative::DoSetClientSize(width, height);
+}
+
+void wxTopLevelWindow::OnNcPaint(wxNcPaintEvent& event)
+{
+ if ( m_usingNativeDecorations || !m_renderer )
+ {
+ event.Skip();
+ }
+ else // we're drawing the decorations ourselves
+ {
+ // get the window rect
+ wxRect rect(GetSize());
+
+ wxWindowDC dc(this);
+ m_renderer->DrawFrameTitleBar(dc, rect,
+ GetTitle(), m_titlebarIcon,
+ GetDecorationsStyle(),
+ m_pressedButton,
+ wxCONTROL_PRESSED);
+ }
+}
+
+long wxTopLevelWindow::HitTest(const wxPoint& pt) const
+{
+ int w, h;
+ wxTopLevelWindowNative::DoGetClientSize(&w, &h);
+ wxRect rect(wxTopLevelWindowNative::GetClientAreaOrigin(), wxSize(w, h));
+
+ return m_renderer->HitTestFrame(rect, pt+GetClientAreaOrigin(), GetDecorationsStyle());
+}
+
+wxSize wxTopLevelWindow::GetMinSize() const
+{
+ wxSize size = wxTopLevelWindowNative::GetMinSize();
+ if ( !m_usingNativeDecorations )
+ {
+ size.IncTo(m_renderer->GetFrameMinSize(GetDecorationsStyle()));
+ }
+
+ return size;
+}
+
+// ----------------------------------------------------------------------------
+// icons
+// ----------------------------------------------------------------------------
+
+void wxTopLevelWindow::SetIcons(const wxIconBundle& icons)
+{
+ wxTopLevelWindowNative::SetIcons(icons);
+
+ if ( !m_usingNativeDecorations && m_renderer )
+ {
+ wxSize size = m_renderer->GetFrameIconSize();
+ const wxIcon& icon = icons.GetIcon( size );
+
+ if ( !icon.Ok() || size.x == wxDefaultCoord )
+ m_titlebarIcon = icon;
+ else
+ {
+ wxBitmap bmp1;
+ bmp1.CopyFromIcon(icon);
+ if ( !bmp1.Ok() )
+ m_titlebarIcon = wxNullIcon;
+ else if ( bmp1.GetWidth() == size.x && bmp1.GetHeight() == size.y )
+ m_titlebarIcon = icon;
+#if wxUSE_IMAGE
+ else
+ {
+ wxImage img = bmp1.ConvertToImage();
+ img.Rescale(size.x, size.y);
+ m_titlebarIcon.CopyFromBitmap(wxBitmap(img));
+ }
+#endif // wxUSE_IMAGE
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+// interactive manipulation
+// ----------------------------------------------------------------------------
+
+
+static bool wxGetResizingCursor(long hitTestResult, wxCursor& cursor)
+{
+ if ( hitTestResult & wxHT_TOPLEVEL_ANY_BORDER )
+ {
+ switch (hitTestResult)
+ {
+ case wxHT_TOPLEVEL_BORDER_N:
+ case wxHT_TOPLEVEL_BORDER_S:
+ cursor = wxCursor(wxCURSOR_SIZENS);
+ break;
+ case wxHT_TOPLEVEL_BORDER_W:
+ case wxHT_TOPLEVEL_BORDER_E:
+ cursor = wxCursor(wxCURSOR_SIZEWE);
+ break;
+ case wxHT_TOPLEVEL_BORDER_NE:
+ case wxHT_TOPLEVEL_BORDER_SW:
+ cursor = wxCursor(wxCURSOR_SIZENESW);
+ break;
+ case wxHT_TOPLEVEL_BORDER_NW:
+ case wxHT_TOPLEVEL_BORDER_SE:
+ cursor = wxCursor(wxCURSOR_SIZENWSE);
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+#define wxINTERACTIVE_RESIZE_DIR \
+ (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E | \
+ wxINTERACTIVE_RESIZE_S | wxINTERACTIVE_RESIZE_N)
+
+struct wxInteractiveMoveData
+{
+ wxTopLevelWindow *m_window;
+ wxEventLoop *m_evtLoop;
+ int m_flags;
+ wxRect m_rect;
+ wxRect m_rectOrig;
+ wxPoint m_pos;
+ wxSize m_minSize, m_maxSize;
+ bool m_sizingCursor;
+};
+
+class wxInteractiveMoveHandler : public wxEvtHandler
+{
+public:
+ wxInteractiveMoveHandler(wxInteractiveMoveData& data) : m_data(data) {}
+
+private:
+ DECLARE_EVENT_TABLE()
+ void OnMouseMove(wxMouseEvent& event);
+ void OnMouseDown(wxMouseEvent& event);
+ void OnMouseUp(wxMouseEvent& event);
+ void OnKeyDown(wxKeyEvent& event);
+
+ wxInteractiveMoveData& m_data;
+};
+
+BEGIN_EVENT_TABLE(wxInteractiveMoveHandler, wxEvtHandler)
+ EVT_MOTION(wxInteractiveMoveHandler::OnMouseMove)
+ EVT_LEFT_DOWN(wxInteractiveMoveHandler::OnMouseDown)
+ EVT_LEFT_UP(wxInteractiveMoveHandler::OnMouseUp)
+ EVT_KEY_DOWN(wxInteractiveMoveHandler::OnKeyDown)
+END_EVENT_TABLE()
+
+
+static inline LINKAGEMODE
+void wxApplyResize(wxInteractiveMoveData& data, const wxPoint& diff)
+{
+ if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
+ {
+ data.m_rect.x += diff.x;
+ data.m_rect.width -= diff.x;
+ }
+ else if ( data.m_flags & wxINTERACTIVE_RESIZE_E )
+ {
+ data.m_rect.width += diff.x;
+ }
+ if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
+ {
+ data.m_rect.y += diff.y;
+ data.m_rect.height -= diff.y;
+ }
+ else if ( data.m_flags & wxINTERACTIVE_RESIZE_S )
+ {
+ data.m_rect.height += diff.y;
+ }
+
+ if ( data.m_minSize.x != wxDefaultCoord && data.m_rect.width < data.m_minSize.x )
+ {
+ if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
+ data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
+ data.m_rect.width = data.m_minSize.x;
+ }
+ if ( data.m_maxSize.x != wxDefaultCoord && data.m_rect.width > data.m_maxSize.x )
+ {
+ if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
+ data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
+ data.m_rect.width = data.m_maxSize.x;
+ }
+ if ( data.m_minSize.y != wxDefaultCoord && data.m_rect.height < data.m_minSize.y )
+ {
+ if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
+ data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
+ data.m_rect.height = data.m_minSize.y;
+ }
+ if ( data.m_maxSize.y != wxDefaultCoord && data.m_rect.height > data.m_maxSize.y )
+ {
+ if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
+ data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
+ data.m_rect.height = data.m_maxSize.y;
+ }
+}
+
+void wxInteractiveMoveHandler::OnMouseMove(wxMouseEvent& event)
+{
+ if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
+ event.Skip();
+
+ else if ( m_data.m_flags & wxINTERACTIVE_MOVE )
+ {
+ wxPoint diff = wxGetMousePosition() - m_data.m_pos;
+ m_data.m_rect = m_data.m_rectOrig;
+ m_data.m_rect.Offset(diff);
+ m_data.m_window->Move(m_data.m_rect.GetPosition());
+ }
+
+ else if ( m_data.m_flags & wxINTERACTIVE_RESIZE )
+ {
+ wxPoint diff = wxGetMousePosition() - m_data.m_pos;
+ m_data.m_rect = m_data.m_rectOrig;
+ wxApplyResize(m_data, diff);
+ m_data.m_window->SetSize(m_data.m_rect);
+ }
+}
+
+void wxInteractiveMoveHandler::OnMouseDown(wxMouseEvent& WXUNUSED(event))
+{
+ if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
+ {
+ m_data.m_evtLoop->Exit();
+ }
+}
+
+void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent& event)
+{
+ wxPoint diff(wxDefaultCoord,wxDefaultCoord);
+
+ switch ( event.GetKeyCode() )
+ {
+ case WXK_UP: diff = wxPoint(0, -16); break;
+ case WXK_DOWN: diff = wxPoint(0, 16); break;
+ case WXK_LEFT: diff = wxPoint(-16, 0); break;
+ case WXK_RIGHT: diff = wxPoint(16, 0); break;
+ case WXK_ESCAPE:
+ m_data.m_window->SetSize(m_data.m_rectOrig);
+ m_data.m_evtLoop->Exit();
+ return;
+ case WXK_RETURN:
+ m_data.m_evtLoop->Exit();
+ return;
+ }
+
+ if ( diff.x != wxDefaultCoord )
+ {
+ if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
+ {
+ m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
+ if ( m_data.m_sizingCursor )
+ {
+ wxEndBusyCursor();
+ m_data.m_sizingCursor = false;
+ }
+
+ if ( m_data.m_flags & wxINTERACTIVE_MOVE )
+ {
+ m_data.m_pos = m_data.m_window->GetPosition() +
+ wxPoint(m_data.m_window->GetSize().x/2, 8);
+ }
+ }
+
+ wxPoint warp;
+ bool changeCur = false;
+
+ if ( m_data.m_flags & wxINTERACTIVE_MOVE )
+ {
+ m_data.m_rect.Offset(diff);
+ m_data.m_window->Move(m_data.m_rect.GetPosition());
+ warp = wxPoint(m_data.m_window->GetSize().x/2, 8);
+ }
+ else /* wxINTERACTIVE_RESIZE */
+ {
+ if ( !(m_data.m_flags &
+ (wxINTERACTIVE_RESIZE_N | wxINTERACTIVE_RESIZE_S)) )
+ {
+ if ( diff.y < 0 )
+ {
+ m_data.m_flags |= wxINTERACTIVE_RESIZE_N;
+ m_data.m_pos.y = m_data.m_window->GetPosition().y;
+ changeCur = true;
+ }
+ else if ( diff.y > 0 )
+ {
+ m_data.m_flags |= wxINTERACTIVE_RESIZE_S;
+ m_data.m_pos.y = m_data.m_window->GetPosition().y +
+ m_data.m_window->GetSize().y;
+ changeCur = true;
+ }
+ }
+ if ( !(m_data.m_flags &
+ (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E)) )
+ {
+ if ( diff.x < 0 )
+ {
+ m_data.m_flags |= wxINTERACTIVE_RESIZE_W;
+ m_data.m_pos.x = m_data.m_window->GetPosition().x;
+ changeCur = true;
+ }
+ else if ( diff.x > 0 )
+ {
+ m_data.m_flags |= wxINTERACTIVE_RESIZE_E;
+ m_data.m_pos.x = m_data.m_window->GetPosition().x +
+ m_data.m_window->GetSize().x;
+ changeCur = true;
+ }
+ }
+
+ wxApplyResize(m_data, diff);
+ m_data.m_window->SetSize(m_data.m_rect);
+
+ if ( m_data.m_flags & wxINTERACTIVE_RESIZE_W )
+ warp.x = 0;
+ else if ( m_data.m_flags & wxINTERACTIVE_RESIZE_E )
+ warp.x = m_data.m_window->GetSize().x-1;
+ else
+ warp.x = wxGetMousePosition().x - m_data.m_window->GetPosition().x;
+
+ if ( m_data.m_flags & wxINTERACTIVE_RESIZE_N )
+ warp.y = 0;
+ else if ( m_data.m_flags & wxINTERACTIVE_RESIZE_S )
+ warp.y = m_data.m_window->GetSize().y-1;
+ else
+ warp.y = wxGetMousePosition().y - m_data.m_window->GetPosition().y;
+ }
+
+ warp -= m_data.m_window->GetClientAreaOrigin();
+ m_data.m_window->WarpPointer(warp.x, warp.y);
+
+ if ( changeCur )
+ {
+ long hit = m_data.m_window->HitTest(warp);
+ wxCursor cur;
+ if ( wxGetResizingCursor(hit, cur) )
+ {
+ if ( m_data.m_sizingCursor )
+ wxEndBusyCursor();
+ wxBeginBusyCursor(&cur);
+ m_data.m_sizingCursor = true;
+ }
+ }
+ }
+}
+
+void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent& WXUNUSED(event))
+{
+ m_data.m_evtLoop->Exit();
+}
+
+
+void wxTopLevelWindow::InteractiveMove(int flags)
+{
+ wxASSERT_MSG( !((flags & wxINTERACTIVE_MOVE) && (flags & wxINTERACTIVE_RESIZE)),
+ wxT("can't move and resize window at the same time") );
+
+ wxASSERT_MSG( !(flags & wxINTERACTIVE_RESIZE) ||
+ (flags & wxINTERACTIVE_WAIT_FOR_INPUT) ||
+ (flags & wxINTERACTIVE_RESIZE_DIR),
+ wxT("direction of resizing not specified") );
+
+ wxInteractiveMoveData data;
+ wxEventLoop loop;
+
+ SetFocus();
+
+#ifndef __WXGTK__
+ if ( flags & wxINTERACTIVE_WAIT_FOR_INPUT )
+ {
+ wxCursor sizingCursor(wxCURSOR_SIZING);
+ wxBeginBusyCursor(&sizingCursor);
+ data.m_sizingCursor = true;
+ }
+ else
+#endif
+ data.m_sizingCursor = false;
+
+ data.m_window = this;
+ data.m_evtLoop = &loop;
+ data.m_flags = flags;
+ data.m_rect = data.m_rectOrig = GetRect();
+ data.m_pos = wxGetMousePosition();
+ data.m_minSize = wxSize(GetMinWidth(), GetMinHeight());
+ data.m_maxSize = wxSize(GetMaxWidth(), GetMaxHeight());
+
+ wxEvtHandler *handler = new wxInteractiveMoveHandler(data);
+ this->PushEventHandler(handler);
+
+ CaptureMouse();
+ loop.Run();
+ ReleaseMouse();
+
+ this->RemoveEventHandler(handler);
+ delete handler;
+
+ if ( data.m_sizingCursor )
+ wxEndBusyCursor();
+}
+
+// ----------------------------------------------------------------------------
+// actions
+// ----------------------------------------------------------------------------
+
+void wxTopLevelWindow::ClickTitleBarButton(long button)
+{
+ switch ( button )
+ {
+ case wxTOPLEVEL_BUTTON_CLOSE:
+ Close();
+ break;
+
+ case wxTOPLEVEL_BUTTON_ICONIZE:
+ Iconize();
+ break;
+
+ case wxTOPLEVEL_BUTTON_MAXIMIZE:
+ Maximize();
+ break;
+
+ case wxTOPLEVEL_BUTTON_RESTORE:
+ Restore();
+ break;
+
+ case wxTOPLEVEL_BUTTON_HELP:
+#if wxUSE_HELP
+ {
+ wxContextHelp contextHelp(this);
+ }
+#endif
+ break;
+
+ default:
+ wxFAIL_MSG(wxT("incorrect button specification"));
+ }
+}
+
+bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
+ long numArg,
+ const wxString& WXUNUSED(strArg))
+{
+ bool isActive = numArg != 0;
+
+ if ( action == wxACTION_TOPLEVEL_ACTIVATE )
+ {
+ if ( m_isActive != isActive )
+ {
+ m_isActive = isActive;
+ RefreshTitleBar();
+ }
+ return true;
+ }
+
+ else if ( action == wxACTION_TOPLEVEL_BUTTON_PRESS )
+ {
+ m_pressedButton = numArg;
+ RefreshTitleBar();
+ return true;
+ }
+
+ else if ( action == wxACTION_TOPLEVEL_BUTTON_RELEASE )
+ {
+ m_pressedButton = 0;
+ RefreshTitleBar();
+ return true;
+ }
+
+ else if ( action == wxACTION_TOPLEVEL_BUTTON_CLICK )
+ {
+ m_pressedButton = 0;
+ RefreshTitleBar();
+ ClickTitleBarButton(numArg);
+ return true;
+ }
+
+ else if ( action == wxACTION_TOPLEVEL_MOVE )
+ {
+ InteractiveMove(wxINTERACTIVE_MOVE);
+ return true;
+ }
+
+ else if ( action == wxACTION_TOPLEVEL_RESIZE )
+ {
+ int flags = wxINTERACTIVE_RESIZE;
+ if ( numArg & wxHT_TOPLEVEL_BORDER_N )
+ flags |= wxINTERACTIVE_RESIZE_N;
+ if ( numArg & wxHT_TOPLEVEL_BORDER_S )
+ flags |= wxINTERACTIVE_RESIZE_S;
+ if ( numArg & wxHT_TOPLEVEL_BORDER_W )
+ flags |= wxINTERACTIVE_RESIZE_W;
+ if ( numArg & wxHT_TOPLEVEL_BORDER_E )
+ flags |= wxINTERACTIVE_RESIZE_E;
+ InteractiveMove(flags);
+ return true;
+ }
+
+ else
+ return false;
+}
+
+void wxTopLevelWindow::OnSystemMenu(wxCommandEvent& event)
+{
+ bool ret = true;
+
+ switch (event.GetId())
+ {
+ case wxID_CLOSE_FRAME:
+ ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
+ wxTOPLEVEL_BUTTON_CLOSE);
+ break;
+ case wxID_MOVE_FRAME:
+ InteractiveMove(wxINTERACTIVE_MOVE | wxINTERACTIVE_WAIT_FOR_INPUT);
+ break;
+ case wxID_RESIZE_FRAME:
+ InteractiveMove(wxINTERACTIVE_RESIZE | wxINTERACTIVE_WAIT_FOR_INPUT);
+ break;
+ case wxID_MAXIMIZE_FRAME:
+ ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
+ wxTOPLEVEL_BUTTON_MAXIMIZE);
+ break;
+ case wxID_ICONIZE_FRAME:
+ ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
+ wxTOPLEVEL_BUTTON_ICONIZE);
+ break;
+ case wxID_RESTORE_FRAME:
+ ret = PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK,
+ wxTOPLEVEL_BUTTON_RESTORE);
+ break;
+
+ default:
+ ret = false;
+ }
+
+ if ( !ret )
+ event.Skip();
+}
+
+/* static */
+wxInputHandler *
+wxTopLevelWindow::GetStdInputHandler(wxInputHandler *handlerDef)
+{
+ static wxStdTLWInputHandler s_handler(handlerDef);
+
+ return &s_handler;
+}
+
+// ============================================================================
+// wxStdTLWInputHandler: handles focus, resizing and titlebar buttons clicks
+// ============================================================================
+
+wxStdTLWInputHandler::wxStdTLWInputHandler(wxInputHandler *inphand)
+ : wxStdInputHandler(inphand)
+{
+ m_winCapture = NULL;
+ m_winHitTest = 0;
+ m_winPressed = 0;
+ m_borderCursorOn = false;
+}
+
+bool wxStdTLWInputHandler::HandleMouse(wxInputConsumer *consumer,
+ const wxMouseEvent& event)
+{
+ // the button has 2 states: pressed and normal with the following
+ // transitions between them:
+ //
+ // normal -> left down -> capture mouse and go to pressed state
+ // pressed -> left up inside -> generate click -> go to normal
+ // outside ------------------>
+ //
+ // the other mouse buttons are ignored
+ if ( event.Button(1) )
+ {
+ if ( event.ButtonDown(1) )
+ {
+ wxTopLevelWindow *w = wxStaticCast(consumer->GetInputWindow(), wxTopLevelWindow);
+ long hit = w->HitTest(event.GetPosition());
+
+ if ( hit & wxHT_TOPLEVEL_ANY_BUTTON )
+ {
+ m_winCapture = w;
+ m_winCapture->CaptureMouse();
+ m_winHitTest = hit;
+ m_winPressed = hit;
+ consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
+ return true;
+ }
+ else if ( (hit & wxHT_TOPLEVEL_TITLEBAR) && !w->IsMaximized() )
+ {
+ consumer->PerformAction(wxACTION_TOPLEVEL_MOVE);
+ return true;
+ }
+ else if ( (consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER)
+ && (hit & wxHT_TOPLEVEL_ANY_BORDER) )
+ {
+ consumer->PerformAction(wxACTION_TOPLEVEL_RESIZE, hit);
+ return true;
+ }
+ }
+
+ else // up
+ {
+ if ( m_winCapture )
+ {
+ m_winCapture->ReleaseMouse();
+ m_winCapture = NULL;
+
+ if ( m_winHitTest == m_winPressed )
+ {
+ consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_CLICK, m_winPressed);
+ return true;
+ }
+ }
+ //else: the mouse was released outside the window, this doesn't
+ // count as a click
+ }
+ }
+
+ return wxStdInputHandler::HandleMouse(consumer, event);
+}
+
+bool wxStdTLWInputHandler::HandleMouseMove(wxInputConsumer *consumer,
+ const wxMouseEvent& event)
+{
+ if ( event.GetEventObject() == m_winCapture )
+ {
+ long hit = m_winCapture->HitTest(event.GetPosition());
+
+ if ( hit != m_winHitTest )
+ {
+ if ( hit != m_winPressed )
+ consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_RELEASE, m_winPressed);
+ else
+ consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
+
+ m_winHitTest = hit;
+ return true;
+ }
+ }
+ else if ( consumer->GetInputWindow()->GetWindowStyle() & wxRESIZE_BORDER )
+ {
+ wxTopLevelWindow *win = wxStaticCast(consumer->GetInputWindow(),
+ wxTopLevelWindow);
+ long hit = win->HitTest(event.GetPosition());
+
+ if ( hit != m_winHitTest )
+ {
+ m_winHitTest = hit;
+
+ if ( m_borderCursorOn )
+ {
+ m_borderCursorOn = false;
+ win->SetCursor(m_origCursor);
+ }
+
+ if ( hit & wxHT_TOPLEVEL_ANY_BORDER )
+ {
+ wxCursor cur;
+
+ m_borderCursorOn = wxGetResizingCursor(hit, cur);
+ if ( m_borderCursorOn )
+ {
+ m_origCursor = win->GetCursor();
+ win->SetCursor(cur);
+ }
+ }
+ }
+ }
+
+ return wxStdInputHandler::HandleMouseMove(consumer, event);
+}
+
+bool wxStdTLWInputHandler::HandleActivation(wxInputConsumer *consumer,
+ bool activated)
+{
+ if ( m_borderCursorOn )
+ {
+ consumer->GetInputWindow()->SetCursor(m_origCursor);
+ m_borderCursorOn = false;
+ }
+ consumer->PerformAction(wxACTION_TOPLEVEL_ACTIVATE, activated);
+ return false;
+}