class WXDLLEXPORT wxTopLevelWindowBase;
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
// Dialogs are created in a special way
#define wxTOPLEVEL_EX_DIALOG 0x00000008
// Styles for ShowFullScreen
// (note that wxTopLevelWindow only handles wxFULLSCREEN_NOBORDER and
// wxFULLSCREEN_NOCAPTION; the rest is handled by wxTopLevelWindow)
-#define wxFULLSCREEN_NOMENUBAR 0x01
-#define wxFULLSCREEN_NOTOOLBAR 0x02
-#define wxFULLSCREEN_NOSTATUSBAR 0x04
-#define wxFULLSCREEN_NOBORDER 0x08
-#define wxFULLSCREEN_NOCAPTION 0x10
-#define wxFULLSCREEN_ALL (wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOTOOLBAR | wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION)
+enum
+{
+ wxFULLSCREEN_NOMENUBAR = 0x0001,
+ wxFULLSCREEN_NOTOOLBAR = 0x0002,
+ wxFULLSCREEN_NOSTATUSBAR = 0x0004,
+ wxFULLSCREEN_NOBORDER = 0x0008,
+ wxFULLSCREEN_NOCAPTION = 0x0010,
+
+ wxFULLSCREEN_ALL = wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOTOOLBAR |
+ wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER |
+ wxFULLSCREEN_NOCAPTION
+};
+
+// Flags for interactive frame manipulation functions (only in wxUniversal):
+enum
+{
+ wxINTERACTIVE_MOVE = 0x00000001,
+ wxINTERACTIVE_RESIZE = 0x00000002,
+ wxINTERACTIVE_RESIZE_S = 0x00000010,
+ wxINTERACTIVE_RESIZE_N = 0x00000020,
+ wxINTERACTIVE_RESIZE_W = 0x00000040,
+ wxINTERACTIVE_RESIZE_E = 0x00000080,
+ wxINTERACTIVE_WAIT_FOR_INPUT = 0x10000000
+};
// ----------------------------------------------------------------------------
// wxTopLevelWindow: a top level (as opposed to child) window
// construction
wxTopLevelWindowBase();
+#ifdef __DARWIN__
+ virtual ~wxTopLevelWindowBase() {}
+#endif
+
// top level wnd state
// --------------------
bool Iconized() const { return IsIconized(); }
#endif // WXWIN_COMPATIBILITY_2
+
+#ifdef __WXUNIVERSAL__
+ // move/resize the frame interactively, i.e. let the user do it
+ virtual void InteractiveMove(int flags = wxINTERACTIVE_MOVE);
+#endif
+
// implementation only from now on
// -------------------------------
// so should be there for all platforms
void OnActivate(wxActivateEvent &WXUNUSED(event)) { }
-#ifdef __DARWIN__
- virtual ~wxTopLevelWindowBase() {}
-#endif
-
protected:
// the frame client to screen translation should take account of the
// toolbar which may shift the origin of the client area
#include "wx/dcclient.h"
#endif // WX_PRECOMP
+#include "wx/evtloop.h"
+
// ----------------------------------------------------------------------------
// event table
// ----------------------------------------------------------------------------
return GetEventHandler()->ProcessEvent(event);
}
+
+// ----------------------------------------------------------------------------
+// interactive manipulation
+// ----------------------------------------------------------------------------
+
+#ifdef __WXUNIVERSAL__
+
+#define wxINTERACTIVE_RESIZE_DIR \
+ (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E | \
+ wxINTERACTIVE_RESIZE_S | wxINTERACTIVE_RESIZE_N)
+
+struct wxInteractiveMoveData
+{
+ wxTopLevelWindowBase *m_window;
+ wxEventLoop *m_evtLoop;
+ int m_flags;
+ wxRect m_rect;
+ wxRect m_rectOrig;
+ wxPoint m_pos;
+ wxSize m_minSize, m_maxSize;
+};
+
+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 != -1 && 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 != -1 && 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 != -1 && 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 != -1 && 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& event)
+{
+ if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
+ {
+ m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
+ m_data.m_pos = wxGetMousePosition();
+ }
+}
+
+void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent& event)
+{
+ if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
+ {
+ m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
+ m_data.m_pos = wxGetMousePosition();
+ }
+
+ wxPoint diff(-1,-1);
+
+ 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 != -1 )
+ {
+ if ( m_data.m_flags & wxINTERACTIVE_MOVE )
+ {
+ m_data.m_rect.Offset(diff);
+ m_data.m_window->Move(m_data.m_rect.GetPosition());
+ }
+ else /* wxINTERACTIVE_RESIZE */
+ {
+ if ( !(m_data.m_flags & wxINTERACTIVE_RESIZE_DIR) )
+ {
+ if ( diff.y < 0 )
+ m_data.m_flags |= wxINTERACTIVE_RESIZE_N;
+ else if ( diff.y > 0 )
+ m_data.m_flags |= wxINTERACTIVE_RESIZE_S;
+ if ( diff.x < 0 )
+ m_data.m_flags |= wxINTERACTIVE_RESIZE_W;
+ else if ( diff.x > 0 )
+ m_data.m_flags |= wxINTERACTIVE_RESIZE_E;
+ }
+
+ wxApplyResize(m_data, diff);
+ m_data.m_window->SetSize(m_data.m_rect);
+ }
+ }
+}
+
+void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent& event)
+{
+ m_data.m_evtLoop->Exit();
+}
+
+
+void wxTopLevelWindowBase::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;
+ wxWindow *focus = FindFocus();
+
+ // FIXME - display resize cursor if waiting for initial input
+
+ 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());
+
+ this->PushEventHandler(new wxInteractiveMoveHandler(data));
+ if ( focus )
+ focus->PushEventHandler(new wxInteractiveMoveHandler(data));
+
+ CaptureMouse();
+ loop.Run();
+ ReleaseMouse();
+
+ this->PopEventHandler(TRUE/*delete*/);
+ if ( focus )
+ focus->PopEventHandler(TRUE/*delete*/);
+}
+
+#endif // __WXUNIVERSAL__
wxASSERT_MSG( !m_windowDisabler, _T("disabling windows twice?") );
+#ifdef __WXGTK__
+ wxBusyCursorSuspender suspender;
+ // FIXME - make sure busy cursor disappears under MSW too
+#endif
+
m_windowDisabler = new wxWindowDisabler(this);
if ( !m_eventLoop )
m_eventLoop = new wxEventLoop;
btnRect.x -= FRAME_BUTTON_WIDTH;
}
- if ( pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
+ if ( pt.y >= client.y && pt.y < client.y + FRAME_TITLEBAR_HEIGHT )
return wxHT_TOPLEVEL_TITLEBAR;
}
{
// we are certainly at one of borders, lets decide which one:
- wxCoord midX = client.x + client.width/2,
- midY = client.y + client.height/2;
int border = 0;
// dirty trick, relies on the way wxHT_TOPLEVEL_XXX are defined!
- if ( pt.x < midX )
+ if ( pt.x < client.x )
border |= wxHT_TOPLEVEL_BORDER_W;
- else
+ else if ( pt.x >= client.width + client.x )
border |= wxHT_TOPLEVEL_BORDER_E;
- if ( pt.y < midY )
+ if ( pt.y < client.y )
border |= wxHT_TOPLEVEL_BORDER_N;
- else
+ else if ( pt.y >= client.height + client.y )
border |= wxHT_TOPLEVEL_BORDER_S;
return border;
}
{
if ( m_isActive != isActive )
{
- Refresh();
m_isActive = isActive;
- wxNcPaintEvent event(GetId());
- event.SetEventObject(this);
- GetEventHandler()->ProcessEvent(event);
+ RefreshTitleBar();
}
return TRUE;
}
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;
}
m_winCapture = NULL;
m_winHitTest = 0;
m_winPressed = 0;
+ m_borderCursorOn = FALSE;
}
bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer *consumer,
consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
return TRUE;
}
+ else if ( hit & wxHT_TOPLEVEL_TITLEBAR )
+ {
+ 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
bool wxStdFrameInputHandler::HandleMouseMove(wxInputConsumer *consumer,
const wxMouseEvent& event)
{
- // we only have to do something when the mouse leaves/enters the pressed
- // button and don't care about the other ones
if ( event.GetEventObject() == m_winCapture )
{
long hit = m_winCapture->HitTest(event.GetPosition());
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 )
+ {
+ m_borderCursorOn = TRUE;
+ wxCursor cur;
+
+ switch (hit)
+ {
+ case wxHT_TOPLEVEL_BORDER_N:
+ case wxHT_TOPLEVEL_BORDER_S:
+ cur = wxCursor(wxCURSOR_SIZENS);
+ break;
+ case wxHT_TOPLEVEL_BORDER_W:
+ case wxHT_TOPLEVEL_BORDER_E:
+ cur = wxCursor(wxCURSOR_SIZEWE);
+ break;
+ case wxHT_TOPLEVEL_BORDER_NE:
+ case wxHT_TOPLEVEL_BORDER_SW:
+ cur = wxCursor(wxCURSOR_SIZENESW);
+ break;
+ case wxHT_TOPLEVEL_BORDER_NW:
+ case wxHT_TOPLEVEL_BORDER_SE:
+ cur = wxCursor(wxCURSOR_SIZENWSE);
+ break;
+ default:
+ m_borderCursorOn = FALSE;
+ break;
+ }
+ if ( m_borderCursorOn )
+ {
+ m_origCursor = win->GetCursor();
+ win->SetCursor(cur);
+ }
+ }
+ }
+ }
return wxStdInputHandler::HandleMouseMove(consumer, event);
}
bool wxStdFrameInputHandler::HandleActivation(wxInputConsumer *consumer,
bool activated)
{
+ if ( m_borderCursorOn )
+ {
+ consumer->GetInputWindow()->SetCursor(m_origCursor);
+ m_borderCursorOn = FALSE;
+ }
consumer->PerformAction(wxACTION_TOPLEVEL_ACTIVATE, activated);
return FALSE;
}