mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-23 06:38:07 +00:00
feat(app): many changes:
- InvertedMouseArea use a asynchronous call on pressed event - ListForm use an external style - ListForm supports outside click - ...
This commit is contained in:
parent
2a1d92fa1f
commit
421eae38a3
15 changed files with 255 additions and 113 deletions
19
tests/imgs/add_field.svg
Normal file
19
tests/imgs/add_field.svg
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="80px" height="80px" viewBox="0 0 80 80" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
|
||||
<!-- Generator: Sketch 3.3.3 (12081) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>add_field_over copy</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="OUTILS" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="linphone_v2.0_icones_buttons" sketch:type="MSArtboardGroup" transform="translate(-6981.000000, -12382.000000)">
|
||||
<g id="add_field_over-copy" sketch:type="MSLayerGroup" transform="translate(6981.045368, 12382.656515)">
|
||||
<g id="Oval-1-Copy-2-+-Imported-Layers-Copy-2" sketch:type="MSShapeGroup">
|
||||
<ellipse id="Oval-1-Copy-2" fill="#444444" cx="39.8422909" cy="39.5061728" rx="39.8422909" ry="39.5061728"></ellipse>
|
||||
<g id="Imported-Layers-Copy-2" transform="translate(18.593069, 19.423868)" stroke="#FFFFFF" stroke-width="5" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M35.4786114,34.191652 L7.01983221,5.97295708 M7.02457534,34.191652 L35.4738683,5.97295708" transform="translate(21.249222, 20.082305) rotate(-315.000000) translate(-21.249222, -20.082305) "></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -1,5 +1,6 @@
|
|||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource prefix="/">
|
||||
<file>imgs/add_field.svg</file>
|
||||
<file>imgs/call.svg</file>
|
||||
<file>imgs/cam.svg</file>
|
||||
<file>imgs/chat_attachment.svg</file>
|
||||
|
|
@ -38,12 +39,12 @@
|
|||
<file>ui/modules/Linphone/Dialog/ConfirmDialog.qml</file>
|
||||
<file>ui/modules/Linphone/Dialog/DialogDescription.qml</file>
|
||||
<file>ui/modules/Linphone/Dialog/DialogPlus.qml</file>
|
||||
<file>ui/modules/Linphone/DropZone.qml</file>
|
||||
<file>ui/modules/Linphone/ForceScrollBar.qml</file>
|
||||
<file>ui/modules/Linphone/Form/AbstractTextButton.qml</file>
|
||||
<file>ui/modules/Linphone/Form/ActionBar.qml</file>
|
||||
<file>ui/modules/Linphone/Form/ActionButton.qml</file>
|
||||
<file>ui/modules/Linphone/Form/CheckBoxText.qml</file>
|
||||
<file>ui/modules/Linphone/Form/DropZone.qml</file>
|
||||
<file>ui/modules/Linphone/Form/ExclusiveButtons.qml</file>
|
||||
<file>ui/modules/Linphone/Form/ListForm.qml</file>
|
||||
<file>ui/modules/Linphone/Form/SmallButton.qml</file>
|
||||
|
|
@ -65,6 +66,7 @@
|
|||
<file>ui/modules/Linphone/Styles/Form/ActionBarStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Form/CheckBoxTextStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Form/ExclusiveButtonsStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Form/ListFormStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Form/SmallButtonStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Form/TextButtonAStyle.qml</file>
|
||||
<file>ui/modules/Linphone/Styles/Form/TextButtonBStyle.qml</file>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#include <cstdlib>
|
||||
|
||||
#include <QQmlFileSelector>
|
||||
#include <QMenu>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlFileSelector>
|
||||
#include <QQuickView>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QtDebug>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ Text {
|
|||
// Never created.
|
||||
// Private data for `lupdate`.
|
||||
Item {
|
||||
property variant i18n: [
|
||||
property var i18n: [
|
||||
QT_TR_NOOP('hangup'),
|
||||
QT_TR_NOOP('incomingCall'),
|
||||
QT_TR_NOOP('lostIncomingCall'),
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import QtQuick.Dialogs 1.2
|
|||
// ===================================================================
|
||||
|
||||
Rectangle {
|
||||
signal dropped (variant files)
|
||||
signal dropped (var files)
|
||||
|
||||
color: '#DDDDDD'
|
||||
id: dropZone
|
||||
|
|
@ -5,8 +5,9 @@ import Linphone.Styles 1.0
|
|||
// ===================================================================
|
||||
|
||||
Row {
|
||||
property var texts
|
||||
|
||||
property int _selectedButton: 0
|
||||
property variant texts
|
||||
|
||||
signal clicked (int button)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,106 +1,123 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
|
||||
import Linphone 1.0
|
||||
import Linphone.Styles 1.0
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RowLayout {
|
||||
readonly property int lineHeight: 30
|
||||
property alias model: values.model
|
||||
property alias title: text.text
|
||||
|
||||
property alias title: text.text
|
||||
function _addValue (value) {
|
||||
if (model.count === 0 ||
|
||||
model.get(model.count - 1).$value.length !== 0) {
|
||||
model.append({ $value: value })
|
||||
}
|
||||
}
|
||||
|
||||
spacing: 0
|
||||
function _handleEditionFinished (index, text) {
|
||||
if (text.length === 0) {
|
||||
model.remove(index)
|
||||
} else {
|
||||
model.set(index, { $value: text })
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredHeight: lineHeight
|
||||
spacing: 20
|
||||
spacing: 0
|
||||
|
||||
// Add item in list.
|
||||
ActionButton {
|
||||
Layout.preferredHeight: 16
|
||||
Layout.preferredWidth: 16
|
||||
onClicked: {
|
||||
if (valuesModel.count === 0 ||
|
||||
valuesModel.get(valuesModel.count - 1).$value.length !== 0) {
|
||||
valuesModel.append({ $value: '' })
|
||||
}
|
||||
}
|
||||
}
|
||||
// Title area.
|
||||
RowLayout {
|
||||
Layout.alignment: Qt.AlignTop
|
||||
Layout.preferredHeight: ListFormStyle.lineHeight
|
||||
spacing: ListFormStyle.titleArea.spacing
|
||||
|
||||
// List title.
|
||||
Text {
|
||||
Layout.preferredWidth: 130
|
||||
id: text
|
||||
}
|
||||
// Button: Add item in list.
|
||||
ActionButton {
|
||||
Layout.preferredHeight: ListFormStyle.titleArea.iconSize
|
||||
Layout.preferredWidth: ListFormStyle.titleArea.iconSize
|
||||
icon: ListFormStyle.titleArea.icon
|
||||
|
||||
onClicked: _addValue('')
|
||||
}
|
||||
|
||||
// Content list.
|
||||
ListView {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: values.count * lineHeight
|
||||
id: values
|
||||
interactive: false
|
||||
// Title text.
|
||||
Text {
|
||||
id: text
|
||||
|
||||
model: ListModel {
|
||||
id: valuesModel
|
||||
|
||||
ListElement { $value: 'toto' }
|
||||
ListElement { $value: 'abc' }
|
||||
ListElement { $value: 'machin' }
|
||||
ListElement { $value: 'bidule' }
|
||||
ListElement { $value: 'truc' }
|
||||
}
|
||||
|
||||
delegate: Item {
|
||||
implicitHeight: textEdit.height
|
||||
width: parent.width
|
||||
|
||||
Rectangle {
|
||||
color: textEdit.focus ? '#E6E6E6' : 'transparent'
|
||||
id: background
|
||||
implicitHeight: textEdit.height
|
||||
implicitWidth: textEdit.contentWidth +
|
||||
textEdit.padding * 2
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.fill: textEdit
|
||||
color: '#5A585B'
|
||||
font.italic: true
|
||||
padding: textEdit.padding
|
||||
text: textEdit.text.length === 0 && !textEdit.focus
|
||||
? qsTr('fillPlaceholder')
|
||||
: ''
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
TextEdit {
|
||||
color: focus ? '#000000' : '#5A585B'
|
||||
font.bold: !focus
|
||||
height: lineHeight
|
||||
id: textEdit
|
||||
padding: 10
|
||||
selectByMouse: true
|
||||
text: $value
|
||||
verticalAlignment: TextEdit.AlignVCenter
|
||||
width: parent.width
|
||||
|
||||
// To handle editingFinished, it's necessary to set
|
||||
// focus on another component.
|
||||
Keys.onReturnPressed: parent.forceActiveFocus()
|
||||
|
||||
onEditingFinished: {
|
||||
if (text.length === 0) {
|
||||
valuesModel.remove(index)
|
||||
} else {
|
||||
// textEdit.text is not the same value than
|
||||
// valuesModel.get(index)
|
||||
valuesModel.set(index, { $value: text })
|
||||
}
|
||||
|
||||
// Hack: The edition is finished but the focus
|
||||
// can be set.
|
||||
focus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
Layout.preferredWidth: ListFormStyle.titleArea.text.width
|
||||
color: ListFormStyle.titleArea.text.color
|
||||
font.pointSize: ListFormStyle.titleArea.text.fontSize
|
||||
}
|
||||
}
|
||||
|
||||
// Values.
|
||||
ListView {
|
||||
id: values
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: count * ListFormStyle.lineHeight
|
||||
interactive: false
|
||||
|
||||
delegate: Item {
|
||||
implicitHeight: textEdit.height
|
||||
width: parent.width
|
||||
|
||||
// Background.
|
||||
Rectangle {
|
||||
color: textEdit.activeFocus
|
||||
? ListFormStyle.value.backgroundColor.focused
|
||||
: ListFormStyle.value.backgroundColor.normal
|
||||
implicitHeight: textEdit.height
|
||||
implicitWidth: textEdit.width
|
||||
}
|
||||
|
||||
// Placeholder.
|
||||
Text {
|
||||
anchors.fill: textEdit
|
||||
color: ListFormStyle.value.placeholder.color
|
||||
font.italic: true
|
||||
font.pointSize: ListFormStyle.value.placeholder.fontSize
|
||||
padding: textEdit.padding
|
||||
text: textEdit.text.length === 0 && !textEdit.activeFocus
|
||||
? qsTr('fillPlaceholder')
|
||||
: ''
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
// Input.
|
||||
TextEdit {
|
||||
id: textEdit
|
||||
|
||||
color: activeFocus
|
||||
? ListFormStyle.value.text.color.focused
|
||||
: ListFormStyle.value.text.color.normal
|
||||
font.bold: !activeFocus
|
||||
height: ListFormStyle.lineHeight
|
||||
padding: ListFormStyle.value.text.padding
|
||||
selectByMouse: true
|
||||
text: $value
|
||||
verticalAlignment: TextEdit.AlignVCenter
|
||||
width: !activeFocus
|
||||
? parent.width
|
||||
: contentWidth + padding * 2
|
||||
|
||||
Keys.onEscapePressed: focus = false
|
||||
Keys.onReturnPressed: focus = false
|
||||
|
||||
onEditingFinished: _handleEditionFinished(index, text)
|
||||
}
|
||||
|
||||
// Handle click outside `TextEdit` instance.
|
||||
InvertedMouseArea {
|
||||
enabled: textEdit.activeFocus
|
||||
height: textEdit.height
|
||||
parent: parent
|
||||
width: textEdit.width
|
||||
|
||||
onPressed: textEdit.focus = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import QtQuick 2.7
|
|||
|
||||
import Linphone 1.0
|
||||
|
||||
import 'qrc:/ui/scripts/utils.js' as Utils
|
||||
|
||||
// ===================================================================
|
||||
// Helper to handle button click outside a component.
|
||||
// ===================================================================
|
||||
|
|
@ -39,9 +41,9 @@ Item {
|
|||
function _isInItem (point) {
|
||||
return (
|
||||
point.x >= item.x &&
|
||||
point.y >= item.y &&
|
||||
point.x <= item.x + item.width &&
|
||||
point.y <= item.y + item.height
|
||||
point.y >= item.y &&
|
||||
point.x <= item.x + item.width &&
|
||||
point.y <= item.y + item.height
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +51,7 @@ Item {
|
|||
// 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 `enabled == true`.
|
||||
// so the mouse area must be created only when `enabled === true`.
|
||||
//
|
||||
// In the first render, `enabled` must be equal to false.
|
||||
Component.onCompleted: enabled && _createMouseArea()
|
||||
|
|
@ -67,6 +69,8 @@ Item {
|
|||
id: builder
|
||||
|
||||
MouseArea {
|
||||
property var _timeout
|
||||
|
||||
anchors.fill: parent
|
||||
propagateComposedEvents: true
|
||||
z: Constants.zMax
|
||||
|
|
@ -75,11 +79,23 @@ Item {
|
|||
// Propagate event.
|
||||
mouse.accepted = false
|
||||
|
||||
// Click is outside or not.
|
||||
if (!_isInItem(
|
||||
mapToItem(item.parent, mouse.x, mouse.y)
|
||||
)) {
|
||||
// Outside!!!
|
||||
item.pressed()
|
||||
if (_timeout != null) {
|
||||
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 mouse event before the `onPressed`
|
||||
// function.
|
||||
//
|
||||
// The timeout is destroyed with the `MouseArea` component.
|
||||
_timeout = Utils.setTimeout.call(this, 0, item.pressed.bind(this))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ ColumnLayout {
|
|||
|
||||
property int entryHeight
|
||||
property int entryWidth
|
||||
property variant entries
|
||||
property var entries
|
||||
|
||||
property int _selectedEntry: 0
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,14 @@ Rectangle {
|
|||
property int entryHeight
|
||||
property int maxMenuHeight
|
||||
|
||||
function show () {
|
||||
visible = true
|
||||
}
|
||||
|
||||
function hide () {
|
||||
visible = false
|
||||
}
|
||||
|
||||
// Ugly. Just ugly.
|
||||
// `model` is a reference on a unknown component!
|
||||
// See usage with SearchBox.
|
||||
|
|
@ -20,14 +28,6 @@ Rectangle {
|
|||
}
|
||||
visible: false
|
||||
|
||||
function show () {
|
||||
visible = true
|
||||
}
|
||||
|
||||
function hide () {
|
||||
visible = false
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: content
|
||||
|
||||
|
|
|
|||
44
tests/ui/modules/Linphone/Styles/Form/ListFormStyle.qml
Normal file
44
tests/ui/modules/Linphone/Styles/Form/ListFormStyle.qml
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
pragma Singleton
|
||||
import QtQuick 2.7
|
||||
|
||||
import Linphone 1.0
|
||||
|
||||
QtObject {
|
||||
property int lineHeight: 30
|
||||
|
||||
property QtObject value: QtObject {
|
||||
property QtObject backgroundColor: QtObject {
|
||||
property color focused: '#E6E6E6'
|
||||
property color normal: 'transparent'
|
||||
}
|
||||
|
||||
property QtObject placeholder: QtObject {
|
||||
property color color: '#5A585B'
|
||||
|
||||
property int fontSize: 10
|
||||
}
|
||||
|
||||
property QtObject text: QtObject {
|
||||
property int padding: 10
|
||||
|
||||
property QtObject color: QtObject {
|
||||
property color focused: '#000000'
|
||||
property color normal: '#5A585B'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property QtObject titleArea: QtObject {
|
||||
property int spacing: 10
|
||||
property int iconSize: 16
|
||||
|
||||
property string icon: 'add_field'
|
||||
|
||||
property QtObject text: QtObject {
|
||||
property color color: '#000000'
|
||||
|
||||
property int fontSize: 10
|
||||
property int width: 130
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ singleton AbstractTextButtonStyle 1.0 Form/AbstractTextButtonStyle.qml
|
|||
singleton ActionBarStyle 1.0 Form/ActionBarStyle.qml
|
||||
singleton CheckBoxTextStyle 1.0 Form/CheckBoxTextStyle.qml
|
||||
singleton ExclusiveButtonsStyle 1.0 Form/ExclusiveButtonsStyle.qml
|
||||
singleton ListFormStyle 1.0 Form/ListFormStyle.qml
|
||||
singleton SmallButtonStyle 1.0 Form/SmallButtonStyle.qml
|
||||
singleton TextButtonAStyle 1.0 Form/TextButtonAStyle.qml
|
||||
singleton TextButtonBStyle 1.0 Form/TextButtonBStyle.qml
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ ContactDescription 1.0 Contact/ContactDescription.qml
|
|||
# Dialog
|
||||
DialogPlus 1.0 Dialog/DialogPlus.qml
|
||||
|
||||
# DropZone
|
||||
DropZone 1.0 DropZone.qml
|
||||
|
||||
# ForceScrollBar
|
||||
ForceScrollBar 1.0 ForceScrollBar.qml
|
||||
|
||||
|
|
@ -32,7 +35,6 @@ ForceScrollBar 1.0 ForceScrollBar.qml
|
|||
ActionBar 1.0 Form/ActionBar.qml
|
||||
ActionButton 1.0 Form/ActionButton.qml
|
||||
CheckBoxText 1.0 Form/CheckBoxText.qml
|
||||
DropZone 1.0 Form/DropZone.qml
|
||||
ExclusiveButtons 1.0 Form/ExclusiveButtons.qml
|
||||
LightButton 1.0 Form/LightButton.qml
|
||||
ListForm 1.0 Form/ListForm.qml
|
||||
|
|
|
|||
|
|
@ -76,3 +76,28 @@ function snakeToCamel (s) {
|
|||
return matches[1].toUpperCase()
|
||||
})
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
function Timer (parent) {
|
||||
return Qt.createQmlObject('import QtQuick 2.7; Timer { }', parent)
|
||||
}
|
||||
|
||||
// A copy of `Window.setTimeout` from js.
|
||||
// Use setTimeout.call(parentContext, delayTime, cb) to use it.
|
||||
//
|
||||
// delay is in milliseconds.
|
||||
function setTimeout (delay, cb) {
|
||||
var timer = new Timer(this)
|
||||
|
||||
timer.interval = delay
|
||||
timer.repeat = false
|
||||
timer.triggered.connect(cb)
|
||||
timer.start()
|
||||
|
||||
return timer
|
||||
}
|
||||
|
||||
function clearTimeout (timer) {
|
||||
timer.destroy() // Not necessary: `timer.stop()`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,18 +72,33 @@ ColumnLayout {
|
|||
|
||||
ListForm {
|
||||
title: qsTr('sipAccounts')
|
||||
model: ListModel {
|
||||
ListElement { $value: 'merinos@sip.linphone.org' }
|
||||
ListElement { $value: 'elisabeth.pro@sip.linphone.org' }
|
||||
}
|
||||
}
|
||||
|
||||
ListForm {
|
||||
title: qsTr('address')
|
||||
model: ListModel {
|
||||
ListElement { $value: '312 East 10th Street - New York, NY 1009' }
|
||||
}
|
||||
}
|
||||
|
||||
ListForm {
|
||||
title: qsTr('emails')
|
||||
model: ListModel {
|
||||
ListElement { $value: 'e.meri@gmail.com' }
|
||||
ListElement { $value: 'toto@truc.machin' }
|
||||
}
|
||||
}
|
||||
|
||||
ListForm {
|
||||
title: qsTr('webSites')
|
||||
model: ListModel {
|
||||
ListElement { $value: 'www.totogro.com' }
|
||||
ListElement { $value: 'www.404.unknown' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue