Revision control

++ // Copyright (C) 2017 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ import QtQuick
++ // Deliberately imported after QtQuick to avoid missing restoreMode property in Binding. Fix in Qt 6.
++ import QtQml
++ import QtQuick.VirtualKeyboard
++ import QtQuick.VirtualKeyboard.Settings
++
++ Item {
++ id: control
++ property alias textEdit: shadowInput
++
++ property real contentWidth
++ property real contentHeight
++
++ enabled: keyboard.active && VirtualKeyboardSettings.fullScreenMode
++
++ MouseArea {
++ anchors.fill: parent
++ }
++
++ onXChanged: InputContext.priv.shadow.updateSelectionProperties()
++ onYChanged: InputContext.priv.shadow.updateSelectionProperties()
++
++ Binding {
++ control.contentWidth: flickable.contentWidth + 2 * (keyboard.style.fullScreenInputMargins + keyboard.style.fullScreenInputPadding) + shadowInput.cursorRectangle.width
++ control.contentHeight: flickable.contentHeight + 2 * (keyboard.style.fullScreenInputMargins + keyboard.style.fullScreenInputPadding)
++ when: keyboard.style
++ }
++
++ Loader {
++ id: containerBackground
++ sourceComponent: keyboard.style.fullScreenInputContainerBackground
++ anchors.fill: parent
++ }
++
++ Loader {
++ id: fullScreenInputBackground
++ sourceComponent: keyboard.style.fullScreenInputBackground
++ anchors.fill: parent
++ anchors.margins: keyboard.style.fullScreenInputMargins
++ }
++
++ Flickable {
++ id: flickable
++ clip: true
++ width: containerBackground.width
++ height: containerBackground.height
++ Binding {
++ flickable.x: keyboard.style.fullScreenInputMargins + keyboard.style.fullScreenInputPadding
++ flickable.width: containerBackground.width - 2 * (keyboard.style.fullScreenInputMargins + keyboard.style.fullScreenInputPadding)
++ when: keyboard.style
++ }
++ flickableDirection: Flickable.HorizontalFlick
++ interactive: contentWidth > width
++ contentWidth: shadowInput.contentWidth + 2 * shadowInput.padding + shadowInput.cursorRectangle.width
++ contentHeight: shadowInput.contentHeight + 2 * shadowInput.padding
++ onContentXChanged: InputContext.priv.shadow.updateSelectionProperties()
++
++ function ensureVisible(rectangle) {
++ if (contentX >= rectangle.x)
++ contentX = rectangle.x
++ else if (contentX + width <= rectangle.x + rectangle.width)
++ contentX = rectangle.x + rectangle.width - width;
++ }
++
++ TextInput {
++ id: shadowInput
++ objectName: "shadowInput"
++ property bool blinkStatus: true
++ Binding {
++ shadowInput.y: keyboard.style.fullScreenInputMargins
++ when: keyboard.style
++ }
++ width: contentWidth + 1 // cursorRectangle.width causes binding loop
++ topPadding: keyboard.style.fullScreenInputPadding
++ bottomPadding: keyboard.style.fullScreenInputPadding
++ activeFocusOnPress: false
++ font: keyboard.style.fullScreenInputFont
++ inputMethodHints: InputContext.inputMethodHints
++ cursorDelegate: keyboard.style.fullScreenInputCursor
++ passwordCharacter: keyboard.style.fullScreenInputPasswordCharacter
++ color: keyboard.style.fullScreenInputColor
++ selectionColor: keyboard.style.fullScreenInputSelectionColor
++ selectedTextColor: keyboard.style.fullScreenInputSelectedTextColor
++ // Mask PasswordEchoOnEdit like Password: this input never has the
++ // active focus, so it must not echo the text in clear.
++ echoMode: keyboard.inputItemEchoMode === TextInput.PasswordEchoOnEdit ?
++ TextInput.Password : keyboard.inputItemEchoMode
++ selectByMouse: !!InputContext.priv.inputItem && !!InputContext.priv.inputItem.selectByMouse
++ onCursorPositionChanged: {
++ cursorSyncTimer.restart()
++ blinkStatus = true
++ if (cursorTimer.running)
++ cursorTimer.restart()
++ }
++ onSelectionStartChanged: cursorSyncTimer.restart()
++ onSelectionEndChanged: cursorSyncTimer.restart()
++ onCursorRectangleChanged: flickable.ensureVisible(cursorRectangle)
++
++ function getAnchorPosition() {
++ if (selectionStart == selectionEnd)
++ return cursorPosition
++ else if (selectionStart == cursorPosition)
++ return selectionEnd
++ else
++ return selectionStart
++ }
++
++ Timer {
++ id: cursorSyncTimer
++ interval: 0
++ onTriggered: {
++ var anchorPosition = shadowInput.getAnchorPosition()
++ if (anchorPosition !== InputContext.anchorPosition || shadowInput.cursorPosition !== InputContext.cursorPosition)
++ InputContext.priv.forceCursorPosition(anchorPosition, shadowInput.cursorPosition)
++ }
++ }
++
++ Timer {
++ id: cursorTimer
++ interval: Qt.styleHints.cursorFlashTime / 2
++ repeat: true
++ running: control.visible
++ onTriggered: shadowInput.blinkStatus = !shadowInput.blinkStatus
++ }
++ }
++ }
++
++ Component.onCompleted: {
++ if (VirtualKeyboardSettings.fullScreenMode) {
++ InputContext.priv.shadow.inputItem = shadowInput
++ }
++ }
++ Connections {
++ target: VirtualKeyboardSettings
++ function onFullScreenModeChanged() {
++ InputContext.priv.shadow.inputItem = VirtualKeyboardSettings.fullScreenMode ? shadowInput : null
++ }
++ }
++ Connections {
++ target: InputContext.priv.shadow
++ function onInputItemChanged() {
++ cursorSyncTimer.stop()
++ if (!InputContext.priv.shadow.inputItem)
++ shadowInput.clear()
++ }
++ }
++ }