[Libreoffice-commits] .: Branch 'feature/layout' - README.layout vcl/inc vcl/source

Ricardo Cruz rpmcruz at kemper.freedesktop.org
Sun Dec 19 12:36:50 PST 2010


 README.layout                   |   47 ++++++++++-
 vcl/inc/vcl/ldialog.hxx         |   10 +-
 vcl/inc/vcl/notebook.hxx        |    9 +-
 vcl/inc/vcl/table.hxx           |   17 +---
 vcl/source/layout/align.cxx     |    2 
 vcl/source/layout/box.cxx       |    6 -
 vcl/source/layout/buttonbox.cxx |    2 
 vcl/source/layout/layout.cxx    |   43 ++++++----
 vcl/source/layout/ldialog.cxx   |   52 +++++++++----
 vcl/source/layout/notebook.cxx  |    7 +
 vcl/source/layout/table.cxx     |  158 +++++++++++++++++++++++++++-------------
 11 files changed, 240 insertions(+), 113 deletions(-)

New commits:
commit fe5298f347de53f489a786a6f3dc078b4c5ff8fa
Author: Ricardo Cruz <rpmcruz at alunos.dcc.fc.up.pt>
Date:   Sun Dec 19 20:35:21 2010 +0000

    Fixed LDialog layout bugs | Improved Table: better space use by multi-span...

diff --git a/README.layout b/README.layout
index ae85721..6eaa501 100644
--- a/README.layout
+++ b/README.layout
@@ -1,4 +1,33 @@
-~ TODO ~
+OVERVIEW                               -=-=-=-=-=-=-=-=-=
+
+Welcome to the feature/layout branch!
+
+The idea here is to introduce logic layout containers
+(ie. Boxes, Tables) to VCL, so that we no longer need
+to manually place widgets using absolute coordinates.
+
+There are a few advantages to that approach. But mostly
+it makes it easier to re-design libreoffice dialogs.
+Especially once we introduce a XML parser and an UI editor.
+
+There was already a first attempt at this. That code is
+under toolkit/source/layout. What's new here is that we
+will be re-implementing this one at the VCL level, which
+should hopefully make it much easier to integrate with the
+existing dialogs.
+
+COMPILING                               -=-=-=-=-=-=-=-=-=
+
+Run the following, from a working build:
+
+./g checkout feature/layout
+./g pull -r
+make
+
+To get a working build, consult:
+http://www.documentfoundation.org/develop/
+
+TODO: Dynamic layout                   -=-=-=-=-=-=-=-=-=
 
 * Make Window an implementation of a Layout (or Widget?)
   interface. Notice that Window and Layout use different
@@ -14,8 +43,11 @@
 * Announcement: try to get people to
   do some dialog porting.
 
+TODO: Desktop integration               -=-=-=-=-=-=-=-=-=
 
-~ TODO: side adventures ~
+These points aren't crucial for the main effort, but it would
+be nice to get these points addressed, and they should be fairly
+trivial nevertheless.
 
 * Integration code should return a ButtonOrder with the
   appropriate spec (see buttonbox.hxx)
@@ -28,9 +60,14 @@
   bold font for the selected tab page: replace that by
   gray-ing out the inactive tabs. Offset inactive tab label
   content if we aren't doing that already.
-
-
-~ HACKING HOWTO ~
+* Buttons flicker quite a bit on focus-in and focus-out.
+* Button: shouldn't be possible to create an instance of
+  this base class: only of PushButton or whatever. The
+  names are too similar and you can easily use Button
+  by mistake, and only notice the mistake on run-time, not
+  while compiling.
+
+HACKING                                  -=-=-=-=-=-=-=-=-=
 
 Some information about the vcl layout code. Useful for both
 people who want to hack on it, or with it.
diff --git a/vcl/inc/vcl/ldialog.hxx b/vcl/inc/vcl/ldialog.hxx
index bf8cd61..3f7de97 100644
--- a/vcl/inc/vcl/ldialog.hxx
+++ b/vcl/inc/vcl/ldialog.hxx
@@ -59,8 +59,7 @@ public:
 
     virtual Size SizeRequest();
     virtual void SizeAllocate (long x, long y, long width, long height);
-    virtual Rectangle GetAllocation() const
-    { return Rectangle (GetPosPixel(), GetSizePixel()); }
+    virtual Rectangle GetAllocation() const  { return Rectangle (Point(0,0), m_allocation); }
 
     virtual void InvalidateSize()  { m_requisition = Size(0, 0); }
     virtual bool SupportsInvalidateSize()  { return true; }
@@ -77,12 +76,15 @@ protected:
     DECL_LINK (RealizeTimerHdl, void *);
     Timer *m_realizeTimer;
 #endif
+    void Realize();
+    void _SizeAllocate (long width, long height);
 
     Widget m_child;
-    int m_autoResize : 2;
+    int m_myResize : 2;
     int m_borderWidth;
     long m_defaultWidth, m_defaultHeight;
-    Size m_requisition;
+    Size m_requisition, m_allocation;
+    // let's keep allocation size, because GetSizePixel() seems to cut size by 1px
 };
 
 #endif /* VCL_LDIALOG_HXX */
diff --git a/vcl/inc/vcl/notebook.hxx b/vcl/inc/vcl/notebook.hxx
index 17d69b3..6d0baae 100644
--- a/vcl/inc/vcl/notebook.hxx
+++ b/vcl/inc/vcl/notebook.hxx
@@ -42,15 +42,14 @@ public:
     virtual void RemoveChild (Widget &child);
     virtual std::list <Widget> GetChildren() const;
 
-    virtual void SetParent (Widget &)  {}
-    virtual Widget GetParent() const  { return Widget (Window::GetParent()); }
+    virtual void SetParent (Widget &parent)  { m_parent = parent; }
+    virtual Widget GetParent() const  { return m_parent; }
 
     virtual void SetBorderWidth (int borderWidth);
 
     virtual Size SizeRequest();
     virtual void SizeAllocate (long x, long y, long width, long height);
-    virtual Rectangle GetAllocation() const
-    { return Rectangle (GetPosPixel(), GetSizePixel()); }
+    virtual Rectangle GetAllocation() const  { return m_allocation; }
 
     virtual void InvalidateSize()  { m_requisition = Size (0, 0); }
     virtual bool SupportsInvalidateSize()  { return true; }
@@ -70,6 +69,8 @@ protected:
     int m_borderWidth;
     std::vector <Widget> m_children;
     Size m_requisition;
+    Rectangle m_allocation;
+    Widget m_parent;
 };
 
 #endif /* VCL_NOTEBOOK_HXX */
diff --git a/vcl/inc/vcl/table.hxx b/vcl/inc/vcl/table.hxx
index f1522d9..8481f03 100644
--- a/vcl/inc/vcl/table.hxx
+++ b/vcl/inc/vcl/table.hxx
@@ -61,31 +61,28 @@ public:
 protected:
     void Attach (Widget &widget, int left, int right, int top, int bottom,
                  bool xexpand, bool yexpand);
-    void GetReqSize (int left, int right, int top, int bottom, long extraWidth, long extraHeight,
-                     long *width, long *height);
+    void SumReqSize (int first[], int last[], long extra[], long reqSize[]);
 
     struct ChildData {
         ChildData (Widget &child, int left, int right, int top, int bottom, bool xexpand, bool yexpand);
 
         Widget widget;
-        int left, right, top, bottom;
-        int xexpand : 2, yexpand : 2;
+        int first[2], last[2];
+        bool expand[2];
     };
     friend struct CmpChild;
 
-    struct GroupData {
+    struct DimData {
         int expand : 2;
         long reqSize;
-
-        GroupData() : expand (false), reqSize (0) {}
     };
 
     std::list <ChildData> m_children;
-    std::vector <GroupData> m_cols, m_rows;
-    int m_colsExpand, m_rowsExpand;
+    std::vector <DimData> m_dim[2];
+    int m_expand[2];
     int m_colsNb, m_rowsNb;
 
-    int m_borderWidth, m_xspacing, m_yspacing;
+    int m_borderWidth, m_spacing[2];
 
     Size m_requisition;
     Rectangle m_allocation;
diff --git a/vcl/source/layout/align.cxx b/vcl/source/layout/align.cxx
index 6ed54ae..9226c16 100644
--- a/vcl/source/layout/align.cxx
+++ b/vcl/source/layout/align.cxx
@@ -24,7 +24,7 @@
 #include <vcl/align.hxx>
 
 Align::Align (float xalign, float yalign, float xscale, float yscale)
-: m_xalign (xalign), m_yalign (yalign), m_xscale (xscale), m_yscale (yscale), m_minWidth (0), m_minHeight(0), m_maxWidth (LONG_MAX), m_maxHeight (LONG_MAX), m_parent (Widget::NIL), m_child (Widget::NIL)
+: m_xalign (xalign), m_yalign (yalign), m_xscale (xscale), m_yscale (yscale), m_minWidth (0), m_minHeight(0), m_maxWidth (LONG_MAX), m_maxHeight (LONG_MAX), m_allocation (Rectangle(0,0,0,0)), m_parent (Widget::NIL), m_child (Widget::NIL)
 {}
 
 void Align::SetMinSize (long minWidth, long minHeight)
diff --git a/vcl/source/layout/box.cxx b/vcl/source/layout/box.cxx
index d17024f..70be531 100644
--- a/vcl/source/layout/box.cxx
+++ b/vcl/source/layout/box.cxx
@@ -36,7 +36,7 @@ Box::ChildData::ChildData (Widget &w, bool e, bool f)
 {}
 
 Box::Box (Orientation orientation, bool homogeneous, int spacing)
-: m_orientation (orientation), m_homogeneous (homogeneous), m_spacing (spacing), m_borderWidth (0), m_parent (Widget::NIL)
+: m_orientation (orientation), m_homogeneous (homogeneous), m_spacing (spacing), m_borderWidth (0), m_allocation (Rectangle(0,0,0,0)), m_parent (Widget::NIL)
 {}
 
 void Box::Pack (Widget &child, bool expand, bool fill)
@@ -180,10 +180,8 @@ void Box::SizeAllocate (long x, long y, long width, long height)
             visibleChildren++;
         }
     }
-fprintf (stderr, "nb children: %d - visible children: %d - homogeneous: %d\n", m_children.size(), visibleChildren, m_homogeneous);
     if (!visibleChildren) return;
-if (m_homogeneous)
-fprintf (stderr, "max child prim size: %ld\n", sameChildSize);
+
     long extraSpace = 0;
     GVector allocSize (this, width, height);
     if (expandChildren) {
diff --git a/vcl/source/layout/buttonbox.cxx b/vcl/source/layout/buttonbox.cxx
index 48e1946..eadb3e4 100644
--- a/vcl/source/layout/buttonbox.cxx
+++ b/vcl/source/layout/buttonbox.cxx
@@ -76,7 +76,7 @@ ButtonBox::ChildData::ChildData (Widget &b, ButtonRole r)
 {}
 
 ButtonBox::ButtonBox()
-: m_borderWidth (0), m_parent (Widget::NIL)
+: m_borderWidth (0), m_allocation (Rectangle(0,0,0,0)), m_parent (Widget::NIL)
 {
     static DefaultButtonOrder order;
     m_buttonOrder = &order;
diff --git a/vcl/source/layout/layout.cxx b/vcl/source/layout/layout.cxx
index 983fca3..91a3c5e 100644
--- a/vcl/source/layout/layout.cxx
+++ b/vcl/source/layout/layout.cxx
@@ -42,13 +42,13 @@ struct LayoutProscratinator : public Timer
 
     LayoutProscratinator() : Timer()
     {
-        SetTimeout (0);
+        SetTimeout (50);
     }
 
     void Add (Widget &widget)
     {
         if (!HasWidget (m_damaged, widget)) {
-fprintf (stderr, "QueueResize::Add (%s)\n", widget.DebugName());
+fprintf (stderr, "** QueueResize::Add (%s)\n", widget.DebugName());
             m_damaged.push_front (widget);
             Start();
         }
@@ -78,12 +78,11 @@ fprintf (stderr, "QueueResize::Add (%s)\n", widget.DebugName());
     {
         Widget ret = w;
 fprintf (stderr, "GetTopWidgetChanged of %s\n", w.DebugName());
-        for (Widget p = w.GetParent(); !p.isNull(); ret = p, p = p.GetParent())
-{
-fprintf (stderr, "parent is %s - size changed? %d - has parent? %d\n", p.DebugName(), p.HasSizeChanged(), !p.GetParent().isNull());
-            if (!p.HasSizeChanged())
+        for (Widget p = w.GetParent(); !p.isNull(); ret = p, p = p.GetParent()) {
+            bool parentSizeChanged = p.HasSizeChanged();
+            if (!parentSizeChanged)
                 break;
-}
+        }
         return ret;
     }
 
@@ -216,15 +215,27 @@ Widget Widget::GetParent() const
 {
     if (m_layout)
         return m_layout->GetParent();
-    Window *parent = m_window->GetParent();
-    if (parent)
-        return Widget (parent);
+    if (m_window) {
+#if 1
+        // take only Layout types as parents.
+        // doesn't work perfectly though: should iterate down
+        // to make sure it didn't miss any Layout-pure parent.
+
+        Window *parent;
+        while ((parent = m_window->GetParent()))
+            if (dynamic_cast <Layout *> (parent))
+                return Widget (parent);
+        return Widget::NIL;
+#else
+        return Widget (m_window->GetParent());
+#endif
+    }
     return Widget::NIL;
 }
 
 bool Widget::IsChild (Widget &parent) const
 {
-    for (Widget p = GetParent(); p != Widget::NIL; p = p.GetParent())
+    for (Widget p = GetParent(); !p.isNull(); p = p.GetParent())
         if (p == parent)
             return true;
     return false;
@@ -234,7 +245,7 @@ bool Widget::IsRealized() const
 {
     if (m_layout) {
         Rectangle r (m_layout->GetAllocation());
-        return r.GetWidth() != 0 || r.GetHeight() != 0;
+        return r.getWidth() != 0 || r.getHeight() != 0;
     }
     if (m_window)
         return m_window->IsReallyVisible();
@@ -320,10 +331,10 @@ fprintf (stderr, "%s::HasSizeChanged() - old size: %ld x %ld , new size: %ld x %
 
 Rectangle Widget::GetAllocation() const
 {
-    if (m_window)
-        return Rectangle (m_window->GetPosPixel(), m_window->GetSizePixel());
     if (m_layout)
         return m_layout->GetAllocation();
+    if (m_window)
+        return Rectangle (m_window->GetPosPixel(), m_window->GetSizePixel());
     return Rectangle();
 }
 
@@ -332,8 +343,8 @@ const char *Widget::DebugName() const
     if (m_layout)
         return m_layout->DebugName();
     if (m_window)
-        return "Window";
-    return "NIL";
+        return "(Window)";
+    return "(NIL)";
 }
 
 bool Widget::operator == (const Widget &other) const
diff --git a/vcl/source/layout/ldialog.cxx b/vcl/source/layout/ldialog.cxx
index 859778b..c97fd7b 100644
--- a/vcl/source/layout/ldialog.cxx
+++ b/vcl/source/layout/ldialog.cxx
@@ -29,11 +29,11 @@
 #define WB_LDIALOG (WB_STDDIALOG | WB_SIZEABLE)
 
 LDialog::LDialog (Window *parent_dialog)
-: Dialog (parent_dialog, WB_LDIALOG), m_child (Widget::NIL), m_autoResize (1), m_borderWidth (0), m_defaultWidth (0), m_defaultHeight (0)
+: Dialog (parent_dialog, WB_LDIALOG), m_child (Widget::NIL), m_myResize (1), m_borderWidth (0), m_defaultWidth (0), m_defaultHeight (0)
 {}
 
 LDialog::LDialog()
-: Dialog (DIALOG_NO_PARENT, WB_LDIALOG), m_child (Widget::NIL), m_autoResize (1), m_borderWidth (0), m_defaultWidth (0), m_defaultHeight (0)
+: Dialog (DIALOG_NO_PARENT, WB_LDIALOG), m_child (Widget::NIL), m_myResize (1), m_borderWidth (0), m_defaultWidth (0), m_defaultHeight (0)
 {}
 
 void LDialog::SetDefaultSize (long width, long height)
@@ -41,7 +41,6 @@ void LDialog::SetDefaultSize (long width, long height)
 
 void LDialog::AddChild (Widget &child)
 {
-fprintf (stderr, "LDialog::AddChild (%s)\n", child.DebugName());
     m_child = child;
     child.SetParent (this);
     QueueResize (this, this);
@@ -98,14 +97,41 @@ Size LDialog::SizePreferred()
     return req;
 }
 
-void LDialog::SizeAllocate (long, long, long width, long height)
+void LDialog::_SizeAllocate (long width, long height)
 {
-    m_autoResize = true;
-    Window::SetPosSizePixel (0, 0, width, height, WINDOW_POSSIZE_SIZE);
+    Size curSize (GetSizePixel());  // GetOutputSizePixel() or GetResizeOutputSizePixel() ?
+
+    // ensure it shows new req-size
+    width = SAL_MAX (width, m_requisition.Width());
+    height = SAL_MAX (height, m_requisition.Height());
+
+    Size newSize (width, height);
+    if (curSize != newSize) {
+        m_myResize = true;
+        SetSizePixel (newSize);
+    }
+    m_allocation = newSize;
 
     if (!m_child.isNull())
         m_child.SizeAllocate (m_borderWidth, m_borderWidth,
             width - m_borderWidth*2, height - m_borderWidth*2);
+
+}
+
+void LDialog::SizeAllocate (long, long, long, long)
+{
+    // This would look much better if we'd return GetSizePixel()
+    // on Layout::GetAllocation(), but that Window method seems
+    // to return a different value between calls.
+    Size curSize (GetSizePixel());
+    _SizeAllocate (curSize.Width(), curSize.Height());
+}
+
+void LDialog::Realize()
+{
+    // dialog starts with some given size: use _SizeAllocate()
+    Size size (SizePreferred());
+    _SizeAllocate (size.Width(), size.Height());
 }
 
 void LDialog::StateChanged (StateChangedType type)
@@ -113,15 +139,13 @@ void LDialog::StateChanged (StateChangedType type)
     Dialog::StateChanged (type);
 
     if (type == STATE_CHANGE_INITSHOW) {
-fprintf (stderr, "LDialog::StateChanged: INITSHOW\n");
 #ifdef USE_REALIZE_TIMER
         m_realizeTimer = new Timer();
         m_realizeTimer->SetTimeoutHdl (LINK (this, LDialog, RealizeTimerHdl));
         m_realizeTimer->SetTimeout (20);
         m_realizeTimer->Start();
 #else
-        Size size (SizePreferred());
-        SizeAllocate (0, 0, size.Width(), size.Height());
+        Realize();
 #endif
     }
 }
@@ -129,19 +153,15 @@ fprintf (stderr, "LDialog::StateChanged: INITSHOW\n");
 void LDialog::Resize()
 {
     Dialog::Resize();
-if (!m_autoResize)
-fprintf (stderr, "LDialog::Resize - not auto\n");
-
-    if (!m_autoResize)
+    if (!m_myResize)
         QueueResize (this, this);
-    m_autoResize = false;
+    m_myResize = false;
 }
 
 #ifdef USE_REALIZE_TIMER
 IMPL_LINK (LDialog, RealizeTimerHdl, void *, EMPTYARG)
 {
-    Size size (SizePreferred());
-    SizeAllocate (0, 0, size.Width(), size.Height());
+    Realize();
     delete m_realizeTimer;
     return 0;
 }
diff --git a/vcl/source/layout/notebook.cxx b/vcl/source/layout/notebook.cxx
index e94d021..8932180 100644
--- a/vcl/source/layout/notebook.cxx
+++ b/vcl/source/layout/notebook.cxx
@@ -33,7 +33,7 @@ struct CmpChild {
 };
 
 Notebook::Notebook (Window *parent)
-: TabControl (parent), m_borderWidth (0)
+: TabControl (parent), m_borderWidth (0), m_allocation (Rectangle(0,0,0,0)), m_parent (Widget::NIL)
 {
     m_children.reserve (8);
 
@@ -136,9 +136,12 @@ void Notebook::SyncChildSize()
 
 void Notebook::SizeAllocate (long x, long y, long width, long height)
 {
+    m_allocation = Rectangle (x, y, width, height);
     x += m_borderWidth; y += m_borderWidth;
     width -= m_borderWidth*2; height -= m_borderWidth*2;
-    Window::SetPosSizePixel (x, y, width, height, WINDOW_POSSIZE_ALL);
+
+    if (GetPosPixel() != Point (x, y) || GetSizePixel() != Size (width, height))
+        SetPosSizePixel (x, y, width, height, WINDOW_POSSIZE_ALL);
     SyncChildSize();
 }
 
diff --git a/vcl/source/layout/table.cxx b/vcl/source/layout/table.cxx
index 83d2a9f..1505626 100644
--- a/vcl/source/layout/table.cxx
+++ b/vcl/source/layout/table.cxx
@@ -22,6 +22,8 @@
 #include "precompiled_vcl.hxx"
 
 #include <vcl/table.hxx>
+#define COL 0
+#define ROW 1
 
 struct CmpChild {
     Widget m_child;
@@ -31,16 +33,23 @@ struct CmpChild {
     { return childData.widget == m_child; }
 };
 
-Table::ChildData::ChildData (Widget &w, int l, int r, int t, int b, bool x, bool y)
-: widget (w), left (l), right (r), top (t), bottom (b), xexpand (x), yexpand (y)
-{}
+Table::ChildData::ChildData (Widget &w, int left, int right, int top, int bottom, bool xexpand, bool yexpand)
+: widget (w)
+{
+    first[COL] = left;
+    last[COL]  = right;
+    first[ROW] = top;
+    last[ROW]  = bottom;
+    expand[COL] = xexpand;
+    expand[ROW] = yexpand;
+}
 
 Table::Table (int cols, int rows)
-: m_colsNb (cols), m_rowsNb (rows), m_borderWidth (0), m_xspacing (0), m_yspacing (0),
-m_parent (Widget::NIL)
+: m_colsNb (cols), m_rowsNb (rows), m_borderWidth (0), m_allocation (Rectangle(0,0,0,0)), m_parent (Widget::NIL)
 {
-    m_cols.resize (cols);
-    m_rows.resize (rows);
+    m_spacing[COL] = 0; m_spacing[ROW] = 0;
+    m_dim[COL].resize (cols);
+    m_dim[ROW].resize (rows);
 }
 
 void Table::Attach (Widget &child, int left, int right, int top, int bottom,
@@ -68,12 +77,13 @@ void Table::Attach (Layout *child, int left, int right, int top, int bottom,
 
 void Table::SetSpacings (int xspacing, int yspacing)
 {
-    m_xspacing = xspacing; m_yspacing = yspacing;
+    m_spacing[COL] = xspacing; m_spacing[ROW] = yspacing;
     QueueResize (this);
 }
 
 void Table::AddChild (Widget &child)
 {
+    // this won't work if the table hasn't been built linearly
     int left = m_children.size() % m_colsNb;
     int top = m_children.size() / m_rowsNb;
     Attach (child, left, left+1, top, top+1, false, false);
@@ -107,14 +117,64 @@ Size Table::SizeRequest()
         return m_requisition;
 
     // 1. clear cols and rows data
-    for (std::vector <GroupData>::iterator it = m_cols.begin();
-         it != m_cols.end(); it++)
-    { it->expand = false; it->reqSize = 0; }
-    for (std::vector <GroupData>::iterator it = m_rows.begin();
-         it != m_rows.end(); it++)
-    { it->expand = false; it->reqSize = 0; }
-
-    // 2. divide children req-size through the rows and cols they occupy
+    for (int dim = 0; dim < 2; dim++)
+        for (std::vector <DimData>::iterator it = m_dim[dim].begin();
+             it != m_dim[dim].end(); it++)
+        { it->expand = false; it->reqSize = 0; }
+
+    // 2. calculate cols and rows req-sizes to support one-span children
+    m_expand[COL] = 0; m_expand[ROW] = 0;
+    for (std::list <ChildData>::iterator it = m_children.begin();
+         it != m_children.end(); it++) {
+        Size childSize (it->widget.SizeRequest());
+        for (int dim = 0; dim < 2; dim++) {
+            if (it->last[dim] - it->first[dim] == 1) {
+                DimData &d = m_dim[dim][it->first[dim]];
+                long childDim = (dim == 0) ? childSize.Width() : childSize.Height();
+                d.reqSize = SAL_MAX (d.reqSize, childDim);
+                if (it->expand[dim] && !d.expand) {
+                    d.expand = true;
+                    m_expand[dim]++;
+                }
+            }
+        }
+    }
+
+    // 3. now, do the same for multi-span columns
+    // note: we could have done this in the previous step, but we want
+    // to minimize the req-size of the cols and rows
+    for (std::list <ChildData>::iterator it = m_children.begin();
+         it != m_children.end(); it++) {
+        Size childSize (it->widget.SizeRequest());
+        for (int dim = 0; dim < 2; dim++) {
+            int span = it->last[dim] - it->first[dim];
+            if (span > 1) {
+                int n_expand = 0;
+                for (int i = it->first[dim]; i < it->last[dim]; i++)
+                    if (m_dim[dim][i].expand)
+                        n_expand++;
+
+                int len = (n_expand == 0) ? span : n_expand;
+                long childDim = (dim == 0) ? childSize.Width() : childSize.Height();
+                // if no col/row is set to expand, and child is, rectify
+                bool rectifyExpand = (n_expand == 0 && it->expand[dim]);
+
+                for (int i = it->first[dim]; i < it->last[dim]; i++) {
+                    DimData &d = m_dim[dim][i];
+                    if (n_expand == 0 || d.expand)
+                        d.reqSize = SAL_MAX (d.reqSize, childDim / len);
+                    if (rectifyExpand)
+                        d.expand = true;
+                }
+                if (rectifyExpand)
+                    m_expand[dim] += span;
+            }
+        }
+    }
+
+
+
+#if 0
     m_colsExpand = 0; m_rowsExpand = 0;
     for (std::list <ChildData>::iterator it = m_children.begin();
          it != m_children.end(); it++) {
@@ -139,43 +199,41 @@ Size Table::SizeRequest()
             }
         }
     }
+#endif
 
-    // 3. sum everything up
-    long width, height;
-    GetReqSize (0, m_colsNb, 0, m_rowsNb, 0, 0, &width, &height);
-    width += m_borderWidth * 2;
-    height += m_borderWidth * 2;
+    // 4. sum everything up
+    int table[4] = { 0, 0, m_colsNb, m_rowsNb };
+    long extra[2] = { 0 }, size[2];
+    SumReqSize (table, table+2, extra, size);
+    size[COL] += m_borderWidth * 2;
+    size[ROW] += m_borderWidth * 2;
 
-    return (m_requisition = Size (width, height));
+    return (m_requisition = Size (size[COL], size[ROW]));
 }
 
-void Table::GetReqSize (int left, int right, int top, int bottom, long extraWidth, long extraHeight, long *width, long *height)
+void Table::SumReqSize (int first[], int last[], long extra[], long reqSize[])
 {
-    *width = 0; *height = 0;
-    for (int i = left; i < right; i++) {
-        GroupData &c = m_cols[i];
-        *width += c.reqSize;
-        if (c.expand) *width += extraWidth;
-    }
-    for (int i = top; i < bottom; i++) {
-        GroupData &r = m_rows[i];
-        *height += r.reqSize;
-        if (r.expand) *height += extraHeight;
+    reqSize[COL] = 0; reqSize[ROW] = 0;
+    for (int dim = 0; dim < 2; dim++) {
+        for (int i = first[dim]; i < last[dim]; i++) {
+            DimData &d = m_dim[dim][i];
+            reqSize[dim] += d.reqSize;
+            if (d.expand)
+                reqSize[dim] += extra[dim];
+        }
+        int span = last[dim] - first[dim];
+        if (span > 1)
+            reqSize[dim] += m_spacing[dim] * (span-1);
     }
-    int xspan = right - left, yspan = bottom - top;
-    if (xspan > 1)
-        *width += m_xspacing * (xspan-1);
-    if (yspan > 1)
-        *height += m_yspacing * (yspan-1);
 }
 
 void Table::SizeAllocate (long x, long y, long width, long height)
 {
-    long extraWidth = 0, extraHeight = 0;
-    if (m_colsExpand)
-        extraWidth = (width - m_requisition.Width()) / m_colsExpand;
-    if (m_rowsExpand)
-        extraHeight = (height - m_requisition.Height()) / m_rowsExpand;
+    long extraSize[2] = { 0 };
+    if (m_expand[COL] > 0)
+        extraSize[COL] = (width - m_requisition.Width()) / m_expand[COL];
+    if (m_expand[ROW] > 0)
+        extraSize[ROW] = (height - m_requisition.Height()) / m_expand[ROW];
 
     m_allocation = Rectangle (x, y, width, height);
     x += m_borderWidth; y += m_borderWidth;
@@ -186,14 +244,14 @@ void Table::SizeAllocate (long x, long y, long width, long height)
          it != m_children.end(); it++) {
         ChildData &child = *it;
 
-        long childX, childY, childWidth, childHeight;
-        GetReqSize (0, child.left, 0, child.top, extraWidth, extraHeight, &childX, &childY);
-        GetReqSize (child.left, child.right, child.top, child.bottom, extraWidth, extraHeight,
-                    &childWidth, &childHeight);
-        if (child.left > 0) childX += m_xspacing;
-        if (child.top > 0) childY += m_yspacing;
+        long childPos[2], childSize[2];
+        int bounds[4] = { 0, 0, child.first[COL], child.first[ROW] };
+        SumReqSize (bounds, bounds+2, extraSize, childPos);
+        SumReqSize (child.first, child.last, extraSize, childSize);
+        if (child.first[COL] > 0) childPos[COL] += m_spacing[COL];
+        if (child.first[ROW] > 0) childPos[ROW] += m_spacing[ROW];
 
-        child.widget.SizeAllocate (x + childX, y + childY, childWidth, childHeight);
+        child.widget.SizeAllocate (x + childPos[0], y + childPos[1], childSize[0], childSize[1]);
     }
 }
 


More information about the Libreoffice-commits mailing list