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()
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
-----------------------------------------------------------

View File

@@ -73,7 +73,7 @@ public:
}
// some shortcuts for Align()
wxSizerFlags& Centre() { return Align(wxCENTRE); }
wxSizerFlags& Centre() { return Align(wxALIGN_CENTRE); }
wxSizerFlags& Center() { return Centre(); }
wxSizerFlags& Top() { return Align(wxALIGN_TOP); }
wxSizerFlags& Left() { return Align(wxALIGN_LEFT); }
@@ -569,8 +569,12 @@ public:
// Calculate the minimal size or return m_minSize if bigger.
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 void RecalcSizes() = 0;
virtual void Layout();
@@ -765,24 +769,80 @@ private:
class WXDLLEXPORT wxBoxSizer: public wxSizer
{
public:
wxBoxSizer( int orient );
wxBoxSizer(int orient)
{
m_orient = orient;
void RecalcSizes();
wxSize CalcMin();
wxASSERT_MSG( m_orient == wxHORIZONTAL || m_orient == wxVERTICAL,
_T("invalid value for wxBoxSizer orientation") );
}
int GetOrientation() const
{ return m_orient; }
int GetOrientation() const { return m_orient; }
void SetOrientation(int orient)
{ m_orient = orient; }
bool IsVertical() const { return m_orient == wxVERTICAL; }
void SetOrientation(int orient) { m_orient = orient; }
// implementation of our resizing logic
virtual wxSize CalcMin();
virtual void RecalcSizes();
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_stretchable;
int m_minWidth;
int m_minHeight;
int m_fixedWidth;
int m_fixedHeight;
// the sum of proportion of all of our elements
int m_totalProportion;
// the minimal size needed for this sizer as calculated by the last call to
// our CalcMin()
wxSize m_minSize;
private:
DECLARE_CLASS(wxBoxSizer)

View File

@@ -1628,204 +1628,106 @@ void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
// wxBoxSizer
//---------------------------------------------------------------------------
wxBoxSizer::wxBoxSizer( int orient )
: m_orient( orient )
{
}
void wxBoxSizer::RecalcSizes()
{
if (m_children.GetCount() == 0)
if ( m_children.empty() )
return;
int delta = 0;
if (m_stretchable)
// the amount of free space which we should redistribute among the
// 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)
delta = m_size.x - m_fixedWidth;
else
delta = m_size.y - m_fixedHeight;
wxSizerItem * const item = *i;
if ( !item->IsShown() )
continue;
const wxSize sizeThis(item->GetMinSizeWithBorder());
// adjust the size in the major direction using the proportion
wxCoord majorSize = SizeInMajorDir(sizeThis);
if ( item->GetProportion() )
{
// as at least one visible item has non-zero proportion the total
// proportion must be non zero
majorSize += (delta * item->GetProportion()) / m_totalProportion;
}
wxPoint pt( m_position );
wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
wxSizerItem *item = node->GetData();
// apply the alignment in the minor direction
wxPoint posChild(pt);
if (item->IsShown())
wxCoord minorSize = SizeInMinorDir(sizeThis);
const int flag = item->GetFlag();
if ( flag & (wxEXPAND | wxSHAPED) )
{
wxSize size( item->GetMinSizeWithBorder() );
if (m_orient == wxVERTICAL)
minorSize = totalMinorSize;
}
else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
{
wxCoord height = size.y;
if (item->GetProportion())
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) )
{
// Because of at least one visible item has non-zero
// proportion then m_stretchable is not zero
height = (delta * item->GetProportion()) / m_stretchable;
PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
}
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
// apply RTL adjustment for horizontal sizers:
if ( !IsVertical() && m_containingWindow )
{
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
posChild.x = m_containingWindow->AdjustForLayoutDirection
(
child_pos.x,
width,
posChild.x,
majorSize,
m_size.x
);
}
item->SetDimension( child_pos, child_size );
// finally set size of this child and advance to the next one
item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
pt.x += width;
}
}
node = node->GetNext();
PosInMajorDir(pt) += majorSize;
}
}
wxSize wxBoxSizer::CalcMin()
{
if (m_children.GetCount() == 0)
return wxSize();
m_totalProportion = 0;
m_minSize = wxSize(0, 0);
m_stretchable = 0;
m_minWidth = 0;
m_minHeight = 0;
m_fixedWidth = 0;
m_fixedHeight = 0;
// precalc item minsizes and count proportions
wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
while (node)
// calculate the minimal sizes for all items and count sum of proportions
for ( wxSizerItemList::const_iterator i = m_children.begin();
i != m_children.end();
++i )
{
wxSizerItem *item = node->GetData();
wxSizerItem * const item = *i;
if ( item->IsShown() )
{
item->CalcMin(); // result is stored in the item
if ( !item->IsShown() )
continue;
m_stretchable += item->GetProportion();
const wxSize sizeMinThis = item->CalcMin();
SizeInMajorDir(m_minSize) += SizeInMajorDir(sizeMinThis);
if ( SizeInMinorDir(sizeMinThis) > SizeInMinorDir(m_minSize) )
SizeInMinorDir(m_minSize) = SizeInMinorDir(sizeMinThis);
m_totalProportion += item->GetProportion();
}
node = node->GetNext();
}
// Total minimum size (width or height) of sizer
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 );
return m_minSize;
}
//---------------------------------------------------------------------------