pragma ComponentBehavior: Bound import QtQuick import Weave.Controls import Weave.Templates as T import "internal" T.SpinBox { id: control implicitWidth: Math.max(implicitContentWidth + leftPadding + rightPadding, Theme.component.input.minHeight) implicitHeight: Math.max(implicitContentHeight + topPadding + bottomPadding, Theme.component.input.minHeight) leftPadding: { if (!mirrored) { return Math.max(T.TableLayout.leftLayoutPadding, _styleAttributes.paddingLeft) } else if (style === T.SpinBox.Box) { return Theme.component.input.numeric.box.spinnerContainer.width } else { return Math.max(up.implicitIndicatorWidth, down.implicitIndicatorWidth) } } rightPadding: { if (mirrored) { return Math.max(T.TableLayout.rightLayoutPadding, _styleAttributes.paddingRight) } else if (style === T.SpinBox.Box) { return Theme.component.input.numeric.box.spinnerContainer.width } else { return Math.max(up.implicitIndicatorWidth, down.implicitIndicatorWidth) } } topPadding: Math.max(T.TableLayout.topLayoutPadding, _styleAttributes.paddingTop) bottomPadding: bottomInset + Math.max(T.TableLayout.bottomLayoutPadding, _styleAttributes.paddingBottom) bottomInset: (control._messageLoader.active ? control._messageLoader.height : 0) font.family: Theme.component.label.fontFamily font.pixelSize: Theme.component.input.fontSize font.weight: Theme.component.input.fontWeight hoverEnabled: control.enabled FontMetrics { id: metrics font: control.font } property Item _messageLoader: TextInputMessageLoader { parent: control y: control.height - height width: control.width message: control.message feedback: control.feedback toolTip: control.feedbackToolTip active: control.message.length > 0 } contentItem: T.TextField { id: textField text: control.displayText font: control.font color: Theme.component.input.textColor selectionColor: control.feedback === Feedback.LouderError ? Theme.component.input.error.backgroundColor.selected : Theme.component.input.backgroundColor.selected selectedTextColor: color verticalAlignment: TextInput.AlignVCenter leftPadding: control.mirrored ? (indicatorsRow.visible ? indicatorsRow.width : warningLoader.width) + Theme.component.input.error.iconContainer.marginLeft : decorationLoader.width rightPadding: control.mirrored ? decorationLoader.width : (indicatorsRow.visible ? indicatorsRow.width : warningLoader.width) + Theme.component.input.error.iconContainer.marginLeft // TextInput has no line height property. So long as line wrapping isn't enabled we can compensate with some additional padding. topPadding: Math.floor(Theme.component.input.lineHeight - metrics.height) / 2 bottomPadding: Math.floor(Theme.component.input.lineHeight - metrics.height) / 2 implicitHeight: Theme.component.input.lineHeight + topPadding + bottomPadding implicitWidth: implicitWidthMetrics.boundingRect.x + implicitWidthMetrics.boundingRect.width + leftPadding + rightPadding readOnly: !control.editable validator: control.validator inputMethodHints: control.inputMethodHints selectByMouse: true opacity: control.enabled ? 1.0 : Theme.component.input.opacity.disabled TextMetrics { id: implicitWidthMetrics font: textField.font text: textField.text } T.DecorationItemLoader { id: decorationLoader x: mirrored ? textField.width - width : 0 y: control.T.TableLayout.topPadding height: Theme.component.input.minHeight - control.T.TableLayout.topPadding - control.T.TableLayout.bottomPadding delegateItem: control sourceComponent: control.decoration leftMargin: Theme.component.menu.icon.marginLeft rightMargin: Theme.component.menu.icon.marginRight topMargin: Theme.component.menu.icon.marginTop bottomMargin: Theme.component.menu.icon.marginBottom } T.TableLayoutLoader { id: warningLoader x: mirrored ? textField.leftPadding - width : textField.width - textField.rightPadding y: decorationLoader.y active: control.feedback !== Feedback.None && !indicatorsRow.visible && control.message.length === 0 verticalItemAlignment: TableLayout.AlignVCenter sourceComponent: InputErrorIcon { id: inputErrorIcon MouseArea { id: hoverDetector anchors.fill: parent enabled: control.feedbackToolTip.text.length > 0 hoverEnabled: true } property Component defaultContent: ToolTipContent {} ToolTip.content: control.feedbackToolTip.content ? control.feedbackToolTip.content : defaultContent ToolTip.text: control.feedbackToolTip.text ToolTip.delay: control.feedbackToolTip.delay ToolTip.timeout: control.feedbackToolTip.timeout ToolTip.preferredAlignment: control.feedbackToolTip.preferredAlignment ToolTip.visible: hoverDetector.containsMouse || (ToolTip.toolTip.parent === inputErrorIcon && ToolTip.toolTip.hovered) || (control.feedbackToolTip.visible) } } T.TableLayoutRow { id: indicatorsRow visible: indicatorsRow.children.length > 0 x: mirrored ? textField.leftPadding - width : textField.width - textField.rightPadding y: decorationLoader.y verticalItemAlignment: TableLayout.AlignVCenter children: control.indicators } } background: T.BackgroundItemLoader { delegateItem: control opacity: control.enabled ? 1.0 : Theme.component.input.opacity.disabled sourceComponent: TextInputBackground { id: backgroundItem style: control.style focused: control.activeFocus hovered: control.hovered error: control.feedback !== Feedback.None louder: control.feedback === Feedback.LouderError color: control._styleAttributes.backgroundColor Rectangle { x: control.mirrored ? control.leftPadding : backgroundItem.width - width - control.rightPadding width: Theme.component.input.numeric.box.spinnerContainer.borderLeftWidth // prevent overlap over the bottom highlight border if it is visible. height: parent.height - ((control.feedback !== Feedback.None || (control.enabled && control.hovered) || (control.activeFocus || control.visualFocus)) ? backgroundItem.bottomBorderWidth : 0) color: Theme.component.input.numeric.box.spinnerContainer.borderLeftColor visible: control.style === T.SpinBox.Box && (control.up.indicator || control.down.indicator) } } } up.indicator: TableLayoutRow { x: control.width - width width: mirrored ? control.leftPadding : control.rightPadding height: (control.height - control.bottomInset) / 2 leftMargin: Theme.component.input.numeric.spinnerUp.paddingLeft rightMargin: Theme.component.input.numeric.spinnerUp.paddingRight topMargin: Theme.component.input.numeric.spinnerUp.paddingTop bottomMargin: Theme.component.input.numeric.spinnerUp.paddingBottom horizontalItemFillMode: TableLayout.Preferred verticalItemFillMode: TableLayout.Preferred opacity: control.enabled ? 1.0 : Theme.component.input.opacity.disabled T.IconImage { name: Theme.icon.medium("caret-up") // TODO: Theme.component.input.numeric.spinnerUp.icon.name color: control.up.pressed ? Theme.component.input.numeric.spinner.icon.fill.pressed : (control.enabled && control.up.hovered) ? Theme.component.input.numeric.spinner.icon.fill.hover : Theme.component.input.numeric.spinner.icon.fill.default verticalAlignment: Image.AlignBottom } } down.indicator: TableLayoutRow { x: control.width - width y: control.height - control.bottomInset - height width: mirrored ? control.leftPadding : control.rightPadding height: (control.height - control.bottomInset) / 2 leftMargin: Theme.component.input.numeric.spinnerDown.paddingLeft rightMargin: Theme.component.input.numeric.spinnerDown.paddingRight topMargin: Theme.component.input.numeric.spinnerDown.paddingTop bottomMargin: Theme.component.input.numeric.spinnerDown.paddingBottom horizontalItemFillMode: TableLayout.Preferred verticalItemFillMode: TableLayout.Preferred opacity: control.enabled ? 1.0 : Theme.component.input.opacity.disabled T.IconImage { name: Theme.icon.medium("caret-down") // TODO: Theme.component.input.numeric.spinnerDown.icon.name color: control.down.pressed ? Theme.component.input.numeric.spinner.icon.fill.pressed : (control.enabled && control.down.hovered) ? Theme.component.input.numeric.spinner.icon.fill.hover : Theme.component.input.numeric.spinner.icon.fill.default verticalAlignment: Image.AlignTop } } }