]> git.saurik.com Git - wxWidgets.git/blobdiff - src/univ/topluniv.cpp
Fix so OGL can build without wxBuffer
[wxWidgets.git] / src / univ / topluniv.cpp
index ab12008f2859faeae5ef66adbf228409ef9709b9..af81456844f98fe5d5440ccd6c2eeda2dfa61cc5 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
 /////////////////////////////////////////////////////////////////////////////
 
 #endif
 
 #include "wx/defs.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/dcclient.h"
+    #include "wx/settings.h"
+#endif
+
 #include "wx/toplevel.h"
 #include "wx/univ/renderer.h"
-#include "wx/dcclient.h"
 #include "wx/bitmap.h"
 #include "wx/image.h"
 #include "wx/cshelp.h"
+#include "wx/evtloop.h"
 
 
 // ----------------------------------------------------------------------------
@@ -50,6 +56,7 @@ WX_FORWARD_TO_INPUT_CONSUMER(wxTopLevelWindow)
 // ============================================================================
 
 int wxTopLevelWindow::ms_drawDecorations = -1;
+int wxTopLevelWindow::ms_canIconize = -1;
 
 void wxTopLevelWindow::Init()
 {
@@ -71,9 +78,18 @@ bool wxTopLevelWindow::Create(wxWindow *parent,
          exstyleOrig = 0;
 
     if ( ms_drawDecorations == -1 )
-        ms_drawDecorations = TRUE;
-        // FIXME_MGL -- this is temporary; we assume for now that native TLW
-        //              can't do decorations, which is not true
+    {
+        ms_drawDecorations = 
+            !wxSystemSettings::HasFeature(wxSYS_CAN_DRAW_FRAME_DECORATIONS) 
+            || wxGetEnv(wxT("WXDECOR"), NULL);
+        // FIXME -- wxUniv should provide a way to force non-native decorations!
+        //          $WXDECOR is just a hack in absence of better wxUniv solution
+    }
+
+    if ( ms_canIconize == -1 )
+    {
+        ms_canIconize = wxSystemSettings::HasFeature(wxSYS_CAN_ICONIZE_FRAME);
+    }
 
     if ( ms_drawDecorations )
     {
@@ -93,15 +109,6 @@ bool wxTopLevelWindow::Create(wxWindow *parent,
                                          size, style, name) )
         return FALSE;
 
-    // FIXME: to be removed as soon as wxTLW/wxFrame/wxDialog creation code in
-    //        wxMSW is rationalized
-#ifdef __WXMSW__
-    extern const wxChar *wxFrameClassName;
-    if ( !MSWCreate(id, NULL, wxFrameClassName, this, title,
-                    pos.x, pos.y, size.x, size.y, style) )
-        return FALSE;
-#endif // __WXMSW__
-
     if ( ms_drawDecorations )
     {
         m_windowStyle = styleOrig;
@@ -141,10 +148,15 @@ long wxTopLevelWindow::GetDecorationsStyle() const
     if ( m_windowStyle & wxCAPTION )
     {
         style |= wxTOPLEVEL_TITLEBAR | wxTOPLEVEL_BUTTON_CLOSE;
-        if ( m_windowStyle & wxMINIMIZE_BOX )
+        if ( (m_windowStyle & wxMINIMIZE_BOX) && ms_canIconize )
             style |= wxTOPLEVEL_BUTTON_ICONIZE;
         if ( m_windowStyle & wxMAXIMIZE_BOX )
-            style |= wxTOPLEVEL_BUTTON_MAXIMIZE;
+        {
+            if ( IsMaximized() )
+                style |= wxTOPLEVEL_BUTTON_RESTORE;
+            else
+                style |= wxTOPLEVEL_BUTTON_MAXIMIZE;
+        }
 #if wxUSE_HELP
         if ( m_exStyle & (wxFRAME_EX_CONTEXTHELP | wxDIALOG_EX_CONTEXTHELP))
             style |= wxTOPLEVEL_BUTTON_HELP;
@@ -254,7 +266,29 @@ long wxTopLevelWindow::HitTest(const wxPoint& pt) const
     wxTopLevelWindowNative::DoGetClientSize(&w, &h);
     wxRect rect(wxTopLevelWindowNative::GetClientAreaOrigin(), wxSize(w, h));
 
-    return m_renderer->HitTestFrame(rect, pt, GetDecorationsStyle());
+    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();
 }
 
 // ----------------------------------------------------------------------------
@@ -264,29 +298,247 @@ long wxTopLevelWindow::HitTest(const wxPoint& pt) const
 void wxTopLevelWindow::SetIcon(const wxIcon& icon)
 {
     wxTopLevelWindowNative::SetIcon(icon);
-    if ( !m_renderer ) return;
-
-    wxSize size = m_renderer->GetFrameIconSize();
 
-    if ( !icon.Ok() || size.x == -1  )
-        m_titlebarIcon = icon;
-    else
+    if ( ms_drawDecorations && m_renderer )
     {
-        wxBitmap bmp1;
-        bmp1.CopyFromIcon(icon);
-        if ( !bmp1.Ok() )
-            m_titlebarIcon = wxNullIcon;
-        else if ( bmp1.GetWidth() == size.x && bmp1.GetHeight() == size.y )
+        wxSize size = m_renderer->GetFrameIconSize();
+
+        if ( !icon.Ok() || size.x == -1  )
             m_titlebarIcon = icon;
         else
         {
-            wxImage img = bmp1.ConvertToImage();
-            img.Rescale(size.x, size.y);
-            m_titlebarIcon.CopyFromBitmap(wxBitmap(img));
+            wxBitmap bmp1;
+            bmp1.CopyFromIcon(icon);
+            if ( !bmp1.Ok() )
+                m_titlebarIcon = wxNullIcon;
+            else if ( bmp1.GetWidth() == size.x && bmp1.GetHeight() == size.y )
+                m_titlebarIcon = icon;
+            else
+            {
+                wxImage img = bmp1.ConvertToImage();
+                img.Rescale(size.x, size.y);
+                m_titlebarIcon.CopyFromBitmap(wxBitmap(img));
+            }
         }
     }
 }
 
+// ----------------------------------------------------------------------------
+// interactive manipulation
+// ----------------------------------------------------------------------------
+
+#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 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;
+    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*/);
+}
+
 // ----------------------------------------------------------------------------
 // actions
 // ----------------------------------------------------------------------------
@@ -334,11 +586,8 @@ bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
     {
         if ( m_isActive != isActive )
         {
-            Refresh();
             m_isActive = isActive;
-            wxNcPaintEvent event(GetId());
-            event.SetEventObject(this);
-            GetEventHandler()->ProcessEvent(event);
+            RefreshTitleBar();
         }
         return TRUE;
     }
@@ -365,6 +614,27 @@ bool wxTopLevelWindow::PerformAction(const wxControlAction& action,
         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;
 }
@@ -380,6 +650,7 @@ wxStdFrameInputHandler::wxStdFrameInputHandler(wxInputHandler *inphand)
     m_winCapture = NULL;
     m_winHitTest = 0;
     m_winPressed = 0;
+    m_borderCursorOn = FALSE;
 }
 
 bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer *consumer,
@@ -409,6 +680,17 @@ bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer *consumer,
                 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
@@ -435,8 +717,6 @@ bool wxStdFrameInputHandler::HandleMouse(wxInputConsumer *consumer,
 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());
@@ -452,6 +732,57 @@ bool wxStdFrameInputHandler::HandleMouseMove(wxInputConsumer *consumer,
             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);
 }
@@ -459,6 +790,11 @@ bool wxStdFrameInputHandler::HandleMouseMove(wxInputConsumer *consumer,
 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;
 }