Files
noctalia-shell/Widgets/NTextInput.qml
2025-11-18 19:17:25 -05:00

223 lines
6.5 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.Commons
ColumnLayout {
id: root
property string label: ""
property string description: ""
property string inputIconName: ""
property bool readOnly: false
property bool enabled: true
property color labelColor: Color.mOnSurface
property color descriptionColor: Color.mOnSurfaceVariant
property string fontFamily: Settings.data.ui.fontDefault
property real fontSize: Style.fontSizeS
property int fontWeight: Style.fontWeightRegular
property alias text: input.text
property alias placeholderText: input.placeholderText
property alias inputMethodHints: input.inputMethodHints
property alias inputItem: input
signal editingFinished
spacing: Style.marginS
NLabel {
label: root.label
description: root.description
labelColor: root.labelColor
descriptionColor: root.descriptionColor
visible: root.label !== "" || root.description !== ""
Layout.fillWidth: true
}
// An active control that blocks input, to avoid events leakage and dragging stuff in the background.
Control {
id: frameControl
Layout.fillWidth: true
Layout.minimumWidth: 80 * Style.uiScaleRatio
implicitHeight: Style.baseWidgetSize * 1.1 * Style.uiScaleRatio
// This is important - makes the control accept focus
focusPolicy: Qt.StrongFocus
hoverEnabled: true
background: Rectangle {
id: frame
radius: Style.radiusM
color: Color.mSurface
border.color: input.activeFocus ? Color.mSecondary : Color.mOutline
border.width: Style.borderS
Behavior on border.color {
ColorAnimation {
duration: Style.animationFast
}
}
}
contentItem: Item {
// Invisible background that captures ALL mouse events
MouseArea {
id: backgroundCapture
anchors.fill: parent
z: 0
acceptedButtons: Qt.AllButtons
hoverEnabled: true
preventStealing: true
propagateComposedEvents: false
onPressed: mouse => {
mouse.accepted = true;
// Focus the input and position cursor
input.forceActiveFocus();
var inputPos = mapToItem(inputContainer, mouse.x, mouse.y);
if (inputPos.x >= 0 && inputPos.x <= inputContainer.width) {
var textPos = inputPos.x - Style.marginM;
if (textPos >= 0 && textPos <= input.width) {
input.cursorPosition = input.positionAt(textPos, input.height / 2);
}
}
}
onReleased: mouse => {
mouse.accepted = true;
}
onDoubleClicked: mouse => {
mouse.accepted = true;
input.selectAll();
}
onPositionChanged: mouse => {
mouse.accepted = true;
}
onWheel: wheel => {
wheel.accepted = true;
}
}
// Container for the actual text field
Item {
id: inputContainer
anchors.fill: parent
anchors.leftMargin: Style.marginM
// anchors.rightMargin: Style.marginM
clip: true
z: 1
RowLayout {
anchors.fill: parent
spacing: 0
NIcon {
id: inputIcon
icon: root.inputIconName
visible: root.inputIconName !== ""
enabled: false
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: visible ? Style.marginS : 0
}
TextField {
id: input
Layout.fillWidth: true
Layout.fillHeight: true
verticalAlignment: TextInput.AlignVCenter
echoMode: TextInput.Normal
readOnly: root.readOnly
enabled: root.enabled
color: Color.mOnSurface
placeholderTextColor: Qt.alpha(Color.mOnSurfaceVariant, 0.6)
selectByMouse: true
topPadding: 0
bottomPadding: 0
leftPadding: 0
rightPadding: 0
background: null
font.family: root.fontFamily
font.pointSize: root.fontSize * Style.uiScaleRatio
font.weight: root.fontWeight
onEditingFinished: root.editingFinished()
// Override mouse handling to prevent propagation
MouseArea {
id: textFieldMouse
anchors.fill: parent
acceptedButtons: Qt.AllButtons
preventStealing: true
propagateComposedEvents: false
cursorShape: Qt.IBeamCursor
property int selectionStart: 0
onPressed: mouse => {
mouse.accepted = true;
input.forceActiveFocus();
var pos = input.positionAt(mouse.x, mouse.y);
input.cursorPosition = pos;
selectionStart = pos;
}
onPositionChanged: mouse => {
if (mouse.buttons & Qt.LeftButton) {
mouse.accepted = true;
var pos = input.positionAt(mouse.x, mouse.y);
input.select(selectionStart, pos);
}
}
onDoubleClicked: mouse => {
mouse.accepted = true;
input.selectAll();
}
onReleased: mouse => {
mouse.accepted = true;
}
onWheel: wheel => {
wheel.accepted = true;
}
}
}
NIconButton {
id: clearButton
icon: "x"
tooltipText: I18n.tr("widgets.text-input.clear")
Layout.alignment: Qt.AlignVCenter
border.width: 0
colorBg: Color.transparent
colorBgHover: Color.transparent
colorFg: Color.mOnSurface
colorFgHover: Color.mError
visible: input.text.length > 0 && !root.readOnly
enabled: input.text.length > 0 && !root.readOnly
onClicked: {
input.clear();
input.forceActiveFocus();
}
}
}
}
}
}
}