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