summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gui/graphicsview/qgraphicslayoutitem.cpp70
-rw-r--r--src/gui/kernel/qwidget_x11.cpp11
-rw-r--r--tests/auto/qgraphicslayoutitem/tst_qgraphicslayoutitem.cpp108
3 files changed, 186 insertions, 3 deletions
diff --git a/src/gui/graphicsview/qgraphicslayoutitem.cpp b/src/gui/graphicsview/qgraphicslayoutitem.cpp
index 0631df8..5a2d051 100644
--- a/src/gui/graphicsview/qgraphicslayoutitem.cpp
+++ b/src/gui/graphicsview/qgraphicslayoutitem.cpp
@@ -133,15 +133,81 @@ void QGraphicsLayoutItemPrivate::init()
/*!
\internal
+
+ effectiveSizeHint has a quirky behavior, one of the quirkinesses is when the hfw function is
+ combined with user-specified min/max sizes. The input to hfw function (e.g width) must be within
+ the min/max width constraint, and the output must be within the min/max height. This sets up a
+ loose dependency between minimum width and maximum height (or minimum height, depending on the
+ type of hfw function). Note that its only the concrete subclass that implements that hfw
+ function that knows if this dependency means that the height will increase or decrease when the
+ width is increased.
+
+ The application should try to ensure that the user-defined sizes are within the range so that
+ they don't conflict with the hfw function.
+
+ Suppose, for instance that the hfw function is:
+
+ height = 2000/width
+
+ and the item has these user-defined sizes:
+
+ min ( 5, 5)
+ pref(100, 10)
+ max (500,100)
+
+ what is the return value if one calls item->effectiveSizeHint(Qt::MinimumSize, QSizeF(10, -1)); ?
+ The sizeHint() function would return QSizeF(10, 200), but it would be bounded down to 100 due
+ to the max value, so it would return (10, 100). This is not what the item expects, since it
+ really wants that its hfw is respected. If this is a label with wrapped text, this would most
+ likely lead to that some text is clipped. This is certainly not what the app developer wants.
+ Now, it would be better if the user changed those constraints to match the hfw function:
+
+ min ( 20, 5)
+ pref(100, 10)
+ max (500,100)
+
+ here, it says that the width cannot be smaller than 20. This is because if it becomes smaller
+ than 20 the result of the hfw function would violate the max height (100).
+
+ However, there is a similar problem if the width passed to the hfw function reaches *max* width:
+
+ the sizeHint() function would now return QSizeF(500, 4), but 4 is smaller than the minimum
+ height (5), so effectiveSizeHint() would return (500, 5), which would leave too much space.
+ In this case, setting the max width to 400 fixes the problem:
+
+ min ( 20, 5)
+ pref(100, 10)
+ max (400,100)
+
+
+ The implementor of a hfw widget must be aware of this when sizeHint() is reimplemented, so that
+ the default min and max sizes works sensible. (unfortunately the implementor does not have the
+ control over user-set values).
+
*/
QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint) const
{
Q_Q(const QGraphicsLayoutItem);
QSizeF *sizeHintCache;
const bool hasConstraint = constraint.width() >= 0 || constraint.height() >= 0;
+ QSizeF adjustedConstraint = constraint;
if (hasConstraint) {
if (!sizeHintWithConstraintCacheDirty && constraint == cachedConstraint)
return cachedSizeHintsWithConstraints;
+
+ const QSizeF *hintsWithoutConstraint = effectiveSizeHints(QSizeF(-1,-1));
+
+ if (adjustedConstraint.width() >= 0)
+ adjustedConstraint.setWidth( qBound( hintsWithoutConstraint[Qt::MinimumSize].width(),
+ adjustedConstraint.width(),
+ hintsWithoutConstraint[Qt::MaximumSize].width()));
+ if (adjustedConstraint.height() >= 0)
+ adjustedConstraint.setHeight( qBound( hintsWithoutConstraint[Qt::MinimumSize].height(),
+ adjustedConstraint.height(),
+ hintsWithoutConstraint[Qt::MaximumSize].height()));
+
+ if (!sizeHintWithConstraintCacheDirty && adjustedConstraint == cachedConstraint)
+ return cachedSizeHintsWithConstraints;
sizeHintCache = cachedSizeHintsWithConstraints;
} else {
if (!sizeHintCacheDirty)
@@ -150,7 +216,7 @@ QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint)
}
for (int i = 0; i < Qt::NSizeHints; ++i) {
- sizeHintCache[i] = constraint;
+ sizeHintCache[i] = adjustedConstraint;
if (userSizeHints)
combineSize(sizeHintCache[i], userSizeHints[i]);
}
@@ -185,7 +251,7 @@ QSizeF *QGraphicsLayoutItemPrivate::effectiveSizeHints(const QSizeF &constraint)
// COMBINE_SIZE(descentS, q->sizeHint(Qt::MinimumDescent, constraint));
if (hasConstraint) {
- cachedConstraint = constraint;
+ cachedConstraint = adjustedConstraint;
sizeHintWithConstraintCacheDirty = false;
} else {
sizeHintCacheDirty = false;
diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp
index f99cc2c..98c33da 100644
--- a/src/gui/kernel/qwidget_x11.cpp
+++ b/src/gui/kernel/qwidget_x11.cpp
@@ -2694,8 +2694,17 @@ void QWidgetPrivate::setConstraints_sys()
#ifdef ALIEN_DEBUG
qDebug() << "QWidgetPrivate::setConstraints_sys START" << q;
#endif
- if (q->testAttribute(Qt::WA_WState_Created))
+ if (q->testAttribute(Qt::WA_WState_Created)) {
do_size_hints(q, extra);
+ QtMWMHints mwmHints = GetMWMHints(X11->display, q->internalWinId());
+ const bool wasFuncResize = mwmHints.functions & MWM_FUNC_RESIZE;
+ if (q->minimumSize() == q->maximumSize())
+ mwmHints.functions &= ~MWM_FUNC_RESIZE;
+ else
+ mwmHints.functions |= MWM_FUNC_RESIZE;
+ if (wasFuncResize != (mwmHints.functions & MWM_FUNC_RESIZE))
+ SetMWMHints(X11->display, q->internalWinId(), mwmHints);
+ }
#ifdef ALIEN_DEBUG
qDebug() << "QWidgetPrivate::setConstraints_sys END" << q;
#endif
diff --git a/tests/auto/qgraphicslayoutitem/tst_qgraphicslayoutitem.cpp b/tests/auto/qgraphicslayoutitem/tst_qgraphicslayoutitem.cpp
index a8b6c08..34ca5d4 100644
--- a/tests/auto/qgraphicslayoutitem/tst_qgraphicslayoutitem.cpp
+++ b/tests/auto/qgraphicslayoutitem/tst_qgraphicslayoutitem.cpp
@@ -44,6 +44,7 @@
#include <qgraphicslayoutitem.h>
#include <float.h>
#include <limits.h>
+#include <QtGui/qgraphicswidget.h>
class tst_QGraphicsLayoutItem : public QObject {
Q_OBJECT
@@ -60,6 +61,8 @@ private slots:
void contentsRect();
void effectiveSizeHint_data();
void effectiveSizeHint();
+ void effectiveSizeHint2_data();
+ void effectiveSizeHint2();
void getContentsMargins();
void isLayout_data();
void isLayout();
@@ -104,6 +107,40 @@ public:
};
+class RectWidget : public QGraphicsWidget
+{
+public:
+ RectWidget(QGraphicsItem *parent = 0) : QGraphicsWidget(parent), m_fnConstraint(fn2000_div_w) {}
+
+
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const
+ {
+ if (constraint.width() < 0 && constraint.height() < 0 && m_sizeHints[which].isValid()) {
+ return m_sizeHints[which];
+ }
+ if (m_fnConstraint) {
+ return m_fnConstraint(which, constraint);
+ }
+ return QGraphicsWidget::sizeHint(which, constraint);
+ }
+
+ void setSizeHint(Qt::SizeHint which, const QSizeF &size) {
+ m_sizeHints[which] = size;
+ updateGeometry();
+ }
+
+ void setConstraintFunction(QSizeF (*fnConstraint)(Qt::SizeHint, const QSizeF &)) {
+ m_fnConstraint = fnConstraint;
+ }
+
+ QSizeF m_sizeHints[Qt::NSizeHints];
+ QSizeF (*m_fnConstraint)(Qt::SizeHint, const QSizeF &);
+
+ static QSizeF fn2000_div_w(Qt::SizeHint /*which*/, const QSizeF &constraint = QSizeF()) {
+ return QSizeF(constraint.width(), 2000.0/constraint.width());
+ }
+};
+
// This will be called before the first test function is executed.
// It is only called once.
void tst_QGraphicsLayoutItem::initTestCase()
@@ -183,6 +220,77 @@ void tst_QGraphicsLayoutItem::effectiveSizeHint()
QCOMPARE(r.height(), constraint.height());
}
+
+void tst_QGraphicsLayoutItem::effectiveSizeHint2_data()
+{
+ QTest::addColumn<QSizeF>("minimumSize");
+ QTest::addColumn<QSizeF>("preferredSize");
+ QTest::addColumn<QSizeF>("maximumSize");
+ QTest::addColumn<QSizeF>("minimumSizeHint");
+ QTest::addColumn<QSizeF>("preferredSizeHint");
+ QTest::addColumn<QSizeF>("maximumSizeHint");
+
+ QTest::addColumn<QSizeF>("inputConstraint");
+ QTest::addColumn<QSizeF>("expectedMinimumESH");
+ QTest::addColumn<QSizeF>("expectedPreferredESH");
+ QTest::addColumn<QSizeF>("expectedMaximumESH");
+
+ QTest::newRow("P1-a")
+ << QSizeF( 6, 4) << QSizeF( 60, 40) << QSizeF( 600, 400)
+ << QSizeF( -1, -1) << QSizeF( -1, -1) << QSizeF( -1, -1)
+ << QSizeF(-1, -1)
+ << QSizeF(6, 4) << QSizeF( 60, 40) << QSizeF(600, 400);
+
+ QTest::newRow("P1-hfw-1")
+ << QSizeF( -1, -1) << QSizeF( -1, -1) << QSizeF( -1, -1)
+ << QSizeF( 6, 4) << QSizeF( 60, 40) << QSizeF(600, 400)
+ << QSizeF(200, -1)
+ << QSizeF(200, 10) << QSizeF(200, 10) << QSizeF(200, 10);
+
+ QTest::newRow("P1-hfw-2")
+ << QSizeF( 6, -1) << QSizeF( 60, -1) << QSizeF(600, -1)
+ << QSizeF( -1, -1) << QSizeF( -1, -1) << QSizeF( -1, -1)
+ << QSizeF(200, -1)
+ << QSizeF(200, 10) << QSizeF(200, 10) << QSizeF(200, 10);
+
+ // constraint is bigger than max width
+ QTest::newRow("P1-hfw-3")
+ << QSizeF( 5, -1) << QSizeF( 50, -1) << QSizeF(500, -1)
+ << QSizeF( -1, -1) << QSizeF( -1, -1) << QSizeF( -1, -1)
+ << QSizeF(600, -1)
+ << QSizeF(500, 4) << QSizeF(500, 4) << QSizeF(500, 4);
+
+}
+
+void tst_QGraphicsLayoutItem::effectiveSizeHint2()
+{
+ QFETCH(QSizeF, minimumSize);
+ QFETCH(QSizeF, preferredSize);
+ QFETCH(QSizeF, maximumSize);
+ QFETCH(QSizeF, minimumSizeHint);
+ QFETCH(QSizeF, preferredSizeHint);
+ QFETCH(QSizeF, maximumSizeHint);
+
+ QFETCH(QSizeF, inputConstraint);
+ QFETCH(QSizeF, expectedMinimumESH);
+ QFETCH(QSizeF, expectedPreferredESH);
+ QFETCH(QSizeF, expectedMaximumESH);
+
+ RectWidget *item = new RectWidget;
+ item->setMinimumSize(minimumSize);
+ item->setPreferredSize(preferredSize);
+ item->setMaximumSize(maximumSize);
+ item->setSizeHint(Qt::MinimumSize, minimumSizeHint);
+ item->setSizeHint(Qt::PreferredSize, preferredSizeHint);
+ item->setSizeHint(Qt::MaximumSize, maximumSizeHint);
+
+ QCOMPARE(item->effectiveSizeHint(Qt::MinimumSize, inputConstraint), expectedMinimumESH);
+ QCOMPARE(item->effectiveSizeHint(Qt::PreferredSize, inputConstraint), expectedPreferredESH);
+ QCOMPARE(item->effectiveSizeHint(Qt::MaximumSize, inputConstraint), expectedMaximumESH);
+
+}
+
+
// void getContentsMargins(qreal* left, qreal* top, qreal* right, qreal* bottom) const public
void tst_QGraphicsLayoutItem::getContentsMargins()
{