Kirix Support Forums

Dock and Pane Resizing

Please post any wxAUI patches or modifications you've created here. Thanks!

Dock and Pane Resizing

Postby Rick on Sat Nov 24, 2007 11:35 am

Hello,

I have been experimenting with wxAUI for a while and found a couple of issues with pane and dock resizing.

1) When dragging the sash to the left or bottom of the frame, the sash hint gets drawn outside the frame. The sash hint is already limited at the left and top side. I have modified wxAuiManager::OnMotion to clip the sash hint on both sides of the client area. Perhaps in the future it would be nice to prevent sash hints from being drawn at all undroppable locations.

2) When resizing the panes in a dock, the minimum pane sizes gets respected at the left and top side, but not at the right or bottom side. The function wxAuiManager::OnLeftUp checks the minimum size of the resized pane. I have modified it such that it also checks the minimum size of the borrow pane.

3) When resizing docks to the opposite direction (bottom dock to the top, right dock to the left, etc.) the client area can shrink below its minimum size, also the dock can overlap with docks at the opposite side. I have created a fix for this in the wxAuiManager::OnLeftUp function. It checks the minimum size of the content area and the current size of the opposite docks and limits the sash drop location to this. A limitation is that I couldn't retrieve the vertical minimum size of the content area, therefore the horizontal minimum is used in both orientations.

4) When shrinking the frame, minimum sizes aren't respected. Not sure how to fix this.


The modifications are based on the framemanager.cpp included in wxWidgets 2.8.6. I have marked all my modifications with //Rick:

1)
Code: Select all
void wxAuiManager::OnMotion(wxMouseEvent& event)
{
    // sometimes when Update() is called from inside this method,
    // a spurious mouse move event is generated; this check will make
    // sure that only real mouse moves will get anywhere in this method;
    // this appears to be a bug somewhere, and I don't know where the
    // mouse move event is being generated.  only verified on MSW

    wxPoint mouse_pos = event.GetPosition();
    if (m_last_mouse_move == mouse_pos)
        return;
    m_last_mouse_move = mouse_pos;


    if (m_action == actionResize)
    {
        wxPoint pos = m_action_part->rect.GetPosition();
      
//Rick: Line added
      wxSize cli_size = m_frame->GetClientSize();

      if (m_action_part->orientation == wxHORIZONTAL)
//Rick: Line modified
            pos.y = wxClip(event.m_y - m_action_offset.y, 0, cli_size.y - m_action_hintrect.GetHeight());
            else
//Rick: Line modified
            pos.x = wxClip(event.m_x - m_action_offset.x, 0, cli_size.x - m_action_hintrect.GetWidth());

        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;
    }

...


2, 3)
Code: Select all
void wxAuiManager::OnLeftUp(wxMouseEvent& event)
{
    if (m_action == actionResize)
    {
        m_frame->ReleaseMouse();

        // get rid of the hint rectangle
        wxScreenDC dc;
        DrawResizeHint(dc, m_action_hintrect);

        // resize the dock or the pane
        if (m_action_part && m_action_part->type==wxAuiDockUIPart::typeDockSizer)
        {
            wxRect& rect = m_action_part->dock->rect;

            wxPoint new_pos(event.m_x - m_action_offset.x,
                            event.m_y - m_action_offset.y);

//Rick: Begin Added:
         int opposite_size = 0;      
         wxAuiDockInfoPtrArray opposite_docks;
         wxSize cli_size = m_frame->GetClientSize();
         unsigned int i;

         // Get minimum size of content area
         // TODO: Get the horizontal minimum size for the left and right docks
         FindDocks(m_docks, wxAUI_DOCK_CENTER, -1, -1, opposite_docks);
         for (i = 0; i < opposite_docks.GetCount(); ++i)
            opposite_size += opposite_docks.Item(i)->min_size;

         // Get opposite docks
         switch (m_action_part->dock->dock_direction)
            {
                case wxAUI_DOCK_LEFT:
               FindDocks(m_docks, wxAUI_DOCK_RIGHT, -1, -1, opposite_docks);
               break;
                case wxAUI_DOCK_TOP:
               FindDocks(m_docks, wxAUI_DOCK_BOTTOM, -1, -1, opposite_docks);
               break;
                case wxAUI_DOCK_RIGHT:
               FindDocks(m_docks, wxAUI_DOCK_LEFT, -1, -1, opposite_docks);
               break;
                case wxAUI_DOCK_BOTTOM:
               FindDocks(m_docks, wxAUI_DOCK_TOP, -1, -1, opposite_docks);
               break;
            }

         // Sum size of the opposite docks
         for (i = 0; i < opposite_docks.GetCount(); ++i)
            opposite_size += opposite_docks.Item(i)->size;
//Rick: End Added

            switch (m_action_part->dock->dock_direction)
            {
                case wxAUI_DOCK_LEFT:
//Rick: Line Added:
               // Limit the sash drop position
               new_pos.x = wxMin(new_pos.x, cli_size.x - opposite_size);

                    m_action_part->dock->size = new_pos.x - rect.x;
                    break;
                case wxAUI_DOCK_TOP:
//Rick: Line Added:
               // Limit the sash drop position
               new_pos.y = wxMin(new_pos.y, cli_size.y - opposite_size);

               m_action_part->dock->size = new_pos.y - rect.y;
                    break;
                case wxAUI_DOCK_RIGHT:
//Rick: Line Added:
               // Limit the sash drop position
               new_pos.x = wxMax(new_pos.x, opposite_size);

               m_action_part->dock->size = rect.x + rect.width -
                                  new_pos.x - m_action_part->rect.GetWidth();
                    break;
                case wxAUI_DOCK_BOTTOM:
//Rick: Line Added:
               // Limit the sash drop position
               new_pos.y = wxMax(new_pos.y, opposite_size);
               
               m_action_part->dock->size = rect.y + rect.height -
                                  new_pos.y - m_action_part->rect.GetHeight();
                    break;
            }

            Update();
            Repaint(NULL);
        }
         else if (m_action_part &&
                  m_action_part->type == wxAuiDockUIPart::typePaneSizer)
        {
            wxAuiDockInfo& dock = *m_action_part->dock;
            wxAuiPaneInfo& pane = *m_action_part->pane;

            int total_proportion = 0;
            int dock_pixels = 0;
            int new_pixsize = 0;

            int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE);
            int pane_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
            int sash_size = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE);

            wxPoint new_pos(event.m_x - m_action_offset.x,
                            event.m_y - m_action_offset.y);

            // determine the pane rectangle by getting the pane part
            wxAuiDockUIPart* pane_part = GetPanePart(pane.window);
            wxASSERT_MSG(pane_part,
                       wxT("Pane border part not found -- shouldn't happen"));

            // determine the new pixel size that the user wants;
            // this will help us recalculate the pane's proportion
            if (dock.IsHorizontal())
                new_pixsize = new_pos.x - pane_part->rect.x;
                 else
                new_pixsize = new_pos.y - pane_part->rect.y;

            // determine the size of the dock, based on orientation
            if (dock.IsHorizontal())
                dock_pixels = dock.rect.GetWidth();
                 else
                dock_pixels = dock.rect.GetHeight();

            // determine the total proportion of all resizable panes,
            // and the total size of the dock minus the size of all
            // the fixed panes
            int i, dock_pane_count = dock.panes.GetCount();
            int pane_position = -1;
            for (i = 0; i < dock_pane_count; ++i)
            {
                wxAuiPaneInfo& p = *dock.panes.Item(i);
                if (p.window == pane.window)
                    pane_position = i;

                // while we're at it, subtract the pane sash
                // width from the dock width, because this would
                // skew our proportion calculations
                if (i > 0)
                    dock_pixels -= sash_size;

                // also, the whole size (including decorations) of
                // all fixed panes must also be subtracted, because they
                // are not part of the proportion calculation
                if (p.IsFixed())
                {
                    if (dock.IsHorizontal())
                        dock_pixels -= p.best_size.x;
                         else
                        dock_pixels -= p.best_size.y;
                }
                 else
                {
                    total_proportion += p.dock_proportion;
                }
            }

            // find a pane in our dock to 'steal' space from or to 'give'
            // space to -- this is essentially what is done when a pane is
            // resized; the pane should usually be the first non-fixed pane
            // to the right of the action pane
//Rick: Line Modified:
            int borrow_pane_index = -1;
            for (i = pane_position+1; i < dock_pane_count; ++i)
            {
                wxAuiPaneInfo& p = *dock.panes.Item(i);
                if (!p.IsFixed())
                {
//Rick: Line Modified:
               borrow_pane_index = i;

                    break;
                }
            }


            // demand that the pane being resized is found in this dock
            // (this assert really never should be raised)
            wxASSERT_MSG(pane_position != -1, wxT("Pane not found in dock"));

            // prevent division by zero
//Rick: Line Modified:
            if (dock_pixels == 0 || total_proportion == 0 || borrow_pane_index == -1)
            {
                m_action = actionNone;
                return;
            }

            // calculate the new proportion of the pane
            int new_proportion = (new_pixsize*total_proportion)/dock_pixels;

            // default minimum size
            int min_size = 0;

            // check against the pane's minimum size, if specified. please note
            // that this is not enough to ensure that the minimum size will
            // not be violated, because the whole frame might later be shrunk,
            // causing the size of the pane to violate it's minimum size
            if (pane.min_size.IsFullySpecified())
            {
                min_size = 0;

                if (pane.HasBorder())
                    min_size += (pane_border_size*2);

                // calculate minimum size with decorations (border,caption)
                if (pane_part->orientation == wxVERTICAL)
                {
                    min_size += pane.min_size.y;
                    if (pane.HasCaption())
                        min_size += caption_size;
                }
                 else
                {
                    min_size += pane.min_size.x;
                }
            }

            // for some reason, an arithmatic error somewhere is causing
            // the proportion calculations to always be off by 1 pixel;
            // for now we will add the 1 pixel on, but we really should
            // determine what's causing this.
            min_size++;

         int min_proportion = (min_size*total_proportion)/dock_pixels;


//Rick: Begin Added:
         wxAuiPaneInfo& borrow_pane = *(dock.panes.Item(i));

            // default minimum size
            int borrow_min_size = 0;

            // check against the pane's minimum size, if specified. please note
            // that this is not enough to ensure that the minimum size will
            // not be violated, because the whole frame might later be shrunk,
            // causing the size of the pane to violate it's minimum size
            if (borrow_pane.min_size.IsFullySpecified())
            {
                borrow_min_size = 0;

                if (borrow_pane.HasBorder())
                    borrow_min_size += (pane_border_size*2);

                // calculate minimum size with decorations (border,caption)
                if (pane_part->orientation == wxVERTICAL)
                {
                    borrow_min_size += borrow_pane.min_size.y;
                    if (borrow_pane.HasCaption())
                        borrow_min_size += caption_size;
                }
                 else
                {
                    borrow_min_size += borrow_pane.min_size.x;
                }
            }

            // for some reason, an arithmatic error somewhere is causing
            // the proportion calculations to always be off by 1 pixel;
            // for now we will add the 1 pixel on, but we really should
            // determine what's causing this.
            borrow_min_size++;

         int borrow_min_proportion = (borrow_min_size*total_proportion)/dock_pixels;
//Rick: End Added
       
//Rick: Begin Modified:
            if (new_proportion < min_proportion)
                new_proportion = min_proportion;

            int prop_diff = new_proportion - pane.dock_proportion;

            // borrow the space from our neighbor pane to the
            // right or bottom (depending on orientation)
         int borrow_new_proportion = borrow_pane.dock_proportion - prop_diff;

         // Prevent borrowing to much
         if (borrow_new_proportion < borrow_min_proportion)
            borrow_new_proportion = borrow_min_proportion;

         prop_diff = borrow_pane.dock_proportion - borrow_new_proportion;

            borrow_pane.dock_proportion -= prop_diff;
            pane.dock_proportion += prop_diff;
//Rick: End Modified

            // repaint
            Update();
            Repaint(NULL);
        }
    }

...


Best regards,
Rick
Rick
Registered User
 
Posts: 2
Joined: Sat Nov 24, 2007 10:53 am

Re: Dock and Pane Resizing

Postby ebf on Tue Nov 27, 2007 9:00 am

Hi Rick,

Great Patch! Thanks for the effort! :)

Cheers!

Eduardo.
ebf
Registered User
 
Posts: 1
Joined: Wed Aug 15, 2007 12:14 pm

Re: Dock and Pane Resizing

Postby Ben on Mon Dec 10, 2007 4:17 am

Thanks for the patch. I will be looking at this in detail soon.

Best,
Ben
Ben Williams
Kirix Support Team
User avatar
Ben
Kirix Support Team
 
Posts: 525
Joined: Mon Dec 19, 2005 6:29 am

Re: Dock and Pane Resizing

Postby Kerantino on Fri Mar 02, 2012 6:11 am

I ended up ditching the XtraBars toolbar that was inside the dockpanel, and once I did that the width of the dockpanel could be changed just fine.
Kerantino
Registered User
 
Posts: 3
Joined: Fri Mar 02, 2012 4:47 am

Return to wxAUI Patches & Modifications