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