// SPDX-License-Identifier: LGPL-3.0-or-later import QtQuick 2.12 import QtQuick.Controls 2.12 TextEdit { id: label font.family: theme.fontFamily.sans font.pixelSize: theme.fontSize.normal color: theme.colors.text textFormat: Label.PlainText tabStopDistance: 4 * 4 // 4 spaces readOnly: true persistentSelection: true activeFocusOnPress: false focus: false onLinkActivated: Qt.openUrlExternally(link) Component.onCompleted: updateSelection() // If index is a whole number, the label will get two \n before itself // in container.joinedSelection. If it's a decimal number, if gets one \n. property real index property HSelectableLabelContainer container property bool selectable: true function updateSelection() { if (! selectable && label.selectedText) { label.deselect() updateContainerSelectedTexts() return } if (! selectable) return if (! container.reversed && container.selectionStart <= container.selectionEnd || container.reversed && container.selectionStart > container.selectionEnd) { var first = container.selectionStart var firstPos = container.selectionStartPosition var last = container.selectionEnd var lastPos = container.selectionEndPosition } else { var first = container.selectionEnd var firstPos = container.selectionEndPosition var last = container.selectionStart var lastPos = container.selectionStartPosition } if (first === index && last === index) { select( label.positionAt(firstPos.x, firstPos.y), label.positionAt(lastPos.x, lastPos.y), ) } else if ((! container.reversed && first < index && index < last) || (container.reversed && first > index && index > last)) { label.selectAll() } else if (first === index) { label.select(positionAt(firstPos.x, firstPos.y), length) } else if (last === index) { label.select(0, positionAt(lastPos.x, lastPos.y)) } else { label.deselect() } updateContainerSelectedTexts() } function updateContainerSelectedTexts() { container.selectedTexts[index] = selectedText container.selectedTextsChanged() } function selectWordAt(position) { container.clearSelection() label.cursorPosition = positionAt(position.x, position.y) label.selectWord() updateContainerSelectedTexts() } function selectAllText() { container.clearSelection() label.selectAll() updateContainerSelectedTexts() } Connections { target: container onSelectionInfoChanged: updateSelection() onDeselectAll: deselect() } DropArea { anchors.fill: parent onPositionChanged: { if (! container.selecting) { container.clearSelection() container.selectionStart = index container.selectionStartPosition = Qt.point(drag.x, drag.y) container.selecting = true } else { container.selectionEnd = index container.selectionEndPosition = Qt.point(drag.x, drag.y) } } } TapHandler { acceptedButtons: Qt.LeftButton onTapped: { tapCount === 2 ? selectWordAt(eventPoint.position) : tapCount === 3 ? selectAllText() : container.clearSelection() } } PointHandler { onActiveChanged: active ? container.dragStarted() : container.dragStopped() onPointChanged: container.dragPointChanged(point) } MouseArea { anchors.fill: label acceptedButtons: Qt.NoButton cursorShape: label.hoveredLink ? Qt.PointingHandCursor : Qt.IBeamCursor } }