wxAuiToolBar's overflow function cannot work as expected, when as pane in wxAuiManager, on GTK.
当增加一个AuiToolBar到一个auimanager之后,如果想用它的overflow feature,在gtk平台,无法工作。 WHY?
1) 首先查看wxAuiToolBar的OnSize函数做了些什么事情:
<!-- lang: cpp -->
void wxAuiToolBar:: OnSize(wxSizeEvent & WXUNUSED (evt))
{
int x , y;
GetClientSize(&x , &y);
if (x > y)
SetOrientation(wxHORIZONTAL );
else
SetOrientation(wxVERTICAL );
if (((x >= y) && m_absolute_min_size .x > x) ||
(( y > x ) && m_absolute_min_size.y > y))
{
// hide all flexible items
size_t i , count;
for (i = 0, count = m_items.GetCount (); i < count; ++i )
{
wxAuiToolBarItem& item = m_items. Item(i );
if (item .sizer_item && item.proportion > 0 && item .sizer_item-> IsShown())
{
item.sizer_item ->Show( false);
item.sizer_item ->SetProportion(0);
}
}
}
else
{
// show all flexible items
size_t i , count;
for (i = 0, count = m_items.GetCount (); i < count; ++i )
{
wxAuiToolBarItem& item = m_items. Item(i );
if (item .sizer_item && item.proportion > 0 && !item .sizer_item-> IsShown())
{
item.sizer_item ->Show( true);
item.sizer_item ->SetProportion( item.proportion );
}
}
}
m_sizer->SetDimension (0, 0, x, y);
Refresh(false );
Update();
}
可以看到函数对一些tool button做了show/hide设置。
然后设置断点,跟踪每次size时, x/y计算出来的值是多少。发现它始终就没变过,不管如何resize那个toolbar
2) 不从ClientSize里面获取x/y值,从evt参数中拿值。看下上层代码是如何给它值。发现下面函数触发OnSize函数调用:
void wxAuiToolBar:: DoSetSize(int x,
int y ,
int width ,
int height ,
int sizeFlags )
{
wxSize parent_size = GetParent()-> GetClientSize();
if (x + width > parent_size.x )
width = wxMax (0, parent_size. x - x );
if (y + height > parent_size.y )
height = wxMax (0, parent_size. y - y );
wxWindow::DoSetSize (x, y, width , height, sizeFlags);
}
跟踪发现width/height确实是更改过的值,但是在wxWindow::DoSetSize函数中,但是gtk版本的DoSetSize函数(src/gtk/window.cpp: 2712行),对width/height进行了进一步的处理。在函数最后处理size事件
<!-- lang: cpp -->
2829 if (!m_nativeSizeEvent)
2830 {
2831 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2832 event.SetEventObject( this );
2833 GetEventHandler()->ProcessEvent( event );
2834 }
跟踪发现m_width/m_height,确实在函数内部以下代码段中更改了。
<!-- lang: cpp -->
2744 int minWidth = GetMinWidth(),
2745 minHeight = GetMinHeight(),
2746 maxWidth = GetMaxWidth(),
2747 maxHeight = GetMaxHeight();
2748
2749 if ((minWidth != -1) && (m_width < minWidth )) m_width = minWidth;
2750 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
2751 if ((maxWidth != -1) && (m_width > maxWidth )) m_width = maxWidth;
2752 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
GetMinWidth函数调用GetMinSize函数获取widht。跟踪发现这个minsize失踪是toolbar最初显示出来的size。我们并没有设置它的minsize啊?是谁在其间调用了SetMinSize函数设置其值了?
3) GDB断点跟踪发现,在auimanager的Update函数中调用了Sizer的SetItemMinSize函数,进而调用了toolbar的SetMinSize函数:
<!-- lang: cpp -->
1658 void wxAuiManager::LayoutAddPane(wxSizer* cont,
1659 wxAuiDockInfo& dock,
1660 wxAuiPaneInfo& pane,
1661 wxAuiDockUIPartArray& uiparts,
1662 bool spacer_only)
...
1779 // determine if the pane should have a minimum size; if the pane is
1780 // non-resizable (fixed) then we must set a minimum size. Alternatively,
1781 // if the pane.min_size is set, we must use that value as well
1782
1783 wxSize min_size = pane.min_size;
1784 if (pane.IsFixed())
1785 {
1786 if (min_size == wxDefaultSize)
1787 {
1788 min_size = pane.best_size;
1789 pane_proportion = 0;
1790 }
1791 }
1792
1793 if (min_size != wxDefaultSize)
1794 {
1795 vert_pane_sizer->SetItemMinSize(
1796 vert_pane_sizer->GetChildren().GetCount()-1,
1797 min_size.x, min_size.y);
1798 }
我们的toolbar是一个fixed的pane,开始时并没有设置它的min size,所以1788行将会设置为best size,而best size将会是初始化时的size。这样1795行将会被调用到,而且是以best size的值来调用。
4) 找到根源之后,如何修改?
最简单的方式是在auimanager.AddPane调用增加toolbar时,设置它的minsize为一个tool button的size。这个size可以从toolbar提供的接口获取到。