Kirix Support Forums

Patch concerning dock resizing

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

Patch concerning dock resizing

Postby seand on Fri Mar 14, 2008 11:57 pm

This is a modification of Rick's patch, which was submitted here:

viewtopic.php?f=16&t=582

I was having trouble with dock resizing in my application and found his patch on the forums; I was a bit upset that it hadn't been integrated into the current build of wxWidgets, but even when I added his modifications, I found it didn't fully fix the all bugs. I believe he completely fixed the first bug he mentioned, about the position of the sash while dragging to resize a dock or pane, but I'll discuss his other changes below:

1) One of the biggest bugs was, in general, the fact that dock sizes weren't being correctly restricted (whether a minimum size was set or not). That is, a dock size could be greater than the maximum (based on the opposite-sided dock sizes) or below the minimum as set by OnLeftUp(). I tried to fix this in each dock case by creating minimum and maximum values, and then using wxClip to ensure that new_pos didn't go beyond them. In the top and bottom docks, I ensured the minimum dock size (of the dock that was being manipulated) was respected by adding in any caption and pane border sizes. In the left and right docks, I ensured this by adding in the size of each button that was present (if there was a caption), pane border sizes, and a seemingly arbitrary value of 3. I found this value from guessing and checking how big the minimum dock sizes were due to a button being present in the caption. I first tried looking in Update() and LayoutAll() to try to find the real value used for determining the minimum size for drawing, but I couldn't find it so I just played around and came up with that (and it seems to work).

2) Another bug occurred when trying to resize a dock all the way so that the center pane was no longer visible (so it would need accurate values for the opposite docks' sizes). Rick had the right idea here, and I just added in sash sizes for each additional dock on the opposite side (unless it was a toolbar).

3) Another thing was that when resizing a dock, any docks that were below it in layer or the same in layer but greater in row (any docks that were in between the dock being resized and the center pane) were also included in opposite_size calculations.

Those are the two basic bugs I tried to fix; I wanted to get to the minimum and maximum sizes of panes and docks, but as I said in the other thread, I won't have much time and it seems like a fairly complicated matter that depends mostly on how the developers feel about it. So I'll list what I noted but didn't try to fix:

- resizing panes that have buttons aren't restricted by those buttons like dock resizing is, so there are bugs in the display where two panes' buttons will overlap
- a horizontal minimum pane size in the center dock is respected, but not a vertical one; this is because the center dock is internally recognized as a vertical dock direction, and I noticed Rick tried to enforce it anyway in his patch by adding in the min_size of the center dock; I edited it to only add that size in if the dock being resized was a vertical one (because otherwise the horizontal minimum size of the center dock would be the same as the vertical one)
- in addition to the center pane's minimum sizes when resizing a dock, another important aspect to note is the minimum sizes of panes in the docks that are its complement; in other words, if we're resizing a dock on the bottom, we have to be wary of pane minimums in the left and right docks as well
- as Rick mentioned in his post, frame resizing raises some additional issues

Here's the code for my patch (I marked everything I changed around on top of Rick's changes):

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

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

      // resize a dock
      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);

         // seand: begin added
         int sash_size = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE);
         int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE);
         int pane_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
         int pane_button_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BUTTON_SIZE);
         // seand: end added

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

         // seand: begin modified
         // Get minimum size of content area (if it's a vertical dock being resized)
         if(m_action_part->dock->IsVertical())
         {
            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;
            }
         }
         // seand: end modified

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

         // seand: begin modified
         // Sum size of the opposite docks and their sashes
         for (i = 0; i < opposite_docks.GetCount(); ++i)
         {
            opposite_size += opposite_docks.Item(i)->size;
            
            // if it's not a toolbar add the sash_size too
            if(!opposite_docks.Item(i)->toolbar)
               opposite_size += sash_size;
         }
         // seand: end modified
         //Rick: End Added

         // seand: begin added
         //
         // get the size of all the docks that are between m_action_part's dock and the center
         FindDocks(m_docks, m_action_part->dock->dock_direction, -1, -1, opposite_docks);
         for(i = 0; i < opposite_docks.GetCount(); ++i)
         {
            wxAuiDockInfo &dock = *opposite_docks.Item(i);
            // if the dock layer is less than m_action_part's dock layer, add the size
            if(dock.dock_layer < m_action_part->dock->dock_layer)
            {
               opposite_size += dock.size + sash_size;
            }
            // if the dock layers are equal but the dock row is greater than m_action_part's dock row,
            // add the size
            else if(dock.dock_layer == m_action_part->dock->dock_layer)
            {
               if(dock.dock_row > m_action_part->dock->dock_row)
               {
                  opposite_size += dock.size + sash_size;
               }
            }
         }

         int min_y, max_y;
         int min_x, max_x;
         // seand: end added
         
         switch (m_action_part->dock->dock_direction)
         {
            case wxAUI_DOCK_LEFT:
               // seand: begin added
               //
               // we add 1 to ensure that the dock size is never 0, because
               // if it is then LayoutAll() thinks it's being created and it messes up
               min_x = rect.x + 1;
               for(i = 0; i < m_action_part->dock->panes.GetCount(); ++i)
               {
                  wxAuiPaneInfo &pane = *m_action_part->dock->panes.Item(i);
                  
                  // if any pane in the dock has a caption or border, add it in to the minimum,
                  // because it's going to be shown there anyway with LayoutAll() from Update()
                  if(pane.HasCaption() || pane.HasBorder())
                  {
                     // if it has a caption we check for any buttons
                     if(pane.HasCaption())
                     {
                        if(pane.HasCloseButton()
                           || pane.HasMaximizeButton()
                           || pane.HasPinButton())
                        {
                           // i need to hardcode this because of how wxAui displays
                           // its buttons (adds on 3 pixels in width if there are buttons,
                           // as opposed to no buttons)
                           min_x += 3;

                           if(pane.HasCloseButton())
                              min_x += pane_button_size;

                           if(pane.HasMaximizeButton())
                              min_x += pane_button_size;

                           if(pane.HasPinButton())
                              min_x += pane_button_size;
                        }
                     }
                     
                     if(pane.HasBorder())
                        min_x += pane_border_size * 2;
                     
                     break;
                  }
               }
               max_x = cli_size.x - opposite_size - sash_size;
               new_pos.x = wxClip(new_pos.x, min_x, max_x);
               // seand: end added

               m_action_part->dock->size = new_pos.x - rect.x;
               break;
            case wxAUI_DOCK_TOP:
               // seand: begin added
               //
               // we add 1 to ensure that the dock size is never 0, because
               // if it is then LayoutAll() thinks it's being created and it messes up
               min_y = rect.y + 1;
               for(i = 0; i < m_action_part->dock->panes.GetCount(); ++i)
               {
                  wxAuiPaneInfo &pane = *m_action_part->dock->panes.Item(i);
                  
                  // if any pane in the dock has a caption or border, add it in to the minimum,
                  // because it's going to be shown there anyway with LayoutAll() from Update()
                  if(pane.HasCaption() ||   pane.HasBorder())
                  {
                     if(pane.HasCaption())
                        min_y += caption_size;
                     
                     if(pane.HasBorder())
                        min_y += pane_border_size * 2;
                     
                     break;
                  }
               }
               max_y = cli_size.y - opposite_size - sash_size;
               new_pos.y = wxClip(new_pos.y, min_y, max_y);
               // seand: end added

               m_action_part->dock->size = new_pos.y - rect.y;
               break;
            case wxAUI_DOCK_RIGHT:
               // seand: begin added
               //
               // we subtract 1 to ensure that the dock size is never 0, because
               // if it is then LayoutAll() thinks it's being created and it messes up
               max_x = rect.x + rect.width - sash_size - 1;
               for(i = 0; i < m_action_part->dock->panes.GetCount(); ++i)
               {
                  wxAuiPaneInfo &pane = *m_action_part->dock->panes.Item(i);
                  
                  // if any pane in the dock has a caption or border, add it in to the minimum,
                  // because it's going to be shown there anyway with LayoutAll() from Update()
                  if(pane.HasCaption() || pane.HasBorder())
                  {
                     // if it has a caption we check for any buttons
                     if(pane.HasCaption())
                     {
                        if(pane.HasCloseButton()
                           || pane.HasMaximizeButton()
                           || pane.HasPinButton())
                        {
                           // i need to hardcode this because of how wxAui displays
                           // its buttons (adds on 3 pixels in width if there are buttons,
                           // as opposed to no buttons)
                           max_x -= 3;

                           if(pane.HasCloseButton())
                              max_x -= pane_button_size;

                           if(pane.HasMaximizeButton())
                              max_x -= pane_button_size;

                           if(pane.HasPinButton())
                              max_x -= pane_button_size;
                        }
                     }
                     
                     if(pane.HasBorder())
                        max_x -= pane_border_size * 2;
                     
                     break;
                  }
               }
               min_x = opposite_size;
               new_pos.x = wxClip(new_pos.x, min_x, max_x);
               // seand: end added

               // seand: line modified (might as well be consistent and not confusing)
               m_action_part->dock->size = rect.x + rect.width - new_pos.x - sash_size;
               break;
            case wxAUI_DOCK_BOTTOM:
               // seand: begin added
               //
               // we subtract 1 to ensure that the dock size is never 0, because
               // if it is then LayoutAll() thinks it's being created and it messes up
               max_y = rect.y + rect.height - sash_size - 1;
               for(i = 0; i < m_action_part->dock->panes.GetCount(); ++i)
               {
                  // if any pane in the dock has a caption or border, add it in to the minimum,
                  // because it's going to be shown there anyway with LayoutAll() from Update()
                  if(m_action_part->dock->panes.Item(i)->HasCaption() ||
                     m_action_part->dock->panes.Item(i)->HasBorder())
                  {
                     if(m_action_part->dock->panes.Item(i)->HasCaption())
                        max_y -= caption_size;
                     if(m_action_part->dock->panes.Item(i)->HasBorder())
                        max_y -= pane_border_size * 2;
                     
                     break;
                  }
               }
               min_y = opposite_size;
               new_pos.y = wxClip(new_pos.y, min_y, max_y);
               // seand: end added

               // seand: line modified (might as well be consistent and not confusing)
               m_action_part->dock->size = rect.y + rect.height - new_pos.y - sash_size;
               break;
         }

         Update();
         Repaint(NULL);
      }
      // resize a pane
      else if (m_action_part && m_action_part->type == wxAuiDockUIPart::typePaneSizer)
      {

...


- seand
seand
Registered User
 
Posts: 6
Joined: Thu Mar 13, 2008 3:09 pm

Re: Patch concerning dock resizing

Postby seand on Tue Mar 18, 2008 3:24 pm

Here's a copy of the auidemo binary with this patch integrated in (only through wxAuiManager, not the notebook). You can notice some differences from the original by just playing around with the dock sashes. The best way to do that is to go to Perspectives -> All Panes in the menu.

auidemo.zip
(638.57 KiB) Downloaded 1203 times
seand
Registered User
 
Posts: 6
Joined: Thu Mar 13, 2008 3:09 pm

Re: Patch concerning dock resizing

Postby Dave on Wed Mar 19, 2008 10:10 pm

Thanks for submitting this patch! We'll take a look at it in the next couple of days...

All the best,
Dave.
Dave Williams
Kirix Support Team
User avatar
Dave
Kirix Support Team
 
Posts: 32
Joined: Wed Sep 21, 2005 11:07 pm

Re: Patch concerning dock resizing

Postby seand on Thu Mar 20, 2008 10:44 pm

all right, thanks, i appreciate it
seand
Registered User
 
Posts: 6
Joined: Thu Mar 13, 2008 3:09 pm

Re: Patch concerning dock resizing

Postby Rick on Sat Apr 05, 2008 8:01 am

Great to see that this patch lives on. I performed some test with it and the results are definitely better than with the old version.
After posting my original patch, I realized the issue of the complement docks. I tried to fix it, but I was not able to figure out how to detect which dock (horizontal or vertical) takes the corner of a layer. Therefore I could not determine which complement docks resize together with the dock being resized by the user.
Also there is still an issue with dropping new docks. It's possible that a new dock resizes existing docks to below their minimum size. I think that in such cases dropping the dock should be denied, also the drop hint should not be drawn. I never looked into this because it considers a totally different piece of code.
Rick
Registered User
 
Posts: 2
Joined: Sat Nov 24, 2007 10:53 am

Re: Patch concerning dock resizing

Postby Dave on Sat Apr 05, 2008 7:36 pm

Hi all,

Just wanted to touch base with everyone. We haven't had a chance to take a look at the patch as of yet. We plan on looking at it sometime around mid-April. Thanks for your patience.

All the best,
Dave.
Dave Williams
Kirix Support Team
User avatar
Dave
Kirix Support Team
 
Posts: 32
Joined: Wed Sep 21, 2005 11:07 pm

Re: Patch concerning dock resizing

Postby seand on Sun Apr 06, 2008 10:18 am

all right, thanks Dave

i noticed that dropping panes issue, too, Rick, but i had the same idea in that it was a whole different thing to mess around with.

I tried to fix it, but I was not able to figure out how to detect which dock (horizontal or vertical) takes the corner of a layer.


i had messed around with the AUI sample and found out that the horizontal takes precedence over the vertical when the docks are the same row and layer as one another. i knew this when i was adding to the patch, but i don't think i added it in, because i didn't check for buttons or captions in panes like i did for panes in the dock being resized.
seand
Registered User
 
Posts: 6
Joined: Thu Mar 13, 2008 3:09 pm

Return to wxAUI Patches & Modifications