Fix Contact edit on messing mouse focus (regression from Qt 5.15.12)

This commit is contained in:
Julien Wadel 2023-03-03 17:16:11 +01:00
parent 4532e278ac
commit 669f47858b
4 changed files with 226 additions and 204 deletions

View file

@ -16,7 +16,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Mute option for each chatrooms.
- New Chat Layout.
## 5.0.11 - undefined
## 5.0.12 - undefined
## Fixed
- Unusable Contact sheet.
## 5.0.11 - 2023-02-24
### Fixed
- Display of non-Ascii avatar

View file

@ -67,6 +67,7 @@ function addValue (value) {
}
function handleEditionFinished (index, text) {
if(index<0) return
var model = values.model
var oldValue = model.get(index).$value

View file

@ -8,104 +8,117 @@ import Common.Styles 1.0
// =============================================================================
Item {
property alias color: textInput.color
property alias font: textInput.font
property alias inputMethodHints: textInput.inputMethodHints
property alias placeholder: placeholder.text
property alias readOnly: textInput.readOnly
property alias text: textInput.text
property bool forceFocus: false
property bool isInvalid: false
property int padding: TransparentTextInputStyle.padding
// ---------------------------------------------------------------------------
signal editingFinished
// ---------------------------------------------------------------------------
onActiveFocusChanged: {
if (activeFocus) {
textInput.focus = true
}
}
Rectangle {
id: background
color: (textInput.activeFocus || parent.forceFocus) && !textInput.readOnly
? TransparentTextInputStyle.backgroundColor.color
: // No Style constant, see component name.
// It's a `transparent` TextInput.
'transparent'
height: parent.height
width: {
var width = textInput.contentWidth + parent.padding * 2
return width < parent.width ? width : parent.width
}
InvertedMouseArea {
anchors.fill: parent
enabled: textInput.activeFocus
onPressed: textInput.focus = false
}
}
Icon {
id: icon
anchors.left: background.right
height: background.height
icon: 'generic_error'
iconSize: TransparentTextInputStyle.iconSize
visible: parent.isInvalid
}
Text {
id: placeholder
anchors.centerIn: parent
color: TransparentTextInputStyle.placeholder.colorModel.color
elide: Text.ElideRight
font {
italic: true
pointSize: TransparentTextInputStyle.placeholder.pointSize
}
height: textInput.height
width: textInput.width
verticalAlignment: Text.AlignVCenter
visible: textInput.text.length === 0 && (!textInput.activeFocus || textInput.readOnly)
}
TextInput {
id: textInput
anchors.centerIn: parent
height: parent.height
width: parent.width - parent.padding * 2
clip: true
color: activeFocus && !readOnly
? TransparentTextInputStyle.text.color.focused.color
: TransparentTextInputStyle.text.color.normal.color
font.pointSize: TransparentTextInputStyle.text.pointSize
selectByMouse: true
verticalAlignment: TextInput.AlignVCenter
Keys.onEscapePressed: focus = false
Keys.onEnterPressed: focus = false
Keys.onReturnPressed: focus = false
onEditingFinished: {
cursorPosition = 0
if (!parent.readOnly) {
parent.editingFinished()
}
}
}
property alias color: textInput.color
property alias font: textInput.font
property alias inputMethodHints: textInput.inputMethodHints
property alias placeholder: placeholder.text
property alias readOnly: textInput.readOnly
property alias text: textInput.oldText
property bool forceFocus: false
property bool isInvalid: false
property int padding: TransparentTextInputStyle.padding
// ---------------------------------------------------------------------------
signal editingFinished
// ---------------------------------------------------------------------------
onActiveFocusChanged: {
if (activeFocus) {
textInput.forceActiveFocus()
}
}
Rectangle {
id: background
property bool displayBackground: (textInput.activeFocus || parent.forceFocus) && !textInput.readOnly
color: displayBackground
? TransparentTextInputStyle.backgroundColor.color
: // No Style constant, see component name.
// It's a `transparent` TextInput.
'transparent'
height: parent.height
width: {
var width = textInput.contentWidth + parent.padding * 2
return width < parent.width ? width : parent.width
}
InvertedMouseArea {
anchors.fill: parent
enabled: textInput.activeFocus
onPressed: textInput.updateText()
}
}
Icon {
id: icon
anchors.left: background.right
height: background.height
icon: 'generic_error'
iconSize: TransparentTextInputStyle.iconSize
visible: parent.isInvalid
}
Text {
id: placeholder
anchors.centerIn: parent
color: TransparentTextInputStyle.placeholder.colorModel.color
elide: Text.ElideRight
font {
italic: true
pointSize: TransparentTextInputStyle.placeholder.pointSize
}
height: textInput.height
width: textInput.width
verticalAlignment: Text.AlignVCenter
visible: textInput.text.length === 0 && (!textInput.activeFocus || textInput.readOnly)
}
TextInput {
id: textInput
anchors.centerIn: parent
height: parent.height
width: parent.width - parent.padding * 2
clip: true
color: activeFocus && !readOnly
? TransparentTextInputStyle.text.color.focused.color
: TransparentTextInputStyle.text.color.normal.color
font.pointSize: TransparentTextInputStyle.text.pointSize
selectByMouse: true
verticalAlignment: TextInput.AlignVCenter
Keys.onEscapePressed: cancelText()
Keys.onEnterPressed: textInput.updateText()
Keys.onReturnPressed: textInput.updateText()
property string oldText
onOldTextChanged: if(text!=oldText) text = oldText
function cancelText(){
text = oldText
focus = false
}
function updateText(){
cursorPosition = 0
oldText = text
if (!parent.readOnly) {
parent.editingFinished()
}
focus = false
}
onEditingFinished: {
if(focus){
updateText()
}
}
}
}

View file

@ -8,107 +8,109 @@ import Utils 1.0
// =============================================================================
Item {
id: item
// ---------------------------------------------------------------------------
property bool _mouseAlwaysOutside
property var _mouseArea: null
// ---------------------------------------------------------------------------
// When emitted, returns a function to test if the click
// is on a specific item. It takes only a item parameter.
signal pressed (var pointIsInItem)
// ---------------------------------------------------------------------------
function _createMouseArea () {
var parent = Utils.getTopParent(item, true)
if (_mouseArea == null) {
_mouseArea = builder.createObject()
}
_mouseArea.parent = parent
// Must be true if a fake parent is used and if `mouseArea`
// is not in the same window that `item`.
_mouseAlwaysOutside =
_mouseArea.parent !== Utils.getTopParent(item)
}
function _deleteMouseArea () {
if (_mouseArea != null) {
_mouseArea.destroy()
_mouseArea = null
}
}
// ---------------------------------------------------------------------------
// It's necessary to use a `enabled` variable.
// See: http://doc.qt.io/qt-5/qml-qtqml-component.html#completed-signal
//
// The creation order of components in a view is undefined,
// so the mouse area must be created only when the target component
// was completed.
Component.onCompleted: enabled && _createMouseArea()
Component.onDestruction: _deleteMouseArea()
onEnabledChanged: {
_deleteMouseArea()
if (enabled) {
_createMouseArea()
}
}
Component {
id: builder
MouseArea {
cursorShape: Qt.ArrowCursor
property var _timeout
function _checkPosition (positionEvent) {
// Propagate event.
positionEvent.accepted = false
// Click is outside or not.
if (
_mouseAlwaysOutside ||
!Utils.pointIsInItem(this, item, positionEvent)
) {
if (_timeout != null) {
// Remove existing timeout to avoid the creation of
// many children.
Utils.clearTimeout(_timeout)
}
// Use a asynchronous call that is executed
// after the propagated event.
//
// It's useful to ensure the window's context is not
// modified with the positionEvent before the `onPressed`
// call.
//
// The timeout is destroyed with the `MouseArea` component.
_timeout = Utils.setTimeout(this, 0, item.pressed.bind(
this,
(function (point, item) {
return Utils.pointIsInItem(this, item, point)
}).bind(this, { x: positionEvent.x, y: positionEvent.y })
))
}
}
anchors.fill: parent
propagateComposedEvents: true
z: Constants.zMax
onPressed: _checkPosition.call(this, mouse)
onWheel: _checkPosition.call(this, wheel)
}
}
id: mainItem
// ---------------------------------------------------------------------------
property bool _mouseAlwaysOutside
property var _mouseArea: null
// ---------------------------------------------------------------------------
// When emitted, returns a function to test if the click
// is on a specific item. It takes only a item parameter.
signal pressed (var pointIsInItem)
// ---------------------------------------------------------------------------
function _createMouseArea () {
var parent = Utils.getTopParent(mainItem, true)
if (_mouseArea == null) {
_mouseArea = builder.createObject()
}
_mouseArea.parent = parent
// Must be true if a fake parent is used and if `mouseArea`
// is not in the same window that `item`.
_mouseAlwaysOutside =
_mouseArea.parent !== Utils.getTopParent(mainItem)
}
function _deleteMouseArea () {
if (_mouseArea != null) {
_mouseArea.destroy()
_mouseArea = null
}
}
// ---------------------------------------------------------------------------
// It's necessary to use a `enabled` variable.
// See: http://doc.qt.io/qt-5/qml-qtqml-component.html#completed-signal
//
// The creation order of components in a view is undefined,
// so the mouse area must be created only when the target component
// was completed.
Component.onCompleted: enabled && _createMouseArea()
Component.onDestruction: _deleteMouseArea()
onEnabledChanged: {
_deleteMouseArea()
if (enabled) {
_createMouseArea()
}
}
Component {
id: builder
MouseArea {
id: area
cursorShape: Qt.ArrowCursor
preventStealing: true
property var _timeout
function _checkPosition (positionEvent) {
// Propagate event.
positionEvent.accepted = false
// Click is outside or not.
if (
_mouseAlwaysOutside ||
!Utils.pointIsInItem(area, mainItem, positionEvent)
) {
if (_timeout != null) {
// Remove existing timeout to avoid the creation of
// many children.
Utils.clearTimeout(_timeout)
}
// Use a asynchronous call that is executed
// after the propagated event.
//
// It's useful to ensure the window's context is not
// modified with the positionEvent before the `onPressed`
// call.
//
// The timeout is destroyed with the `MouseArea` component.
_timeout = Utils.setTimeout(area, 0, mainItem.pressed.bind(
this,
(function (point, item) {
return Utils.pointIsInItem(area, item, point)
}).bind(this, { x: positionEvent.x, y: positionEvent.y })
))
}
}
anchors.fill: parent
propagateComposedEvents: true
z: Constants.zMax
onPressed: _checkPosition.call(area, mouse)
onWheel: _checkPosition.call(area, wheel)
}
}
}