Skip to content

Commit 331806c

Browse files
committed
Make it possible to do some TextField-related actions
Introduces copy, paste and select all when a text field is selected. Uses the __editMenu property introduced in Qt 5.6. Integrates the text field custom menu, as shown in the demo.
1 parent 42da3ad commit 331806c

File tree

7 files changed

+283
-1
lines changed

7 files changed

+283
-1
lines changed

demo/TextFieldDemo.qml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import QtQuick 2.0
22
import QtQuick.Layouts 1.1
3+
import QtQuick.Controls 1.1 as Controls
34
import Material 0.1
45

56
Item {
@@ -35,6 +36,17 @@ Item {
3536
anchors.horizontalCenter: parent.horizontalCenter
3637
}
3738

39+
TextField {
40+
placeholderText: "Text Field with Menu"
41+
anchors.horizontalCenter: parent.horizontalCenter
42+
menu: Controls.Menu {
43+
Controls.MenuItem {
44+
text: "Print \"awesome\""
45+
onTriggered: console.log("awesome");
46+
}
47+
}
48+
}
49+
3850
TextField {
3951
id: passwordField
4052
placeholderText: "Password"

modules/Material/Button.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ Controls.Button {
6767
The context of the button, which is used to control special styling of
6868
buttons in dialogs or snackbars.
6969
*/
70-
property string context: "default" // or "dialog" or "snackbar"
70+
property string context: "default" // "dialog", "snackbar" or "editmenu"
7171

7272
/*!
7373
Set to \c true if the button is on a dark background

modules/QtQuick/Controls/Styles/Material/ButtonStyle.qml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ ButtonStyle {
9292
implicitWidth: context == "dialog"
9393
? Math.max(Units.dp(64), label.width + Units.dp(16))
9494
: context == "snackbar" ? label.width + Units.dp(16)
95+
: context == "editmenu" ? label.width
9596
: Math.max(Units.dp(88), label.width + Units.dp(32))
9697

9798
Label {
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright (C) 2015 by Aleix Pol Gonzalez <[email protected]>
3+
* Copyright (C) 2015 by Marco Martin <[email protected]>
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU Library General Public License as
7+
* published by the Free Software Foundation; either version 2, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU Library General Public License for more details
14+
*
15+
* You should have received a copy of the GNU Library General Public
16+
* License along with this program; if not, write to the
17+
* Free Software Foundation, Inc.,
18+
* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
19+
*/
20+
21+
import QtQuick 2.1
22+
import QtQuick.Controls 1.1
23+
import QtQuick.Controls.Styles 1.1
24+
import QtQuick.Layouts 1.0
25+
import Material 0.1
26+
27+
Item {
28+
id: root
29+
anchors.fill: parent
30+
31+
property bool editing: true
32+
onEditingChanged: {
33+
updateCursorOpacity()
34+
}
35+
function updateCursorOpacity() {
36+
var opacity = root.editing ? 0 : 1;
37+
cursorHandle.opacity = opacity;
38+
selectionHandle.opacity = opacity;
39+
}
40+
Component.onCompleted: updateCursorOpacity()
41+
42+
// https://www.google.com/design/spec/patterns/selection.html#selection-text-selection
43+
Component {
44+
id: editControls
45+
Item {
46+
id: popup
47+
visible: input.activeFocus && !root.editing
48+
z: 9999
49+
50+
Behavior on x { NumberAnimation { duration: 500; easing.type: Easing.InOutQuad } }
51+
52+
Component.onCompleted: {
53+
var par = control
54+
//heuristic: if a flickable is found in the parents,
55+
//reparent to it, so it scrolls together
56+
while (par.parent && par.parent.contentY === undefined) {
57+
par = par.parent
58+
}
59+
60+
popup.parent = par
61+
}
62+
63+
function popup(startRect) {
64+
// var selectedTextTopPadding = Units.dp(8);
65+
var mapped = parent.mapFromItem(input, startRect.x, startRect.y);
66+
var mapWidget = parent.mapFromItem(input.parent, input.x, input.y, input.width, input.height);
67+
68+
popup.x = Math.min(Math.max(mapWidget.x, mapped.x), mapWidget.x+mapWidget.width-bg.width);
69+
popup.y = Math.max(0, mapped.y - bg.height);
70+
}
71+
function dismiss() {
72+
popup.visible = false;
73+
}
74+
75+
View {
76+
id: bg
77+
elevation: 1
78+
anchors {
79+
fill: buttons
80+
topMargin: -Units.dp(12)
81+
bottomMargin: -Units.dp(14)
82+
leftMargin: -Units.dp(24)
83+
rightMargin: -Units.dp(16)
84+
}
85+
}
86+
87+
RowLayout {
88+
id: buttons
89+
spacing: Units.dp(32)
90+
Button {
91+
text: qsTr("Cut")
92+
visible: input.selectedText != ""
93+
context: "editmenu"
94+
onClicked: {
95+
control.cut();
96+
select(input.cursorPosition, input.cursorPosition);
97+
}
98+
}
99+
Button {
100+
text: qsTr("Copy")
101+
visible: input.selectedText != ""
102+
context: "editmenu"
103+
onClicked: {
104+
control.copy();
105+
select(input.cursorPosition, input.cursorPosition);
106+
}
107+
}
108+
Button {
109+
text: qsTr("Paste")
110+
visible: input.canPaste
111+
context: "editmenu"
112+
onClicked: {
113+
control.paste();
114+
}
115+
}
116+
Button {
117+
text: qsTr("Select All")
118+
visible: input.text != ""
119+
context: "editmenu"
120+
onClicked: {
121+
control.selectAll();
122+
}
123+
}
124+
125+
IconButton {
126+
iconName: "navigation/more_vert"
127+
visible: control.menu !== null
128+
onClicked: {
129+
getMenuInstance().popup()
130+
}
131+
}
132+
}
133+
}
134+
}
135+
136+
Connections {
137+
target: mouseArea
138+
139+
onClicked: {
140+
var pos = input.positionAt(mouse.x, mouse.y)
141+
input.moveHandles(pos, pos)
142+
input.activate()
143+
}
144+
onPressAndHold: {
145+
root.editing = false;
146+
var pos = input.positionAt(mouse.x, mouse.y)
147+
input.moveHandles(pos, control.selectByMouse ? -1 : pos)
148+
input.activate()
149+
}
150+
}
151+
152+
Connections {
153+
target: input
154+
onSelectionStartChanged: popupTimer.restart()
155+
onSelectionEndChanged: popupTimer.restart()
156+
onActiveFocusChanged: {
157+
popupTimer.restart()
158+
root.editing = true;
159+
}
160+
onTextChanged: root.editing = true;
161+
}
162+
163+
Connections {
164+
target: flickable
165+
onMovingChanged: popupTimer.restart()
166+
}
167+
168+
property Item editControlsInstance: null
169+
function getEditControlsInstance() {
170+
// Lazy load the view when first requested
171+
if (!editControlsInstance) {
172+
editControlsInstance = editControls.createObject(control);
173+
}
174+
return editControlsInstance;
175+
}
176+
177+
Timer {
178+
id: popupTimer
179+
interval: 200
180+
onTriggered: {
181+
if (input.canPaste || selectionStart !== selectionEnd) {
182+
var startRect = input.positionToRectangle(input.selectionStart);
183+
184+
getEditControlsInstance().popup(startRect);
185+
}
186+
}
187+
}
188+
}

modules/QtQuick/Controls/Styles/Material/TextFieldStyle.qml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,22 @@ TextFieldStyle {
4242
selectionColor: control.hasOwnProperty("color") ? control.color : Theme.accentColor
4343
textColor: Theme.light.textColor
4444

45+
//make sure to QT_QUICK_CONTROLS_MOBILE=ON to properly test this
46+
property Component __editMenu: MaterialEditMenu {
47+
id: menu
48+
}
49+
50+
property Component __cursorHandle: TextHandle {
51+
side: control.selectionEnd - control.selectionStart
52+
color: Palette.colors["blue"]["400"]
53+
}
54+
55+
property Component __selectionHandle: TextHandle {
56+
side: control.selectionStart - control.selectionEnd
57+
color: Palette.colors["blue"]["400"]
58+
}
59+
60+
4561
background : Item {
4662
id: background
4763

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Copyright (C) 2015 by Aleix Pol Gonzalez <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Library General Public License as
6+
* published by the Free Software Foundation; either version 2, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Library General Public License for more details
13+
*
14+
* You should have received a copy of the GNU Library General Public
15+
* License along with this program; if not, write to the
16+
* Free Software Foundation, Inc.,
17+
* 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA.
18+
*/
19+
20+
import QtQuick 2.1
21+
import Material 0.1
22+
23+
Rectangle {
24+
id: root
25+
property int side: 0 //-1 left, 0 center, 1 right
26+
27+
width: Units.dp(22)
28+
height: Units.dp(22)
29+
30+
radius: width
31+
y: styleData.lineHeight
32+
33+
Rectangle {
34+
id: rect
35+
width: parent.width/2
36+
height: parent.height/2
37+
color: parent.color
38+
}
39+
40+
states: [
41+
State {
42+
when: side<0
43+
name: "right"
44+
PropertyChanges { target: root; x: -width}
45+
AnchorChanges { target: rect; anchors.right: parent.right }
46+
},
47+
State {
48+
when: side>0
49+
name: "left"
50+
AnchorChanges { target: rect; anchors.left: parent.left }
51+
},
52+
State {
53+
when: side==0
54+
name: "center"
55+
PropertyChanges { target: rect; rotation: 45 }
56+
PropertyChanges { target: rect; width: root.width/Math.SQRT2 }
57+
PropertyChanges { target: rect; height: rect.width }
58+
PropertyChanges { target: rect; x: (root.width-rect.width)/2 }
59+
60+
PropertyChanges { target: root; y: styleData.lineHeight/*+root.height/2*/ }
61+
PropertyChanges { target: root; x: -root.width/2 }
62+
}
63+
]
64+
}

modules/QtQuick/Controls/Styles/Material/qmldir

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ ToolButtonStyle.qml 0.1 ToolButtonStyle.qml
99
RadioButtonStyle 0.1 RadioButtonStyle.qml
1010
SliderStyle 0.1 SliderStyle.qml
1111
TextFieldStyle 0.1 TextFieldStyle.qml
12+
TextHandle 0.1 TextHandle.qml

0 commit comments

Comments
 (0)