aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2023-03-07 16:06:29 +0800
committerMitch Curtis <mitch.curtis@qt.io>2023-03-08 14:50:54 +0800
commit4f5b4f81b0e73f264a19a690b8795f776778fa3c (patch)
tree040a67918b165ea7f604823dfebffe7e2f3f4d4e
parentee3d11f70bf7d5d7f3b0f4f0b531a0ed2a20e721 (diff)
Material: fix placeholder text y position when control is too small
Ensure that it's sensibly positioned despite its size. Fixes: QTBUG-111515 Pick-to: 6.5 6.5.0 Change-Id: I71816c461ff1d2f85e010bf871ab1b7ef2ccaf6e Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io>
-rw-r--r--src/quickcontrols/material/TextArea.qml1
-rw-r--r--src/quickcontrols/material/TextField.qml1
-rw-r--r--src/quickcontrols/material/impl/qquickmaterialplaceholdertext.cpp58
-rw-r--r--src/quickcontrols/material/impl/qquickmaterialplaceholdertext_p.h6
-rw-r--r--tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml37
5 files changed, 91 insertions, 12 deletions
diff --git a/src/quickcontrols/material/TextArea.qml b/src/quickcontrols/material/TextArea.qml
index 545cadee82..32f6d5d5f7 100644
--- a/src/quickcontrols/material/TextArea.qml
+++ b/src/quickcontrols/material/TextArea.qml
@@ -50,6 +50,7 @@ T.TextArea {
controlHasActiveFocus: control.activeFocus
controlHasText: control.length > 0
controlImplicitBackgroundHeight: control.implicitBackgroundHeight
+ controlHeight: control.height
}
background: MaterialTextContainer {
diff --git a/src/quickcontrols/material/TextField.qml b/src/quickcontrols/material/TextField.qml
index e2ec69dc27..b8ddd55cf4 100644
--- a/src/quickcontrols/material/TextField.qml
+++ b/src/quickcontrols/material/TextField.qml
@@ -50,6 +50,7 @@ T.TextField {
controlHasActiveFocus: control.activeFocus
controlHasText: control.length > 0
controlImplicitBackgroundHeight: control.implicitBackgroundHeight
+ controlHeight: control.height
}
background: MaterialTextContainer {
diff --git a/src/quickcontrols/material/impl/qquickmaterialplaceholdertext.cpp b/src/quickcontrols/material/impl/qquickmaterialplaceholdertext.cpp
index b908a62fc0..40557f46a2 100644
--- a/src/quickcontrols/material/impl/qquickmaterialplaceholdertext.cpp
+++ b/src/quickcontrols/material/impl/qquickmaterialplaceholdertext.cpp
@@ -9,6 +9,7 @@
#include <QtGui/qpainterpath.h>
#include <QtQml/qqmlinfo.h>
#include <QtQuickTemplates2/private/qquicktheme_p.h>
+#include <QtQuickTemplates2/private/qquicktextarea_p.h>
QT_BEGIN_NAMESPACE
@@ -100,13 +101,25 @@ bool QQuickMaterialPlaceholderText::shouldAnimate() const
: !m_controlHasText && !text().isEmpty();
}
+void QQuickMaterialPlaceholderText::updateY()
+{
+ setY(shouldFloat() ? floatingTargetY() : normalTargetY());
+}
+
qreal QQuickMaterialPlaceholderText::normalTargetY() const
{
+ auto *textArea = qobject_cast<QQuickTextArea *>(parentItem());
+ if (textArea && m_controlHeight >= textArea->implicitHeight()) {
+ // TextArea can be multiple lines in height, and we want the
+ // placeholder text to sit in the middle of its default-height
+ // (one-line) if its explicit height is greater than or equal to its
+ // implicit height - i.e. if it has room for it. If it doesn't have
+ // room, just do what TextField does.
+ return (m_controlImplicitBackgroundHeight - m_largestHeight) / 2.0;
+ }
+
// When the placeholder text shouldn't float, it should sit in the middle of the TextField.
- // We could just use the control's height minus our height instead of the members, but
- // that doesn't work for TextArea, which can be multiple lines in height and hence taller.
- // In that case, we want the placeholder text to sit in the middle of its default-height (one-line).
- return (m_controlImplicitBackgroundHeight - m_largestHeight) / 2.0;
+ return (m_controlHeight - height()) / 2.0;
}
qreal QQuickMaterialPlaceholderText::floatingTargetY() const
@@ -142,10 +155,34 @@ void QQuickMaterialPlaceholderText::setControlImplicitBackgroundHeight(qreal con
return;
m_controlImplicitBackgroundHeight = controlImplicitBackgroundHeight;
- setY(shouldFloat() ? floatingTargetY() : normalTargetY());
+ updateY();
emit controlImplicitBackgroundHeightChanged();
}
+/*!
+ \internal
+
+ Exists so that we can call updateY when the control's height changes,
+ which is necessary for some y position calculations.
+
+ We don't really need it for the actual calculations, since we already
+ have access to the parent item, from which the property comes, but
+ it's simpler just to use it.
+*/
+qreal QQuickMaterialPlaceholderText::controlHeight() const
+{
+ return m_controlHeight;
+}
+
+void QQuickMaterialPlaceholderText::setControlHeight(qreal controlHeight)
+{
+ if (qFuzzyCompare(m_controlHeight, controlHeight))
+ return;
+
+ m_controlHeight = controlHeight;
+ updateY();
+}
+
qreal QQuickMaterialPlaceholderText::verticalPadding() const
{
return m_verticalPadding;
@@ -185,8 +222,7 @@ void QQuickMaterialPlaceholderText::controlGotActiveFocus()
m_focusInAnimation->start(QAbstractAnimation::DeleteWhenStopped);
} else {
- const int newY = shouldFloat() ? floatingTargetY() : normalTargetY();
- setY(newY);
+ updateY();
}
}
@@ -212,16 +248,14 @@ void QQuickMaterialPlaceholderText::controlLostActiveFocus()
m_focusOutAnimation->start(QAbstractAnimation::DeleteWhenStopped);
} else {
- const int newY = shouldFloat() ? floatingTargetY() : normalTargetY();
- setY(newY);
+ updateY();
}
}
void QQuickMaterialPlaceholderText::maybeSetFocusAnimationProgress()
{
- const bool shouldWeFloat = shouldFloat();
- setY(shouldWeFloat ? floatingTargetY() : normalTargetY());
- setScale(shouldWeFloat ? floatingScale : 1.0);
+ updateY();
+ setScale(shouldFloat() ? floatingScale : 1.0);
}
void QQuickMaterialPlaceholderText::componentComplete()
diff --git a/src/quickcontrols/material/impl/qquickmaterialplaceholdertext_p.h b/src/quickcontrols/material/impl/qquickmaterialplaceholdertext_p.h
index 525e079c28..22e8b4e99a 100644
--- a/src/quickcontrols/material/impl/qquickmaterialplaceholdertext_p.h
+++ b/src/quickcontrols/material/impl/qquickmaterialplaceholdertext_p.h
@@ -34,6 +34,7 @@ class QQuickMaterialPlaceholderText : public QQuickPlaceholderText
Q_PROPERTY(qreal verticalPadding READ verticalPadding WRITE setVerticalPadding NOTIFY verticalPaddingChanged FINAL)
Q_PROPERTY(qreal controlImplicitBackgroundHeight READ controlImplicitBackgroundHeight
WRITE setControlImplicitBackgroundHeight NOTIFY controlImplicitBackgroundHeightChanged FINAL)
+ Q_PROPERTY(qreal controlHeight READ controlHeight WRITE setControlHeight FINAL)
QML_NAMED_ELEMENT(FloatingPlaceholderText)
QML_ADDED_IN_VERSION(6, 5)
@@ -54,6 +55,9 @@ public:
qreal controlImplicitBackgroundHeight() const;
void setControlImplicitBackgroundHeight(qreal controlImplicitBackgroundHeight);
+ qreal controlHeight() const;
+ void setControlHeight(qreal controlHeight);
+
qreal verticalPadding() const;
void setVerticalPadding(qreal verticalPadding);
@@ -69,6 +73,7 @@ private:
bool shouldFloat() const;
bool shouldAnimate() const;
+ void updateY();
qreal normalTargetY() const;
qreal floatingTargetY() const;
@@ -85,6 +90,7 @@ private:
int m_largestHeight = 0;
qreal m_verticalPadding = 0;
qreal m_controlImplicitBackgroundHeight = 0;
+ qreal m_controlHeight = 0;
QPointer<QParallelAnimationGroup> m_focusInAnimation;
QPointer<QParallelAnimationGroup> m_focusOutAnimation;
};
diff --git a/tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml b/tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml
index f627f7ee1b..46dd5b42d0 100644
--- a/tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml
+++ b/tests/auto/quickcontrols/qquickmaterialstyle/data/tst_material.qml
@@ -7,6 +7,7 @@ import QtTest
import QtQuick.Templates as T
import QtQuick.Controls
import QtQuick.Controls.Material
+import QtQuick.Controls.Material.impl as MaterialImpl
TestCase {
id: testCase
@@ -953,4 +954,40 @@ TestCase {
verify(item)
compare(item["__isDiscrete"], data.expectTickmarks)
}
+
+ Component {
+ id: textFieldComponent
+ TextField {}
+ }
+
+ Component {
+ id: textAreaComponent
+ TextArea {}
+ }
+
+ function test_placeholderText() {
+ {
+ // The non-floating placeholder text should be in the middle of TextField regardless of its height.
+ let textField = createTemporaryObject(textFieldComponent, testCase, { placeholderText: "TextField" })
+ verify(textField)
+ let placeholderTextItem = textField.children[0]
+ verify(placeholderTextItem as MaterialImpl.FloatingPlaceholderText)
+ compare(placeholderTextItem.y, (textField.height - placeholderTextItem.height) / 2)
+ textField.height = 10
+ compare(placeholderTextItem.y, (textField.height - placeholderTextItem.height) / 2)
+ textField.destroy()
+ }
+
+ {
+ // The non-floating placeholder text should be near the top of TextArea while it has room, but when it
+ // doesn't have room, it should start behaving like TextField's.
+ let textArea = createTemporaryObject(textAreaComponent, testCase, { placeholderText: "TextArea" })
+ verify(textArea)
+ let placeholderTextItem = textArea.children[0]
+ verify(placeholderTextItem as MaterialImpl.FloatingPlaceholderText)
+ compare(placeholderTextItem.y, (placeholderTextItem.controlImplicitBackgroundHeight - placeholderTextItem.largestHeight) / 2)
+ textArea.height = 10
+ compare(placeholderTextItem.y, (textArea.height - placeholderTextItem.height) / 2)
+ }
+ }
}