refactor(StatusBaseInput): use RowLayout for position management

This commit is contained in:
Patryk Osmaczko 2022-03-18 13:08:02 +01:00 committed by Michał Cieślak
parent ffb7289b9f
commit f2c832e015
2 changed files with 165 additions and 207 deletions

View File

@ -146,7 +146,7 @@ Column {
StatusInput { StatusInput {
label: "Label" label: "Label"
input.placeholderText: "Input width component (right side)" input.placeholderText: "Input width component (right side)"
input.component: StatusIcon { input.rightComponent: StatusIcon {
icon: "cancel" icon: "cancel"
height: 16 height: 16
color: Theme.palette.dangerColor1 color: Theme.palette.dangerColor1
@ -173,25 +173,27 @@ Column {
} }
StatusInput { StatusInput {
property bool toggled: true
label: "Input with emoji icon" label: "Input with emoji icon"
input.placeholderText: "Enter Name" input.placeholderText: "Enter Name"
input.icon.emoji: "😁" input.icon.emoji: toggled ? "😁" : "🧸"
input.icon.color: "blue" input.icon.color: "blue"
input.isIconSelectable: true input.isIconSelectable: true
onIconClicked: { onIconClicked: {
// launch emoji popup toggled = !toggled
} }
} }
StatusInput { StatusInput {
property bool toggled: true
label: "Input with selectable icon which is not an emoji" label: "Input with selectable icon which is not an emoji"
input.placeholderText: "Enter Name" input.placeholderText: "Enter Name"
input.icon.emoji: "" input.icon.emoji: ""
input.icon.name: "filled-account" input.icon.name: toggled ? "filled-account" : "image"
input.icon.color: "blue" input.icon.color: "blue"
input.isIconSelectable: true input.isIconSelectable: true
onIconClicked: { onIconClicked: {
// launch emoji popup toggled = !toggled
} }
} }
} }

View File

@ -1,15 +1,15 @@
import QtQuick 2.14 import QtQuick 2.14
import QtQuick.Controls 2.14 as QC import QtQuick.Controls 2.14 as QC
import QtQuick.Layouts 1.14
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
Item { Item {
id: statusBaseInput id: root
property bool multiline: false property bool multiline: false
@ -66,40 +66,24 @@ Item {
} }
} }
property Item leftComponent property Component leftComponent
property Item component property Component rightComponent
signal iconClicked() signal iconClicked
onClearableChanged: {
if (clearable && !component) {
clearButtonLoader.active = true
clearButtonLoader.parent = statusBaseInputComponentSlot
} else {
clearButtonLoader.active = false
}
}
onLeftComponentChanged: {
if (!!leftComponent) {
leftComponent.parent = statusBaseInputLeftComponentSlot;
}
}
onComponentChanged: {
if (!!component) {
component.parent = statusBaseInputComponentSlot
}
}
implicitWidth: 448 implicitWidth: 448
implicitHeight: multiline ? Math.max((edit.implicitHeight + topPadding + bottomPadding), 44) : 44 implicitHeight: multiline ? Math.min(Math.max(
(edit.implicitHeight + topPadding + bottomPadding),
44, root.minimumHeight), root.maximumHeight) : 44
Rectangle { Rectangle {
width: parent.width width: parent.width
height: maximumHeight != 0 ? Math.min( height: maximumHeight != 0 ? Math.min(
minimumHeight != 0 ? Math.max(statusBaseInput.implicitHeight, minimumHeight) minimumHeight
: statusBaseInput.implicitHeight, maximumHeight) : parent.height != 0 ? Math.max(
root.implicitHeight,
minimumHeight) : root.implicitHeight,
maximumHeight) : parent.height
color: Theme.palette.baseColor2 color: Theme.palette.baseColor2
radius: 8 radius: 8
@ -107,16 +91,15 @@ Item {
border.width: 1 border.width: 1
border.color: { border.color: {
if (!statusBaseInput.valid && statusBaseInput.dirty) { if (!root.valid && root.dirty) {
return Theme.palette.dangerColor1; return Theme.palette.dangerColor1
} }
if (edit.activeFocus) { if (edit.activeFocus) {
return Theme.palette.primaryColor1; return Theme.palette.primaryColor1
} }
return sensor.containsMouse ? Theme.palette.primaryColor2 : "transparent" return sensor.containsMouse ? Theme.palette.primaryColor2 : "transparent"
} }
MouseArea { MouseArea {
id: sensor id: sensor
enabled: !edit.activeFocus enabled: !edit.activeFocus
@ -127,191 +110,128 @@ Item {
edit.forceActiveFocus() edit.forceActiveFocus()
} }
StatusSmartIdenticon { RowLayout {
id: emoji anchors {
anchors.left: parent.left fill: parent
anchors.leftMargin: 10 leftMargin: root.leftPadding
anchors.verticalCenter: parent.verticalCenter rightMargin: root.rightPadding
icon.width: !statusBaseInput.icon.emoji ? 20 : 30
icon.height: !statusBaseInput.icon.emoji ? 20 : 30
icon.background: statusBaseInput.icon.background
icon.color: statusBaseInput.icon.color
icon.letterSize: statusBaseInput.icon.letterSize
icon.emoji: statusBaseInput.icon.emoji
icon.name: !statusBaseInput.icon.emoji ? statusBaseInput.icon.name : ""
visible: (!!statusBaseInput.icon.emoji || !!statusBaseInput.icon.name) && statusBaseInput.isIconSelectable
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
hoverEnabled: true
enabled: emoji.visible
onClicked: statusBaseInput.iconClicked()
} }
}
StatusIcon {
id: statusIcon
anchors.topMargin: 10
anchors.left: statusBaseInput.leftIcon ? parent.left : undefined
anchors.right: !statusBaseInput.leftIcon ? parent.right : undefined
anchors.leftMargin: 10
anchors.rightMargin: 10
anchors.verticalCenter: parent.verticalCenter
icon: statusBaseInput.icon.name
width: statusBaseInput.icon.width
height: statusBaseInput.icon.height
color: statusBaseInput.icon.color
visible: !!statusBaseInput.icon.name && !statusBaseInput.isIconSelectable
}
Item {
id: statusBaseInputLeftComponentSlot
anchors.left: parent.left
anchors.leftMargin: 12
width: childrenRect.width
height: childrenRect.height
anchors.verticalCenter: parent.verticalCenter
}
Flickable {
id: flick
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: {
if (statusIcon.visible && statusBaseInput.leftIcon) {
return statusIcon.right;
} else if (emoji.visible) {
return emoji.right;
} else if (!!statusBaseInput.leftComponent) {
return statusBaseInputLeftComponentSlot.right;
} else {
return parent.left;
}
}
anchors.right: {
if (!!statusBaseInput.component) {
return statusBaseInputComponentSlot.left
}
return statusIcon.visible && !statusBaseInput.leftIcon ? statusIcon.left : parent.right
}
anchors.leftMargin: (statusIcon.visible && statusBaseInput.leftIcon)
|| !!statusBaseInput.leftComponent ? 8
: statusBaseInput.leftPadding
anchors.rightMargin: {
return clearable ? clearButtonLoader.width + 12 :
(statusIcon.visible && !leftIcon) || !!statusBaseInput.component ? 8 : 0
}
contentWidth: edit.paintedWidth
contentHeight: edit.paintedHeight
boundsBehavior: Flickable.StopAtBounds
QC.ScrollBar.vertical: QC.ScrollBar { interactive: multiline; enabled: multiline }
clip: true clip: true
function ensureVisible(r) {
if (contentX >= r.x) Loader {
contentX = r.x; sourceComponent: {
else if (contentX+width <= r.x+r.width) if (root.leftComponent) return root.leftComponent
contentX = r.x+r.width-width; if (!root.leftIcon) return undefined
if (contentY >= r.y) if (root.icon.emoji) return identiconComponent
contentY = r.y; if (root.icon.name) return isIconSelectable ? identiconComponent : iconComponent
else if (contentY+height <= r.y+r.height) return undefined
contentY = r.y+r.height-height; }
} }
TextEdit {
id: edit Flickable {
property string previousText: text id: flick
property var keyEvent
width: flick.width Layout.fillHeight: true
height: flick.height Layout.fillWidth: true
verticalAlignment: Text.AlignVCenter Layout.topMargin: root.topPadding
selectByMouse: true Layout.bottomMargin: root.bottomPadding
selectionColor: Theme.palette.primaryColor2
selectedTextColor: color contentWidth: edit.paintedWidth
focus: true contentHeight: edit.paintedHeight
font.pixelSize: 15 boundsBehavior: Flickable.StopAtBounds
font.family: Theme.palette.baseFont.name QC.ScrollBar.vertical: QC.ScrollBar {
color: Theme.palette.directColor1 interactive: multiline
onCursorRectangleChanged: { flick.ensureVisible(cursorRectangle); } enabled: multiline
wrapMode: statusBaseInput.multiline ? Text.WrapAtWordBoundaryOrAnywhere : TextEdit.NoWrap }
onActiveFocusChanged: { clip: true
if (statusBaseInput.pristine) {
statusBaseInput.pristine = false function ensureVisible(r) {
} if (contentX >= r.x)
contentX = r.x
else if (contentX + width <= r.x + r.width)
contentX = r.x + r.width - width
if (contentY >= r.y)
contentY = r.y
else if (contentY + height <= r.y + r.height)
contentY = r.y + r.height - height
} }
Keys.onPressed: { TextEdit {
edit.keyEvent = event.key; id: edit
}
Keys.onReturnPressed: { property string previousText: text
if (multiline) {
event.accepted = false
} else {
event.accepted = true
}
}
Keys.onEnterPressed: { width: flick.width
if (multiline) { height: flick.height
event.accepted = false verticalAlignment: Text.AlignVCenter
} else { selectByMouse: true
event.accepted = true selectionColor: Theme.palette.primaryColor2
} selectedTextColor: color
} focus: true
Keys.forwardTo: [statusBaseInput]
onTextChanged: {
statusBaseInput.dirty = true
if (statusBaseInput.maximumLength > 0) {
if (text.length > statusBaseInput.maximumLength) {
var cursor = cursorPosition;
text = previousText;
if (cursor > text.length) {
cursorPosition = text.length;
} else {
cursorPosition = cursor-1;
}
}
previousText = text
}
}
StatusBaseText {
id: placeholder
visible: (edit.text.length === 0)
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: statusBaseInput.rightPadding
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15 font.pixelSize: 15
elide: StatusBaseText.ElideRight
font.family: Theme.palette.baseFont.name font.family: Theme.palette.baseFont.name
color: statusBaseInput.enabled ? Theme.palette.baseColor1 : color: Theme.palette.directColor1
Theme.palette.directColor6 wrapMode: root.multiline ? Text.WrapAtWordBoundaryOrAnywhere : TextEdit.NoWrap
Keys.onReturnPressed: event.accepted = !multiline
Keys.onEnterPressed: event.accepted = !multiline
Keys.forwardTo: [statusBaseInput]
onCursorRectangleChanged: flick.ensureVisible(cursorRectangle)
onActiveFocusChanged: if (root.pristine) root.pristine = false
onTextChanged: {
root.dirty = true
if (root.maximumLength > 0) {
if (text.length > root.maximumLength) {
var cursor = cursorPosition
text = previousText
if (cursor > text.length) {
cursorPosition = text.length
} else {
cursorPosition = cursor - 1
}
}
previousText = text
}
}
StatusBaseText {
id: placeholder
visible: (edit.text.length === 0)
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: root.rightPadding
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 15
elide: StatusBaseText.ElideRight
font.family: Theme.palette.baseFont.name
color: root.enabled ? Theme.palette.baseColor1 : Theme.palette.directColor6
}
}
} // Flickable
Loader {
sourceComponent: {
if (root.rightComponent) return root.rightComponent
if (root.clearable) return clearButton
if (root.leftIcon) return undefined
if (root.icon.emoji) return identiconComponent
if (root.icon.name) return isIconSelectable ? identiconComponent : iconComponent
return undefined
} }
} }
} // Flickable
Item {
id: statusBaseInputComponentSlot
anchors.right: parent.right
anchors.rightMargin: 12
width: childrenRect.width
height: childrenRect.height
anchors.verticalCenter: parent.verticalCenter
} }
} }
} // Rectangle } // Rectangle
Loader {
id: clearButtonLoader Component {
sourceComponent: StatusFlatRoundButton { id: clearButton
id: clearButton
visible: edit.text.length != 0 && StatusFlatRoundButton {
statusBaseInput.clearable && visible: edit.text.length != 0 && root.clearable && !root.multiline
!statusBaseInput.multiline && && edit.activeFocus
edit.activeFocus
type: StatusFlatRoundButton.Type.Secondary type: StatusFlatRoundButton.Type.Secondary
width: 24 width: 24
height: 24 height: 24
@ -325,5 +245,41 @@ Item {
} }
} }
Component {
id: identiconComponent
StatusSmartIdenticon {
id: identicon
icon.width: !root.icon.emoji ? 20 : 30
icon.height: !root.icon.emoji ? 20 : 30
icon.background: root.icon.background
icon.color: root.icon.color
icon.letterSize: root.icon.letterSize
icon.emoji: root.icon.emoji
icon.name: !root.icon.emoji ? root.icon.name : ""
MouseArea {
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
anchors.fill: parent
hoverEnabled: true
enabled: identicon.visible
onClicked: root.iconClicked()
}
}
}
Component {
id: iconComponent
StatusIcon {
id: statusIcon
icon: root.icon.name
width: root.icon.width
height: root.icon.height
color: root.icon.color
}
}
} }