distribute only the extra, free, space according to the items proportions in wxBoxSizer and not the entire available space

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@45577 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2007-04-22 12:50:01 +00:00
parent 55bfbcb92b
commit 8906471733
3 changed files with 158 additions and 189 deletions

View File

@@ -19,6 +19,13 @@ Changes in behaviour not resulting in compilation errors, please read this!
other platforms in the future), use wxWindow::Navigate() or NavigateIn() other platforms in the future), use wxWindow::Navigate() or NavigateIn()
instead. instead.
- Sizers distribute only the extra space between the stretchable items
according to their proportions and not all available space. We believe the
new behaviour corresponds better to user expectations but if you did rely
on the old behaviour you will have to update your code to set the minimal
sizes of the sizer items to be in the same proportion as the items
proportions to return to the old behaviour.
Changes in behaviour which may result in compilation errors Changes in behaviour which may result in compilation errors
----------------------------------------------------------- -----------------------------------------------------------

View File

@@ -73,7 +73,7 @@ public:
} }
// some shortcuts for Align() // some shortcuts for Align()
wxSizerFlags& Centre() { return Align(wxCENTRE); } wxSizerFlags& Centre() { return Align(wxALIGN_CENTRE); }
wxSizerFlags& Center() { return Centre(); } wxSizerFlags& Center() { return Centre(); }
wxSizerFlags& Top() { return Align(wxALIGN_TOP); } wxSizerFlags& Top() { return Align(wxALIGN_TOP); }
wxSizerFlags& Left() { return Align(wxALIGN_LEFT); } wxSizerFlags& Left() { return Align(wxALIGN_LEFT); }
@@ -569,8 +569,12 @@ public:
// Calculate the minimal size or return m_minSize if bigger. // Calculate the minimal size or return m_minSize if bigger.
wxSize GetMinSize(); wxSize GetMinSize();
virtual void RecalcSizes() = 0; // These virtual functions are used by the layout algorithm: first
// CalcMin() is called to calculate the minimal size of the sizer and
// prepare for laying it out and then RecalcSizes() is called to really
// update all the sizer items
virtual wxSize CalcMin() = 0; virtual wxSize CalcMin() = 0;
virtual void RecalcSizes() = 0;
virtual void Layout(); virtual void Layout();
@@ -765,24 +769,80 @@ private:
class WXDLLEXPORT wxBoxSizer: public wxSizer class WXDLLEXPORT wxBoxSizer: public wxSizer
{ {
public: public:
wxBoxSizer( int orient ); wxBoxSizer(int orient)
{
m_orient = orient;
void RecalcSizes(); wxASSERT_MSG( m_orient == wxHORIZONTAL || m_orient == wxVERTICAL,
wxSize CalcMin(); _T("invalid value for wxBoxSizer orientation") );
}
int GetOrientation() const int GetOrientation() const { return m_orient; }
{ return m_orient; }
void SetOrientation(int orient) bool IsVertical() const { return m_orient == wxVERTICAL; }
{ m_orient = orient; }
void SetOrientation(int orient) { m_orient = orient; }
// implementation of our resizing logic
virtual wxSize CalcMin();
virtual void RecalcSizes();
protected: protected:
// helpers for our code: this returns the component of the given wxSize in
// the direction of the sizer and in the other direction, respectively
int SizeInMajorDir(const wxSize& sz) const
{
return m_orient == wxHORIZONTAL ? sz.x : sz.y;
}
int& SizeInMajorDir(wxSize& sz)
{
return m_orient == wxHORIZONTAL ? sz.x : sz.y;
}
int& PosInMajorDir(wxPoint& pt)
{
return m_orient == wxHORIZONTAL ? pt.x : pt.y;
}
int SizeInMinorDir(const wxSize& sz) const
{
return m_orient == wxHORIZONTAL ? sz.y : sz.x;
}
int& SizeInMinorDir(wxSize& sz)
{
return m_orient == wxHORIZONTAL ? sz.y : sz.x;
}
int& PosInMinorDir(wxPoint& pt)
{
return m_orient == wxHORIZONTAL ? pt.y : pt.x;
}
// another helper: creates wxSize from major and minor components
wxSize SizeFromMajorMinor(int major, int minor) const
{
if ( m_orient == wxHORIZONTAL )
{
return wxSize(major, minor);
}
else // wxVERTICAL
{
return wxSize(minor, major);
}
}
// either wxHORIZONTAL or wxVERTICAL
int m_orient; int m_orient;
int m_stretchable;
int m_minWidth; // the sum of proportion of all of our elements
int m_minHeight; int m_totalProportion;
int m_fixedWidth;
int m_fixedHeight; // the minimal size needed for this sizer as calculated by the last call to
// our CalcMin()
wxSize m_minSize;
private: private:
DECLARE_CLASS(wxBoxSizer) DECLARE_CLASS(wxBoxSizer)

View File

@@ -1628,204 +1628,106 @@ void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
// wxBoxSizer // wxBoxSizer
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
wxBoxSizer::wxBoxSizer( int orient )
: m_orient( orient )
{
}
void wxBoxSizer::RecalcSizes() void wxBoxSizer::RecalcSizes()
{ {
if (m_children.GetCount() == 0) if ( m_children.empty() )
return; return;
int delta = 0; // the amount of free space which we should redistribute among the
if (m_stretchable) // stretchable items (i.e. those with non zero proportion)
const int delta = SizeInMajorDir(m_size) - SizeInMajorDir(m_minSize);
// the position at which we put the next child
wxPoint pt(m_position);
const wxCoord totalMinorSize = SizeInMinorDir(m_size);
for ( wxSizerItemList::const_iterator i = m_children.begin();
i != m_children.end();
++i )
{ {
if (m_orient == wxHORIZONTAL) wxSizerItem * const item = *i;
delta = m_size.x - m_fixedWidth;
else
delta = m_size.y - m_fixedHeight;
}
wxPoint pt( m_position ); if ( !item->IsShown() )
continue;
wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); const wxSize sizeThis(item->GetMinSizeWithBorder());
while (node)
{
wxSizerItem *item = node->GetData();
if (item->IsShown())
// adjust the size in the major direction using the proportion
wxCoord majorSize = SizeInMajorDir(sizeThis);
if ( item->GetProportion() )
{ {
wxSize size( item->GetMinSizeWithBorder() ); // as at least one visible item has non-zero proportion the total
// proportion must be non zero
if (m_orient == wxVERTICAL) majorSize += (delta * item->GetProportion()) / m_totalProportion;
{
wxCoord height = size.y;
if (item->GetProportion())
{
// Because of at least one visible item has non-zero
// proportion then m_stretchable is not zero
height = (delta * item->GetProportion()) / m_stretchable;
}
wxPoint child_pos( pt );
wxSize child_size( size.x, height );
if (item->GetFlag() & (wxEXPAND | wxSHAPED))
child_size.x = m_size.x;
else if (item->GetFlag() & wxALIGN_RIGHT)
child_pos.x += m_size.x - size.x;
else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
// XXX wxCENTER is added for backward compatibility;
// wxALIGN_CENTER should be used in new code
child_pos.x += (m_size.x - size.x) / 2;
item->SetDimension( child_pos, child_size );
pt.y += height;
}
else
{
wxCoord width = size.x;
if (item->GetProportion())
{
// Because of at least one visible item has non-zero
// proportion then m_stretchable is not zero
width = (delta * item->GetProportion()) / m_stretchable;
}
wxPoint child_pos( pt );
wxSize child_size( width, size.y );
if (item->GetFlag() & (wxEXPAND | wxSHAPED))
child_size.y = m_size.y;
else if (item->GetFlag() & wxALIGN_BOTTOM)
child_pos.y += m_size.y - size.y;
else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
// XXX wxCENTER is added for backward compatibility;
// wxALIGN_CENTER should be used in new code
child_pos.y += (m_size.y - size.y) / 2;
if ( m_containingWindow )
{
child_pos.x = m_containingWindow->AdjustForLayoutDirection
(
child_pos.x,
width,
m_size.x
);
}
item->SetDimension( child_pos, child_size );
pt.x += width;
}
} }
node = node->GetNext();
// apply the alignment in the minor direction
wxPoint posChild(pt);
wxCoord minorSize = SizeInMinorDir(sizeThis);
const int flag = item->GetFlag();
if ( flag & (wxEXPAND | wxSHAPED) )
{
minorSize = totalMinorSize;
}
else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
{
PosInMinorDir(posChild) += totalMinorSize - minorSize;
}
// NB: wxCENTRE is used here only for backwards compatibility,
// wxALIGN_CENTRE should be used in new code
else if ( flag & (wxCENTER | wxALIGN_CENTRE) )
{
PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
}
// apply RTL adjustment for horizontal sizers:
if ( !IsVertical() && m_containingWindow )
{
posChild.x = m_containingWindow->AdjustForLayoutDirection
(
posChild.x,
majorSize,
m_size.x
);
}
// finally set size of this child and advance to the next one
item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
PosInMajorDir(pt) += majorSize;
} }
} }
wxSize wxBoxSizer::CalcMin() wxSize wxBoxSizer::CalcMin()
{ {
if (m_children.GetCount() == 0) m_totalProportion = 0;
return wxSize(); m_minSize = wxSize(0, 0);
m_stretchable = 0; // calculate the minimal sizes for all items and count sum of proportions
m_minWidth = 0; for ( wxSizerItemList::const_iterator i = m_children.begin();
m_minHeight = 0; i != m_children.end();
m_fixedWidth = 0; ++i )
m_fixedHeight = 0;
// precalc item minsizes and count proportions
wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
while (node)
{ {
wxSizerItem *item = node->GetData(); wxSizerItem * const item = *i;
if ( item->IsShown() ) if ( !item->IsShown() )
{ continue;
item->CalcMin(); // result is stored in the item
m_stretchable += item->GetProportion(); const wxSize sizeMinThis = item->CalcMin();
}
node = node->GetNext(); SizeInMajorDir(m_minSize) += SizeInMajorDir(sizeMinThis);
if ( SizeInMinorDir(sizeMinThis) > SizeInMinorDir(m_minSize) )
SizeInMinorDir(m_minSize) = SizeInMinorDir(sizeMinThis);
m_totalProportion += item->GetProportion();
} }
// Total minimum size (width or height) of sizer return m_minSize;
int maxMinSize = 0;
node = m_children.GetFirst();
while (node)
{
wxSizerItem *item = node->GetData();
if (item->IsShown() && item->GetProportion() != 0)
{
int stretch = item->GetProportion();
wxSize size( item->GetMinSizeWithBorder() );
int minSize;
// Integer division rounded up is (a + b - 1) / b
// Round up needed in order to guarantee that all
// all items will have size not less then their min size
if (m_orient == wxHORIZONTAL)
minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
else
minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
if (minSize > maxMinSize)
maxMinSize = minSize;
}
node = node->GetNext();
}
// Calculate overall minimum size
node = m_children.GetFirst();
while (node)
{
wxSizerItem *item = node->GetData();
if (item->IsShown())
{
wxSize size( item->GetMinSizeWithBorder() );
if (item->GetProportion() != 0)
{
if (m_orient == wxHORIZONTAL)
size.x = (maxMinSize*item->GetProportion())/m_stretchable;
else
size.y = (maxMinSize*item->GetProportion())/m_stretchable;
}
else
{
if (m_orient == wxVERTICAL)
{
m_fixedHeight += size.y;
m_fixedWidth = wxMax( m_fixedWidth, size.x );
}
else
{
m_fixedWidth += size.x;
m_fixedHeight = wxMax( m_fixedHeight, size.y );
}
}
if (m_orient == wxHORIZONTAL)
{
m_minWidth += size.x;
m_minHeight = wxMax( m_minHeight, size.y );
}
else
{
m_minHeight += size.y;
m_minWidth = wxMax( m_minWidth, size.x );
}
}
node = node->GetNext();
}
return wxSize( m_minWidth, m_minHeight );
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------