refactor(StatusBaseInput): use RowLayout for position management
This commit is contained in:
parent
ffb7289b9f
commit
f2c832e015
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue