]> git.saurik.com Git - wxWidgets.git/blobdiff - src/aui/framemanager.cpp
handle correctly never/always shown scrollbars in GetClientSize()
[wxWidgets.git] / src / aui / framemanager.cpp
index 518eab1b33a04c15b8c579c8736f21085ff5b588..4c7d3831c3cf7d954413a4a00f607e82fdd7bc60 100644 (file)
@@ -29,6 +29,7 @@
 #include "wx/aui/dockart.h"
 #include "wx/aui/floatpane.h"
 #include "wx/aui/tabmdi.h"
+#include "wx/aui/auibar.h"
 
 #ifndef WX_PRECOMP
     #include "wx/panel.h"
@@ -64,7 +65,13 @@ DEFINE_EVENT_TYPE(wxEVT_AUI_FIND_MANAGER)
     // a few defines to avoid nameclashes
     #define __MAC_OS_X_MEMORY_MANAGER_CLEAN__ 1
     #define __AIFF__
-    #include "wx/mac/private.h"
+    #include "wx/osx/private.h"
+#endif
+
+#ifdef __WXMSW__
+    #include "wx/msw/wrapwin.h"
+    #include "wx/msw/private.h"
+    #include "wx/msw/dc.h"
 #endif
 
 IMPLEMENT_DYNAMIC_CLASS(wxAuiManagerEvent, wxEvent)
@@ -74,6 +81,8 @@ IMPLEMENT_CLASS(wxAuiManager, wxEvtHandler)
 
 const int auiToolBarLayer = 10;
 
+#ifndef __WXGTK20__
+
 
 class wxPseudoTransparentFrame : public wxFrame
 {
@@ -209,6 +218,75 @@ BEGIN_EVENT_TABLE(wxPseudoTransparentFrame, wxFrame)
 END_EVENT_TABLE()
 
 
+#else
+  // __WXGTK20__
+
+#include <gtk/gtk.h>
+
+static void
+gtk_pseudo_window_realized_callback( GtkWidget *m_widget, void *WXUNUSED(win) )
+{
+        wxSize disp = wxGetDisplaySize();
+        int amount = 128;
+        wxRegion region;
+        for (int y=0; y<disp.y; y++)
+                {
+                    // Reverse the order of the bottom 4 bits
+                    int j=((y&8)?1:0)|((y&4)?2:0)|((y&2)?4:0)|((y&1)?8:0);
+                    if ((j*16+8)<amount)
+                        region.Union(0, y, disp.x, 1);
+                }
+        gdk_window_shape_combine_region(m_widget->window, region.GetRegion(), 0, 0);
+}
+
+
+class wxPseudoTransparentFrame: public wxFrame
+{
+public:
+    wxPseudoTransparentFrame(wxWindow* parent = NULL,
+                wxWindowID id = wxID_ANY,
+                const wxString& title = wxEmptyString,
+                const wxPoint& pos = wxDefaultPosition,
+                const wxSize& size = wxDefaultSize,
+                long style = wxDEFAULT_FRAME_STYLE,
+                const wxString &name = wxT("frame"))
+    {
+         if (!CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
+            return;
+
+        m_title = title;
+
+        m_widget = gtk_window_new( GTK_WINDOW_POPUP );
+        g_object_ref(m_widget);
+
+        if (parent) parent->AddChild(this);
+
+        g_signal_connect( m_widget, "realize",
+                      G_CALLBACK (gtk_pseudo_window_realized_callback), this );
+
+        GdkColor col;
+        col.red = 128 * 256;
+        col.green = 192 * 256;
+        col.blue = 255 * 256;
+        gtk_widget_modify_bg( m_widget, GTK_STATE_NORMAL, &col );
+    }
+
+    bool SetTransparent(wxByte WXUNUSED(alpha))
+    {
+        return true;
+    }
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxPseudoTransparentFrame)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxPseudoTransparentFrame, wxFrame)
+
+#endif
+ // __WXGTK20__
+
+
+
 // -- static utility functions --
 
 static wxBitmap wxPaneCreateStippleBitmap()
@@ -223,10 +301,15 @@ static void DrawResizeHint(wxDC& dc, const wxRect& rect)
     wxBitmap stipple = wxPaneCreateStippleBitmap();
     wxBrush brush(stipple);
     dc.SetBrush(brush);
+#ifdef __WXMSW__
+    wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
+    PatBlt(GetHdcOf(*impl), rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight(), PATINVERT);
+#else
     dc.SetPen(*wxTRANSPARENT_PEN);
 
     dc.SetLogicalFunction(wxXOR);
     dc.DrawRectangle(rect);
+#endif
 }
 
 
@@ -430,20 +513,26 @@ static void RemovePaneFromDocks(wxAuiDockInfoArray& docks,
     }
 }
 
+/*
+// This function works fine, and may be used in the future
+
 // RenumberDockRows() takes a dock and assigns sequential numbers
 // to existing rows.  Basically it takes out the gaps; so if a
 // dock has rows with numbers 0,2,5, they will become 0,1,2
 static void RenumberDockRows(wxAuiDockInfoPtrArray& docks)
 {
-    int i, dock_count, j, pane_count;
+    int i, dock_count;
     for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
     {
         wxAuiDockInfo& dock = *docks.Item(i);
         dock.dock_row = i;
+
+        int j, pane_count;
         for (j = 0, pane_count = dock.panes.GetCount(); j < pane_count; ++j)
             dock.panes.Item(j)->dock_row = i;
     }
 }
+*/
 
 
 // SetActivePane() sets the active pane, as well as cycles through
@@ -483,6 +572,7 @@ BEGIN_EVENT_TABLE(wxAuiManager, wxEvtHandler)
     EVT_LEFT_UP(wxAuiManager::OnLeftUp)
     EVT_MOTION(wxAuiManager::OnMotion)
     EVT_LEAVE_WINDOW(wxAuiManager::OnLeaveWindow)
+    EVT_MOUSE_CAPTURE_LOST(wxAuiManager::OnCaptureLost)
     EVT_CHILD_FOCUS(wxAuiManager::OnChildFocus)
     EVT_AUI_FIND_MANAGER(wxAuiManager::OnFindManager)
     EVT_TIMER(101, wxAuiManager::OnHintFadeTimer)
@@ -512,12 +602,18 @@ wxAuiManager::wxAuiManager(wxWindow* managed_wnd, unsigned int flags)
 
 wxAuiManager::~wxAuiManager()
 {
+    // NOTE: It's possible that the windows have already been destroyed by the
+    // time this dtor is called, so this loop can result in memory access via
+    // invalid pointers, resulting in a crash.  So it will be disabled while
+    // waiting for a better solution.
+#if 0
     for ( size_t i = 0; i < m_panes.size(); i++ )
     {
         wxAuiPaneInfo& pinfo = m_panes[i];
         if (pinfo.window && !pinfo.window->GetParent())
             delete pinfo.window;
     }
+#endif
 
     delete m_art;
 }
@@ -682,6 +778,7 @@ void wxAuiManager::UpdateHintWindowConfig()
         {
             wxFrame* f = static_cast<wxFrame*>(w);
             can_do_transparent = f->CanSetTransparent();
+            
             break;
         }
 
@@ -717,6 +814,8 @@ void wxAuiManager::UpdateHintWindowConfig()
                                          wxDefaultPosition, wxSize(1,1),
                                          wxFRAME_FLOAT_ON_PARENT
                                          | wxFRAME_TOOL_WINDOW );
+            m_hint_wnd->Connect(wxEVT_ACTIVATE,
+                wxActivateEventHandler(wxAuiManager::OnHintActivate), NULL, this);
 
             // Can't set the bg colour of a Frame in wxMac
             wxPanel* p = new wxPanel(m_hint_wnd);
@@ -845,6 +944,8 @@ void wxAuiManager::SetArtProvider(wxAuiDockArt* art_provider)
 
 bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info)
 {
+    wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed"));
+    
     // check if the pane has a valid window
     if (!window)
         return false;
@@ -878,7 +979,7 @@ bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info)
     if (pinfo.name.empty() || already_exists)
     {
         pinfo.name.Printf(wxT("%08lx%08x%08x%08lx"),
-             ((unsigned long)pinfo.window) & 0xffffffff,
+             wxPtrToUInt(pinfo.window) & 0xffffffff,
              (unsigned int)time(NULL),
 #ifdef __WXWINCE__
              (unsigned int)GetTickCount(),
@@ -912,6 +1013,22 @@ bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info)
         button.button_id = wxAUI_BUTTON_CLOSE;
         pinfo.buttons.Add(button);
     }
+    
+    if (pinfo.HasGripper())
+    {
+        if (pinfo.window->IsKindOf(CLASSINFO(wxAuiToolBar)))
+        {
+            // prevent duplicate gripper -- both wxAuiManager and wxAuiToolBar
+            // have a gripper control.  The toolbar's built-in gripper
+            // meshes better with the look and feel of the control than ours,
+            // so turn wxAuiManager's gripper off, and the toolbar's on.
+            
+            wxAuiToolBar* tb = static_cast<wxAuiToolBar*>(pinfo.window);
+            pinfo.SetFlag(wxAuiPaneInfo::optionGripper, false);
+            tb->SetGripperVisible(true);
+        }
+    }
+    
 
     if (pinfo.best_size == wxDefaultSize &&
         pinfo.window)
@@ -943,6 +1060,8 @@ bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info)
         }
     }
 
+
+    
     return true;
 }
 
@@ -980,6 +1099,8 @@ bool wxAuiManager::AddPane(wxWindow* window,
 bool wxAuiManager::InsertPane(wxWindow* window, const wxAuiPaneInfo& pane_info,
                                 int insert_level)
 {
+    wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed"));
+
     // shift the panes around, depending on the insert level
     switch (insert_level)
     {
@@ -1040,6 +1161,8 @@ bool wxAuiManager::InsertPane(wxWindow* window, const wxAuiPaneInfo& pane_info,
 // method will not destroy the window that is removed.
 bool wxAuiManager::DetachPane(wxWindow* window)
 {
+    wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed"));
+
     int i, count;
     for (i = 0, count = m_panes.GetCount(); i < count; ++i)
     {
@@ -1093,8 +1216,7 @@ bool wxAuiManager::DetachPane(wxWindow* window)
     return false;
 }
 
-// ClosePane() destroys or hides the pane depending on its
-// flags
+// ClosePane() destroys or hides the pane depending on its flags
 void wxAuiManager::ClosePane(wxAuiPaneInfo& pane_info)
 {
     // if we were maximized, restore
@@ -1479,7 +1601,7 @@ void wxAuiManager::GetPanePositionsAndSizes(wxAuiDockInfo& dock,
     {
         wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i));
 
-        if (pane.state & wxAuiPaneInfo::actionPane)
+        if (pane.HasFlag(wxAuiPaneInfo::actionPane))
         {
             wxASSERT_MSG(action_pane==-1, wxT("Too many fixed action panes"));
             action_pane = pane_i;
@@ -2091,7 +2213,7 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
                 dock.toolbar = false;
             if (pane.HasFlag(wxAuiPaneInfo::optionDockFixed))
                 dock.fixed = true;
-            if (pane.state & wxAuiPaneInfo::actionPane)
+            if (pane.HasFlag(wxAuiPaneInfo::actionPane))
                 action_pane_marked = true;
         }
 
@@ -2170,7 +2292,6 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
 
         // find any top docks in this layer
         FindDocks(docks, wxAUI_DOCK_TOP, layer, -1, arr);
-        RenumberDockRows(arr);
         if (!arr.IsEmpty())
         {
             for (row = 0, row_count = arr.GetCount(); row < row_count; ++row)
@@ -2185,7 +2306,6 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
 
         // find any left docks in this layer
         FindDocks(docks, wxAUI_DOCK_LEFT, layer, -1, arr);
-        RenumberDockRows(arr);
         if (!arr.IsEmpty())
         {
             for (row = 0, row_count = arr.GetCount(); row < row_count; ++row)
@@ -2224,20 +2344,21 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
 
         // find any right docks in this layer
         FindDocks(docks, wxAUI_DOCK_RIGHT, layer, -1, arr);
-        RenumberDockRows(arr);
         if (!arr.IsEmpty())
         {
             for (row = arr.GetCount()-1; row >= 0; --row)
                 LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only);
         }
 
-        cont->Add(middle, 1, wxEXPAND);
-
+        if (middle->GetChildren().GetCount() > 0)
+            cont->Add(middle, 1, wxEXPAND);
+             else
+            delete middle;
+            
 
 
         // find any bottom docks in this layer
         FindDocks(docks, wxAUI_DOCK_BOTTOM, layer, -1, arr);
-        RenumberDockRows(arr);
         if (!arr.IsEmpty())
         {
             for (row = arr.GetCount()-1; row >= 0; --row)
@@ -2295,6 +2416,7 @@ void wxAuiManager::GetDockSizeConstraint(double* width_pct, double* height_pct)
 void wxAuiManager::Update()
 {
     m_hover_button = NULL;
+    m_action_part = NULL;
 
     wxSizer* sizer;
     int i, pane_count = m_panes.GetCount();
@@ -2773,7 +2895,8 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks,
                     (part->dock->dock_direction != wxAUI_DOCK_CENTER &&
                      part->dock->dock_direction != wxAUI_DOCK_NONE)))
                 {
-                    drop.Float();
+                    if (drop.IsFloatable())
+                        drop.Float();
                 }
 
                 m_skipping = false;
@@ -3141,7 +3264,7 @@ void wxAuiManager::ShowHint(const wxRect& rect)
         // nasty redrawn problems.
         clip.Intersect(m_frame->GetRect());
 
-        screendc.SetClippingRegion(clip);
+        screendc.SetDeviceClippingRegion(clip);
 
         wxBitmap stipple = wxPaneCreateStippleBitmap();
         wxBrush brush(stipple);
@@ -3177,6 +3300,17 @@ void wxAuiManager::HideHint()
     }
 }
 
+void wxAuiManager::OnHintActivate(wxActivateEvent& WXUNUSED(event))
+{
+    // Do nothing so this event isn't handled in the base handlers.
+
+    // Letting the hint window activate without this handler can lead to
+    // weird behavior on Mac where the menu is switched out to the top
+    // window's menu in MDI applications when it shouldn't be. So since
+    // we don't want user interaction with the hint window anyway, we just
+    // prevent it from activating here.
+}
+
 
 
 void wxAuiManager::StartPaneDrag(wxWindow* pane_window,
@@ -3474,7 +3608,6 @@ void wxAuiManager::OnFloatingPaneMoved(wxWindow* wnd, wxDirection dir)
     wxPoint frame_pos = pane.frame->GetPosition();
     wxPoint action_offset(pt.x-frame_pos.x, pt.y-frame_pos.y);
 
-
     // if a key modifier is pressed while dragging the frame,
     // don't dock the window
     if (CanDockPanel(pane))
@@ -3532,7 +3665,15 @@ void wxAuiManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt)
     }
     else
     {
-        ClosePane(pane);
+        // close the pane, but check that it
+        // still exists in our pane array first
+        // (the event handler above might have removed it)
+
+        wxAuiPaneInfo& check = GetPane(wnd);
+        if (check.IsOk())
+        {
+            ClosePane(pane);
+        }
     }
 }
 
@@ -4079,17 +4220,21 @@ void wxAuiManager::OnLeftUp(wxMouseEvent& event)
     {
         m_hover_button = NULL;
         m_frame->ReleaseMouse();
-        UpdateButtonOnScreen(m_action_part, event);
-
-        // make sure we're still over the item that was originally clicked
-        if (m_action_part == HitTest(event.GetX(), event.GetY()))
+        
+        if (m_action_part)
         {
-            // fire button-click event
-            wxAuiManagerEvent e(wxEVT_AUI_PANE_BUTTON);
-            e.SetManager(this);
-            e.SetPane(m_action_part->pane);
-            e.SetButton(m_action_part->button->button_id);
-            ProcessMgrEvent(e);
+            UpdateButtonOnScreen(m_action_part, event);
+
+            // make sure we're still over the item that was originally clicked
+            if (m_action_part == HitTest(event.GetX(), event.GetY()))
+            {
+                // fire button-click event
+                wxAuiManagerEvent e(wxEVT_AUI_PANE_BUTTON);
+                e.SetManager(this);
+                e.SetPane(m_action_part->pane);
+                e.SetButton(m_action_part->button->button_id);
+                ProcessMgrEvent(e);
+            }
         }
     }
     else if (m_action == actionClickCaption)
@@ -4152,20 +4297,23 @@ void wxAuiManager::OnMotion(wxMouseEvent& event)
 
     if (m_action == actionResize)
     {
-        wxPoint pos = m_action_part->rect.GetPosition();
-        if (m_action_part->orientation == wxHORIZONTAL)
-            pos.y = wxMax(0, event.m_y - m_action_offset.y);
-        else
-            pos.x = wxMax(0, event.m_x - m_action_offset.x);
+        if (m_action_part)
+        {
+            wxPoint pos = m_action_part->rect.GetPosition();
+            if (m_action_part->orientation == wxHORIZONTAL)
+                pos.y = wxMax(0, event.m_y - m_action_offset.y);
+            else
+                pos.x = wxMax(0, event.m_x - m_action_offset.x);
 
-        wxRect rect(m_frame->ClientToScreen(pos),
-                    m_action_part->rect.GetSize());
+            wxRect rect(m_frame->ClientToScreen(pos),
+                        m_action_part->rect.GetSize());
 
-        wxScreenDC dc;
-        if (!m_action_hintrect.IsEmpty())
-            DrawResizeHint(dc, m_action_hintrect);
-        DrawResizeHint(dc, rect);
-        m_action_hintrect = rect;
+            wxScreenDC dc;
+            if (!m_action_hintrect.IsEmpty())
+                DrawResizeHint(dc, m_action_hintrect);
+            DrawResizeHint(dc, rect);
+            m_action_hintrect = rect;
+        }
     }
     else if (m_action == actionClickCaption)
     {
@@ -4175,8 +4323,9 @@ void wxAuiManager::OnMotion(wxMouseEvent& event)
         // caption has been clicked.  we need to check if the mouse
         // is now being dragged. if it is, we need to change the
         // mouse action to 'drag'
-        if (abs(event.m_x - m_action_start.x) > drag_x_threshold ||
-            abs(event.m_y - m_action_start.y) > drag_y_threshold)
+        if (m_action_part &&
+            (abs(event.m_x - m_action_start.x) > drag_x_threshold ||
+             abs(event.m_y - m_action_start.y) > drag_y_threshold))
         {
             wxAuiPaneInfo* pane_info = m_action_part->pane;
 
@@ -4231,7 +4380,7 @@ void wxAuiManager::OnMotion(wxMouseEvent& event)
         wxAuiPaneInfo& pane = GetPane(m_action_window);
         wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
 
-        pane.state |= wxAuiPaneInfo::actionPane;
+        pane.SetFlag(wxAuiPaneInfo::actionPane, true);
 
         wxPoint pt = event.GetPosition();
         DoDrop(m_docks, m_panes, pane, pt, m_action_offset);
@@ -4306,6 +4455,16 @@ void wxAuiManager::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
     }
 }
 
+void wxAuiManager::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
+{
+    // cancel the operation in progress, if any
+    if ( m_action != actionNone )
+    {
+        m_action = actionNone;
+        HideHint();
+    }
+}
+
 void wxAuiManager::OnChildFocus(wxChildFocusEvent& event)
 {
     // when a child pane has it's focus set, we should change the
@@ -4343,7 +4502,16 @@ void wxAuiManager::OnPaneButton(wxAuiManagerEvent& evt)
 
         if (!e.GetVeto())
         {
-            ClosePane(pane);
+            // close the pane, but check that it
+            // still exists in our pane array first
+            // (the event handler above might have removed it)
+
+            wxAuiPaneInfo& check = GetPane(pane.window);
+            if (check.IsOk())
+            {
+                ClosePane(pane);
+            }
+
             Update();
         }
     }