]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/topluniv.cpp
The UseAntiAliasing is off by default on wxMac. Add a menu item to
[wxWidgets.git] / src / univ / topluniv.cpp
index 6dceed79d762bf611e01f4ed19484a2efbc160bd..dea87cf2f57191bb03c0865c44c1035d6f4acae9 100644 (file)
@@ -2,7 +2,7 @@
 // Name:        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
 /////////////////////////////////////////////////////////////////////////////
 
@@ -14,7 +14,7 @@
 // headers
 // ----------------------------------------------------------------------------
 
-#ifdef __GNUG__
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
     #pragma implementation "univtoplevel.h"
 #endif
 
@@ -37,6 +37,7 @@
 #include "wx/bitmap.h"
 #include "wx/image.h"
 #include "wx/cshelp.h"
+#include "wx/evtloop.h"
 
 
 // ----------------------------------------------------------------------------
@@ -46,6 +47,7 @@
 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)
@@ -99,7 +101,7 @@ bool wxTopLevelWindow::Create(wxWindow *parent,
         style &= ~(wxCAPTION | wxMINIMIZE_BOX | wxMAXIMIZE_BOX |
                    wxSYSTEM_MENU | wxRESIZE_BORDER | wxFRAME_TOOL_WINDOW |
                    wxTHICK_FRAME);
-        style = wxSIMPLE_BORDER;
+        style |= wxSIMPLE_BORDER;
         SetExtraStyle(exstyleOrig &
                       ~(wxFRAME_EX_CONTEXTHELP | wxDIALOG_EX_CONTEXTHELP));
     }
@@ -236,7 +238,7 @@ void wxTopLevelWindow::DoSetClientSize(int width, int height)
         wxTopLevelWindowNative::DoSetClientSize(width, height);
 }
 
-void wxTopLevelWindow::OnNcPaint(wxPaintEvent& event)
+void wxTopLevelWindow::OnNcPaint(wxNcPaintEvent& event)
 {
     if ( !ms_drawDecorations || !m_renderer )
         event.Skip();
@@ -268,17 +270,40 @@ long wxTopLevelWindow::HitTest(const wxPoint& pt) const
     return m_renderer->HitTestFrame(rect, pt+GetClientAreaOrigin(), GetDecorationsStyle());
 }
 
+int wxTopLevelWindow::GetMinWidth() const
+{
+    if ( ms_drawDecorations )
+    {
+        return wxMax(wxTopLevelWindowNative::GetMinWidth(),
+                     m_renderer->GetFrameMinSize(GetDecorationsStyle()).x);
+    }
+    else
+        return wxTopLevelWindowNative::GetMinWidth();
+}
+
+int wxTopLevelWindow::GetMinHeight() const
+{
+    if ( ms_drawDecorations )
+    {
+        return wxMax(wxTopLevelWindowNative::GetMinHeight(),
+                     m_renderer->GetFrameMinSize(GetDecorationsStyle()).y);
+    }
+    else
+        return wxTopLevelWindowNative::GetMinHeight();
+}
+
 // ----------------------------------------------------------------------------
 // icons
 // ----------------------------------------------------------------------------
 
-void wxTopLevelWindow::SetIcon(const wxIcon& icon)
+void wxTopLevelWindow::SetIcons(const wxIconBundle& icons)
 {
-    wxTopLevelWindowNative::SetIcon(icon);
+    wxTopLevelWindowNative::SetIcons(icons);
 
     if ( ms_drawDecorations && m_renderer )
     {
         wxSize size = m_renderer->GetFrameIconSize();
+        const wxIcon& icon = icons.GetIcon( size );
 
         if ( !icon.Ok() || size.x == -1  )
             m_titlebarIcon = icon;
@@ -300,6 +325,336 @@ void wxTopLevelWindow::SetIcon(const wxIcon& icon)
     }
 }
 
+// ----------------------------------------------------------------------------
+// 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;
+                #if 0
+                // not rachable due to earlier return
+                break;
+                #endif
+        }
+        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 != -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& WXUNUSED(event))
+{
+    if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
+    {
+        m_data.m_evtLoop->Exit();
+    }
+}
+
+void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent& event)
+{
+    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_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
 // ----------------------------------------------------------------------------
@@ -339,7 +694,7 @@ void wxTopLevelWindow::ClickTitleBarButton(long button)
 
 bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
                                      long numArg,
-                                     const wxString& strArg)
+                                     const wxString& WXUNUSED(strArg))
 {
     bool isActive = numArg != 0;
 
@@ -400,6 +755,43 @@ bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
         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();
+}
+
 
 // ============================================================================
 // wxStdFrameInputHandler: handles focus, resizing and titlebar buttons clicks
@@ -441,7 +833,7 @@ bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer *consumer,
                 consumer->PerformAction(wxACTION_TOPLEVEL_BUTTON_PRESS, m_winPressed);
                 return TRUE;
             }
-            else if ( hit & wxHT_TOPLEVEL_TITLEBAR )
+            else if ( (hit & wxHT_TOPLEVEL_TITLEBAR) && !w->IsMaximized() )
             {
                 consumer->PerformAction(wxACTION_TOPLEVEL_MOVE);
                 return TRUE;
@@ -511,31 +903,9 @@ bool wxStdFrameInputHandler::HandleMouseMove(wxInputConsumer *consumer,
 
             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;
-                }
+                m_borderCursorOn = wxGetResizingCursor(hit, cur);
                 if ( m_borderCursorOn )
                 {
                     m_origCursor = win->GetCursor();