Merge lp:~zsombi/ubuntu-ui-toolkit/textinput-carets into lp:ubuntu-ui-toolkit/staging

Proposed by Zsombor Egri
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1036
Merged at revision: 1037
Proposed branch: lp:~zsombi/ubuntu-ui-toolkit/textinput-carets
Merge into: lp:ubuntu-ui-toolkit/staging
Prerequisite: lp:~zsombi/ubuntu-ui-toolkit/textinputs-rightclick
Diff against target: 1322 lines (+808/-173)
16 files modified
components.api (+1/-0)
modules/Ubuntu/Components/InputHandler.qml (+107/-5)
modules/Ubuntu/Components/TextArea.qml (+10/-72)
modules/Ubuntu/Components/TextCursor.qml (+235/-26)
modules/Ubuntu/Components/TextField.qml (+11/-21)
modules/Ubuntu/Components/Themes/Ambiance/TextAreaStyle.qml (+16/-1)
modules/Ubuntu/Components/Themes/Ambiance/TextCursorStyle.qml (+58/-40)
modules/Ubuntu/Components/Themes/Ambiance/TextFieldStyle.qml (+1/-0)
modules/Ubuntu/Components/Themes/Ambiance/TextSelectionEndCursorStyle.qml (+66/-0)
modules/Ubuntu/Components/Themes/Ambiance/TextSelectionStartCursorStyle.qml (+66/-0)
modules/Ubuntu/Components/Themes/Ambiance/qmldir (+3/-0)
modules/Ubuntu/Test/UbuntuTestCase.qml (+25/-2)
tests/resources/inputs/TextInputs.qml (+4/-0)
tests/unit_x11/tst_components/tst_textarea.qml (+6/-5)
tests/unit_x11/tst_components/tst_textfield.qml (+1/-1)
tests/unit_x11/tst_components/tst_textinput_common.qml (+198/-0)
To merge this branch: bzr merge lp:~zsombi/ubuntu-ui-toolkit/textinput-carets
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Cris Dywan Approve
Review via email: mp+216665@code.launchpad.net

Commit message

Text input caret handler visuals and functionality.

To post a comment you must log in.
Revision history for this message
Cris Dywan (kalikiana) wrote :

The carrots actually do a nice job on the desktop enabling me to extend selections with just a mouse - ordinarily it would require ⇧Arrow.

A single carrot is visible when there's no selection but can't be dragged.

If the selection is at the very start of the text field the first carrot is clipped.

505 - Ubuntu.Mouse.forwardTo: [inputHandler]
506 +// Ubuntu.Mouse.forwardTo: [inputHandler]

Accident?

526 +// FIXME: stabilize API

What does this mean? Could you make the comment more verbose or mention a bug?

Revision history for this message
Zsombor Egri (zsombi) wrote :

> The carrots actually do a nice job on the desktop enabling me to extend
> selections with just a mouse - ordinarily it would require ⇧Arrow.
>
> A single carrot is visible when there's no selection but can't be dragged.

The single caret is just to grab the cursor for easy positioning of it. It's not a selection caret. The selection cares get visible when there is selected text.
>
> If the selection is at the very start of the text field the first carrot is
> clipped.

The carets are clipped in the input area atm, so the selection beginning will be clipped yet. I'll try to get a similar image above the actual one, but unfortunately positioning the overlay caret is not that stable... And may require changes in the logic...

>
> 505 - Ubuntu.Mouse.forwardTo: [inputHandler]
> 506 +// Ubuntu.Mouse.forwardTo: [inputHandler]
>
> Accident?

Yes, good catch!

>
> 526 +// FIXME: stabilize API
>
> What does this mean? Could you make the comment more verbose or mention a bug?

Means that the API will be moved in Ubuntu.Components.Styles. Once I get everything done, and in a separate MR perhaps.

Revision history for this message
Cris Dywan (kalikiana) wrote :

> > The carrots actually do a nice job on the desktop enabling me to extend
> > selections with just a mouse - ordinarily it would require ⇧Arrow.
> >
> > A single carrot is visible when there's no selection but can't be dragged.
>
> The single caret is just to grab the cursor for easy positioning of it. It's
> not a selection caret. The selection cares get visible when there is selected
> text.

The problem with that is to start a selection you still have to aim freely, so there's no benefit in precisely moving the caret right now - unless there is going to be a way to long press/ right-click the carrot itself to start a selection or invoke the context menu.

> > If the selection is at the very start of the text field the first carrot is
> > clipped.
>
> The carets are clipped in the input area atm, so the selection beginning will
> be clipped yet. I'll try to get a similar image above the actual one, but
> unfortunately positioning the overlay caret is not that stable... And may
> require changes in the logic...

I could agree to filing a bug for it and leaving it as-is for now, it's not a deal breaker for typical use.

> >
> > 526 +// FIXME: stabilize API
> >
> > What does this mean? Could you make the comment more verbose or mention a
> bug?
>
> Means that the API will be moved in Ubuntu.Components.Styles. Once I get
> everything done, and in a separate MR perhaps.

Maybe just leave that out of this branch then? Since it's not actually a bug or anything, more like something that belongs in a bug or blueprint.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:1032
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/146/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-trusty-touch/540
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/5168
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-amd64-ci/146
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-armhf-ci/146
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-armhf-ci/146/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-i386-ci/146
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/475
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/4815
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/4815/artifact/work/output/*zip*/output.zip
    FAILURE: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/6589/console
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/4441
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/5373
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/5373/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/146/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:1034
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/156/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-trusty-touch/568
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-trusty/5194
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-amd64-ci/156
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-armhf-ci/156
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-armhf-ci/156/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-trusty-i386-ci/156
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/496
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/4862
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-armhf/4862/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/6697
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-trusty/4462
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/5417
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-trusty-amd64/5417/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/156/rebuild

review: Approve (continuous-integration)
Revision history for this message
Cris Dywan (kalikiana) wrote :

> > > A single carrot is visible when there's no selection but can't be dragged.
> > The single caret is just to grab the cursor for easy positioning of it. It's
> > not a selection caret.
> The problem with that is to start a selection you still have to aim freely, so
> there's no benefit in precisely moving the caret right now - unless there is
> going to be a way to long press/ right-click the carrot itself to start a
> selection or invoke the context menu.

?

> > > at the very start of the text field the first carrot is clipped.
> > The carets are clipped in the input area atm

It would seem to be fixed now. Nice.

> > > 526 +// FIXME: stabilize API
> > > What does this mean? Could you make the comment more verbose
> > Means that the API will be moved in Ubuntu.Components.Styles. Once I get
> > everything done, and in a separate MR perhaps.
> Maybe just leave that out of this branch then? Since it's not actually a bug
> or anything, more like something that belongs in a bug or blueprint.

?

From more testing I noticed, sometimes selecting text with the mouse gets ignored, even if you try a few times, and then it works again. Not sure what exactly causes it, it's hard to say if it's stuck or a timeout is catching it. I almost thought the last changes broke normal mouse selection :-(

review: Needs Information
Revision history for this message
Zsombor Egri (zsombi) wrote :

> > > > A single carrot is visible when there's no selection but can't be
> dragged.
> > > The single caret is just to grab the cursor for easy positioning of it.
> It's
> > > not a selection caret.
> > The problem with that is to start a selection you still have to aim freely,
> so
> > there's no benefit in precisely moving the caret right now - unless there is
> > going to be a way to long press/ right-click the carrot itself to start a
> > selection or invoke the context menu.
>
> ?

So, first of all, the caret is a handler which is used to grab the cursor (both in edit and select modes). We need them in all the modes, not only in selection mode.

You need to be able to position the cursor pretty precisely if you want to insert some text at a given position. When you have a single caret, you only have the cursor, you are not in the selection mode yet. That caret moves the cursor in a way so you can see where it actually gets positioned.

>
> > > > at the very start of the text field the first carrot is clipped.
> > > The carets are clipped in the input area atm
>
> It would seem to be fixed now. Nice.
>
> > > > 526 +// FIXME: stabilize API
> > > > What does this mean? Could you make the comment more verbose
> > > Means that the API will be moved in Ubuntu.Components.Styles. Once I get
> > > everything done, and in a separate MR perhaps.
> > Maybe just leave that out of this branch then? Since it's not actually a bug
> > or anything, more like something that belongs in a bug or blueprint.
>
> ?

FIXME comments we use not only to fix something, but to remember that there's more work to be done there. I can remove that of course, and I won't have the API stabilized in this MR for sure, but it is good to have extra reminders that these kind of tasks should also be done.

>
> From more testing I noticed, sometimes selecting text with the mouse gets
> ignored, even if you try a few times, and then it works again. Not sure what
> exactly causes it, it's hard to say if it's stuck or a timeout is catching it.
> I almost thought the last changes broke normal mouse selection :-(

Double tap? I noticed that because of the caret positioning, if you tap too close to the caret, the double tap will get stolen by the caret dragger... Perhaps I'd need to position the caret a bit closer to the bottom of the cursor so it doesn't interfere with the clicks...

Revision history for this message
Cris Dywan (kalikiana) wrote :

Very nice to have the cursor take events now. And I can actually open the menu more precisely through the carrot in tricky cases with small letters.

As I double-checked, the ignored selections are not new in this branch, just depend a lot on the exact mouse movement, so let's not worry about it here.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:1035
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/169/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/13
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/7/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-ci/1
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/1
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/1/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-ci/1
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/528
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/88
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/88/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/6810
    FAILURE: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/10/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/23
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/23/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/169/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Autolanding.
More details in the following jenkins job:
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-autolanding/57/
Executed test runs:
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/14
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/9
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-autolanding/1
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-autolanding/1
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-autolanding/1/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-autolanding/1
    UNSTABLE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/529
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/90
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/90/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/6812
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/12
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/25
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/25/artifact/work/output/*zip*/output.zip

review: Needs Fixing (continuous-integration)
1036. By Zsombor Egri

staging merge

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:1036
http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/170/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/19
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/13
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-amd64-ci/2
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/2
        deb: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-armhf-ci/2/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-utopic-i386-ci/2
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/530
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/97
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/97/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/6815
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/14
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/29
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/29/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-sdk-team-ubuntu-ui-toolkit-staging-ci/170/rebuild

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'components.api'
--- components.api 2014-05-02 11:09:58 +0000
+++ components.api 2014-05-06 12:22:48 +0000
@@ -605,6 +605,7 @@
605TestCase605TestCase
606 function findChild(obj,objectName)606 function findChild(obj,objectName)
607 function findInvisibleChild(obj,objectName)607 function findInvisibleChild(obj,objectName)
608 function findChildWithProperty(item, property, value)
608 function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay)609 function mouseMoveSlowly(item,x,y,dx,dy,steps,stepdelay)
609 function flick(item, x, y, dx, dy, pressTimeout, steps, button, modifiers, delay)610 function flick(item, x, y, dx, dy, pressTimeout, steps, button, modifiers, delay)
610 function mouseLongPress(item, x, y, button, modifiers, delay)611 function mouseLongPress(item, x, y, button, modifiers, delay)
611612
=== modified file 'modules/Ubuntu/Components/InputHandler.qml'
--- modules/Ubuntu/Components/InputHandler.qml 2014-05-01 12:15:29 +0000
+++ modules/Ubuntu/Components/InputHandler.qml 2014-05-06 12:22:48 +0000
@@ -29,7 +29,7 @@
29 property Item main29 property Item main
30 // the input instance30 // the input instance
31 property Item input31 property Item input
32 // the Flickable holdiong the input instance32 // the Flickable holding the input instance
33 property Flickable flickable33 property Flickable flickable
34 // selection cursor mode34 // selection cursor mode
35 property bool selectionCursor: input && input.selectedText !== ""35 property bool selectionCursor: input && input.selectedText !== ""
@@ -38,7 +38,20 @@
38 // property holding the selection mode timeout38 // property holding the selection mode timeout
39 property int selectionModeTimeout: 20039 property int selectionModeTimeout: 200
4040
41 // signal triggered when popup shoudl be opened41 // item filling the text input visible area, used to check teh caret handler
42 // visibility
43 property Item visibleArea: Item {
44 parent: flickable
45 anchors.fill: parent
46 }
47
48 // line size and spacing
49 property real lineSpacing: units.dp(3)
50 property real lineSize: input.font.pixelSize + lineSpacing
51 // input x/y distance from the frame
52 property point frameDistance: Qt.point(0,0)
53
54 // signal triggered when popup should be opened
42 signal pressAndHold(int pos)55 signal pressAndHold(int pos)
4356
44 function activateInput() {57 function activateInput() {
@@ -80,9 +93,11 @@
80 readonly property Flickable scroller: (scrollingDisabled && grandScroller) ? grandScroller : flickable93 readonly property Flickable scroller: (scrollingDisabled && grandScroller) ? grandScroller : flickable
8194
82 // ensures the text cusrorRectangle is always in the internal Flickable's visible area95 // ensures the text cusrorRectangle is always in the internal Flickable's visible area
83 function ensureVisible()96 function ensureVisible(rect)
84 {97 {
85 var rect = input.cursorRectangle;98 if (rect === undefined) {
99 rect = input.cursorRectangle;
100 }
86 if (flickable.moving || flickable.flicking)101 if (flickable.moving || flickable.flicking)
87 return;102 return;
88 if (flickable.contentX >= rect.x)103 if (flickable.contentX >= rect.x)
@@ -94,9 +109,14 @@
94 else if (flickable.contentY + flickable.height <= rect.y + rect.height)109 else if (flickable.contentY + flickable.height <= rect.y + rect.height)
95 flickable.contentY = rect.y + rect.height - flickable.height;110 flickable.contentY = rect.y + rect.height - flickable.height;
96 }111 }
112 // returns the cursor position from x,y pair
113 function cursorPosition(x, y) {
114 return singleLine ? input.positionAt(x, TextInput.CursorOnCharacter) : input.positionAt(x, y, TextInput.CursorOnCharacter);
115 }
116
97 // returns the mouse position117 // returns the mouse position
98 function mousePosition(mouse) {118 function mousePosition(mouse) {
99 return singleLine ? input.positionAt(mouse.x) : input.positionAt(mouse.x, mouse.y);119 return cursorPosition(mouse.x, mouse.y);
100 }120 }
101 // checks whether the position is in the selected text121 // checks whether the position is in the selected text
102 function positionInSelection(pos) {122 function positionInSelection(pos) {
@@ -165,6 +185,30 @@
165 }185 }
166 }186 }
167187
188 // moves the specified position, called by the cursor handler
189 // positioner = "currentPosition/selectionStart/selectionEnd"
190 function positionCaret(positioner, x, y) {
191 if (positioner === "cursorPosition") {
192 input[positioner] = cursorPosition(x, y);
193 } else {
194 var pos = cursorPosition(x, y);
195 if (positioner === "selectionStart" && (pos < input.selectionEnd)) {
196 input.select(pos, input.selectionEnd);
197 } else if (positioner === "selectionEnd" && (pos > input.selectionStart)) {
198 input.select(input.selectionStart, pos);
199 }
200 }
201 }
202
203 // returns the styles for the cursors depending on the position property given
204 function textCursorStyle(positionProperty) {
205 switch (positionProperty) {
206 case "cursorPosition": return main.__styleInstance.mainCursorStyle;
207 case "selectionStart": return main.__styleInstance.selectionStartCursorStyle;
208 case "selectionEnd": return main.__styleInstance.selectionEndCursorStyle;
209 }
210 }
211
168 Component.onCompleted: {212 Component.onCompleted: {
169 state = (main.focus) ? "" : "inactive";213 state = (main.focus) ? "" : "inactive";
170 }214 }
@@ -313,4 +357,62 @@
313 // trigger pressAndHold357 // trigger pressAndHold
314 onReleased: openContextMenu(mouse)358 onReleased: openContextMenu(mouse)
315 }359 }
360
361 // cursors to use when text is selected
362 Connections {
363 property Item selectionStartCursor: null
364 property Item selectionEndCursor: null
365 target: input
366 onSelectedTextChanged: {
367 if (selectedText !== "" && input.cursorDelegate) {
368 if (!selectionStartCursor) {
369 selectionStartCursor = input.cursorDelegate.createObject(
370 input, {
371 "positionProperty": "selectionStart",
372 "height": lineSize,
373 "handler": inputHandler,
374 }
375 );
376 moveSelectionCursor(selectionStartCursor);
377 }
378 if (!selectionEndCursor) {
379 selectionEndCursor = input.cursorDelegate.createObject(
380 input, {
381 "positionProperty": "selectionEnd",
382 "height": lineSize,
383 "handler": inputHandler,
384 }
385 );
386 moveSelectionCursor(selectionEndCursor);
387 }
388 } else {
389 if (selectionStartCursor) {
390 selectionStartCursor.destroy();
391 selectionStartCursor = null;
392 }
393 if (selectionEndCursor) {
394 selectionEndCursor.destroy();
395 selectionEndCursor = null;
396 }
397 }
398 }
399 onSelectionStartChanged: moveSelectionCursor(selectionStartCursor, true);
400 onSelectionEndChanged: moveSelectionCursor(selectionEndCursor, true);
401
402 function moveSelectionCursor(cursor, updateProperty) {
403 if (!cursor) {
404 return;
405 }
406 // workaround for https://bugreports.qt-project.org/browse/QTBUG-38704
407 // selectedTextChanged signal is not emitted for TextEdit when selectByMouse is false
408 if (updateProperty && QuickUtils.className(input) === "QQuickTextEdit") {
409 input.selectedTextChanged();
410 }
411
412 var pos = input.positionToRectangle(input[cursor.positionProperty]);
413 cursor.x = pos.x;
414 cursor.y = pos.y;
415 ensureVisible(pos);
416 }
417 }
316}418}
317419
=== modified file 'modules/Ubuntu/Components/TextArea.qml'
--- modules/Ubuntu/Components/TextArea.qml 2014-04-28 06:48:28 +0000
+++ modules/Ubuntu/Components/TextArea.qml 2014-05-06 12:22:48 +0000
@@ -158,7 +158,7 @@
158 area defined in the current theme. The default value is the same as the visible158 area defined in the current theme. The default value is the same as the visible
159 input area's width.159 input area's width.
160 */160 */
161 property real contentWidth: internal.inputAreaWidth161 property real contentWidth: control.width - 2 * internal.frameSpacing
162162
163 /*!163 /*!
164 The property folds the height of the text editing content. This can be equal or164 The property folds the height of the text editing content. This can be equal or
@@ -166,7 +166,7 @@
166 area defined in the current theme. The default value is the same as the visible166 area defined in the current theme. The default value is the same as the visible
167 input area's height.167 input area's height.
168 */168 */
169 property real contentHeight: internal.inputAreaHeight169 property real contentHeight: control.height - 2 * internal.frameSpacing
170170
171 /*!171 /*!
172 The property overrides the default popover of the TextArea. When set, the172 The property overrides the default popover of the TextArea. When set, the
@@ -233,10 +233,8 @@
233233
234 Note that the root item of the delegate component must be a QQuickItem or234 Note that the root item of the delegate component must be a QQuickItem or
235 QQuickItem derived item.235 QQuickItem derived item.
236
237 \qmlproperty Component cursorDelegate
238 */236 */
239 property alias cursorDelegate: editor.cursorDelegate237 property Component cursorDelegate: null
240238
241 /*!239 /*!
242 The position of the cursor in the TextArea.240 The position of the cursor in the TextArea.
@@ -731,7 +729,6 @@
731 /*!\internal - to remove warnings */729 /*!\internal - to remove warnings */
732 Component.onCompleted: {730 Component.onCompleted: {
733 editor.linkActivated.connect(control.linkActivated);731 editor.linkActivated.connect(control.linkActivated);
734 internal.prevShowCursor = control.cursorVisible;
735 }732 }
736733
737 // activation area on mouse click734 // activation area on mouse click
@@ -756,15 +753,6 @@
756 control.focus = false;753 control.focus = false;
757 }754 }
758755
759 /*!\internal */
760 onContentWidthChanged: internal.inputAreaWidth = control.contentWidth
761 /*!\internal */
762 onContentHeightChanged: internal.inputAreaHeight = control.contentHeight
763 /*!\internal */
764 onWidthChanged: internal.inputAreaWidth = control.width - 2 * internal.frameSpacing
765 /*!\internal */
766 onHeightChanged: internal.inputAreaHeight = control.height - 2 * internal.frameSpacing
767
768 LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft756 LayoutMirroring.enabled: Qt.application.layoutDirection == Qt.RightToLeft
769 LayoutMirroring.childrenInherit: true757 LayoutMirroring.childrenInherit: true
770758
@@ -772,32 +760,12 @@
772 id: internal760 id: internal
773 // public property locals enabling aliasing761 // public property locals enabling aliasing
774 property string displayText: editor.getText(0, editor.length)762 property string displayText: editor.getText(0, editor.length)
775 property real lineSpacing: units.dp(3)
776 property real frameSpacing: control.__styleInstance.frameSpacing763 property real frameSpacing: control.__styleInstance.frameSpacing
777 property real lineSize: editor.font.pixelSize + lineSpacing
778 property real minimumSize: units.gu(4)764 property real minimumSize: units.gu(4)
779 property real inputAreaWidth: control.width - 2 * frameSpacing
780 property real inputAreaHeight: control.height - 2 * frameSpacing
781 //selection properties
782 property bool prevShowCursor
783
784 function toggleSelectionCursors(show)
785 {
786 if (!show) {
787 leftCursorLoader.sourceComponent = undefined;
788 rightCursorLoader.sourceComponent = undefined;
789 editor.cursorVisible = prevShowCursor;
790 } else {
791 prevShowCursor = editor.cursorVisible;
792 editor.cursorVisible = false;
793 leftCursorLoader.sourceComponent = cursor;
794 rightCursorLoader.sourceComponent = cursor;
795 }
796 }
797765
798 function linesHeight(lines)766 function linesHeight(lines)
799 {767 {
800 var lineHeight = editor.font.pixelSize * lines + lineSpacing * lines768 var lineHeight = editor.font.pixelSize * lines + inputHandler.lineSpacing * lines
801 return lineHeight + 2 * frameSpacing;769 return lineHeight + 2 * frameSpacing;
802 }770 }
803771
@@ -829,39 +797,6 @@
829 }797 }
830 Keys.onReleased: event.accepted = (event.key === Qt.Key_Enter) || (event.key === Qt.Key_Return)798 Keys.onReleased: event.accepted = (event.key === Qt.Key_Enter) || (event.key === Qt.Key_Return)
831799
832 // cursor is FIXME: move in a separate element and align with TextField
833 Component {
834 id: cursor
835 TextCursor {
836 id: cursorItem
837 editorItem: control
838 height: internal.lineSize
839 popover: control.popover
840 visible: editor.cursorVisible
841
842 Component.onCompleted: inputHandler.pressAndHold.connect(cursorItem.openPopover)
843 }
844 }
845 // selection cursor loader
846 Loader {
847 id: leftCursorLoader
848 onStatusChanged: {
849 if (status == Loader.Ready && item) {
850 item.positionProperty = "selectionStart";
851 item.parent = editor;
852 }
853 }
854 }
855 Loader {
856 id: rightCursorLoader
857 onStatusChanged: {
858 if (status == Loader.Ready && item) {
859 item.positionProperty = "selectionEnd";
860 item.parent = editor;
861 }
862 }
863 }
864
865 // holding default values800 // holding default values
866 Label { id: fontHolder }801 Label { id: fontHolder }
867802
@@ -911,13 +846,15 @@
911 readOnly: false846 readOnly: false
912 id: editor847 id: editor
913 focus: true848 focus: true
914 width: internal.inputAreaWidth849 width: control.contentWidth
915 height: Math.max(internal.inputAreaHeight, editor.contentHeight)850 height: Math.max(control.contentHeight, editor.contentHeight)
916 wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere851 wrapMode: TextEdit.WrapAtWordBoundaryOrAnywhere
917 mouseSelectionMode: TextEdit.SelectWords852 mouseSelectionMode: TextEdit.SelectWords
918 selectByMouse: false853 selectByMouse: false
919 activeFocusOnPress: false854 activeFocusOnPress: false
920 cursorDelegate: cursor855 cursorDelegate: TextCursor {
856 handler: inputHandler
857 }
921 color: control.__styleInstance.color858 color: control.__styleInstance.color
922 selectedTextColor: Theme.palette.selected.foregroundText859 selectedTextColor: Theme.palette.selected.foregroundText
923 selectionColor: Theme.palette.selected.foreground860 selectionColor: Theme.palette.selected.foreground
@@ -937,6 +874,7 @@
937 input: editor874 input: editor
938 flickable: flicker875 flickable: flicker
939 selectionModeTimeout: control.__styleInstance.selectionModeTimeout876 selectionModeTimeout: control.__styleInstance.selectionModeTimeout
877 frameDistance: Qt.point(internal.frameSpacing, internal.frameSpacing)
940 }878 }
941 }879 }
942 }880 }
943881
=== modified file 'modules/Ubuntu/Components/TextCursor.qml'
--- modules/Ubuntu/Components/TextCursor.qml 2014-04-28 06:48:28 +0000
+++ modules/Ubuntu/Components/TextCursor.qml 2014-05-06 12:22:48 +0000
@@ -15,48 +15,257 @@
15 */15 */
1616
17import QtQuick 2.017import QtQuick 2.0
18import Ubuntu.Components 1.1 as Ubuntu
18import Ubuntu.Components.Popups 1.019import Ubuntu.Components.Popups 1.0
1920
20StyledItem {21Ubuntu.StyledItem {
21 id: cursorItem22 id: cursorItem
2223
23 width: units.dp(1)24 width: units.dp(1)
2425
25 /*26 /*
26 Property holding the text input item instance.
27 */
28 property var editorItem
29
30 /*
31 Property holding the text input's custor position property. Can be one of27 Property holding the text input's custor position property. Can be one of
32 the following ones: cursorPosition, selectionStart and selectionEnd.28 the following ones: cursorPosition, selectionStart and selectionEnd.
33 */29 */
34 property string positionProperty: "cursorPosition"30 property string positionProperty: "cursorPosition"
3531
36 /*32 /*
37 The property contains the custom popover to be shown.33 Input handler instance
38 */34 */
39 property var popover35 property InputHandler handler
4036
37 /*
38 Cursor delegate used. This is the visual component from the main
39 */
40 readonly property Component cursorDelegate: handler.main.cursorDelegate ?
41 handler.main.cursorDelegate :
42 __styleInstance.cursorDelegate
43
44 // depending on the positionProperty, we chose different styles
45 style: Theme.createStyleComponent(handler.textCursorStyle(positionProperty), cursorItem);
46
47 //Caret instance from the style.
48 property Item caret: __styleInstance.caret
49 property real caretX: caret ? caret.x : 0
50 property real caretY: caret ? caret.y : 0
51
52 // returns the mapped cursor position to a position relative to the main component
53 function mappedCursorPosition(pos) {
54 return cursorItem[pos] + handler.frameDistance[pos] - handler.flickable["content"+pos.toUpperCase()];
55 }
41 /*56 /*
42 The function opens the text input popover setting the text cursor as caller.57 The function opens the text input popover setting the text cursor as caller.
43 */58 */
59 Connections {
60 target: inputHandler
61 onPressAndHold: openPopover()
62 }
63
44 function openPopover() {64 function openPopover() {
45 if (!visible)65 if (!visible || opacity === 0.0 || dragger.drag.active) {
46 return;66 return;
47 if (popover === undefined) {67 }
48 // open the default one68 // open context menu only for cursorPosition or selectionEnd
49 PopupUtils.open(Qt.resolvedUrl("TextInputPopover.qml"), cursorItem,69 if (positionProperty !== "selectionStart") {
50 {70 if (handler.main.popover === undefined) {
51 "target": editorItem71 // open the default one
52 })72 PopupUtils.open(Qt.resolvedUrl("TextInputPopover.qml"), cursorItem,
53 } else {73 {
54 PopupUtils.open(popover, cursorItem,74 "target": handler.main
55 {75 })
56 "target": editorItem76 } else {
57 })77 PopupUtils.open(handler.main.popover, cursorItem,
58 }78 {
59 }79 "target": handler.main
6080 })
61 style: Theme.createStyleComponent("TextCursorStyle.qml", cursorItem)81 }
82 }
83 }
84
85 visible: handler.main.cursorVisible
86 // change opacity to 0 if text is selected and the positionProperty is cursorPosition
87 // note: we should not touch visibility as cursorVisible alters that!
88 opacity: (positionProperty === "cursorPosition") && (handler.main.selectedText !== "") ? 0.0 : 1.0
89
90 // cursor visual loader
91 Loader {
92 id: cursorLoader
93 sourceComponent: cursorDelegate
94 height: parent.height
95 onItemChanged: {
96 if (item) {
97 cursorItem.width = item.width;
98 }
99 }
100 // bind the cursor height as it may change depending on the text size
101 Binding {
102 target: cursorLoader.item
103 property: "height"
104 value: cursorLoader.height
105 when: cursorLoader.item
106 }
107 }
108
109 /*
110 * Handle pressAndHold as well as right clicks when pressed around the
111 */
112 MouseArea {
113 anchors {
114 fill: parent
115 margins: -units.dp(4)
116 }
117 acceptedButtons: Qt.LeftButon | Qt.RightButton
118 preventStealing: false
119 onPressAndHold: openPopover()
120 onClicked: if (mouse.button === Qt.RightButton) openPopover()
121 }
122
123 /*
124 * Caret dragging handling. We need a separate item which is dragged along the
125 * component's area, which can move freely and not attached to the caret itself.
126 * This area will then be used to update the caret position.
127 */
128 onXChanged: if (draggedItem.state === "") draggedItem.moveToCaret()
129 onYChanged: if (draggedItem.state === "") draggedItem.moveToCaret()
130 Component.onCompleted: draggedItem.moveToCaret()
131
132 //dragged item
133 Item {
134 id: draggedItem
135 objectName: cursorItem.positionProperty + "_draggeditem"
136 width: caret ? caret.width : 0
137 height: caret ? caret.height : 0
138 parent: handler.main
139 visible: cursorItem.visible && (cursorItem.opacity > 0.0)
140
141 // when the dragging ends, reposition the dragger back to caret
142 onStateChanged: {
143 if (state === "") {
144 draggedItem.moveToCaret();
145 }
146 }
147
148 /*
149 Mouse area to turn on dragging or selection mode when pressed
150 on the handler area. The drag mode is turned off when the drag
151 gets inactive or when the LeftButton is released.
152 */
153 MouseArea {
154 objectName: cursorItem.positionProperty + "_activator"
155 anchors.fill: parent
156 acceptedButtons: Qt.LeftButton | Qt.RightButton
157 preventStealing: true
158 enabled: parent.width && parent.height
159
160 onPressed: {
161 draggedItem.moveToCaret(mouse.x, mouse.y);
162 draggedItem.state = "dragging";
163 }
164 onPressAndHold: openPopover()
165 onClicked: if (mouse.button === Qt.RightButton) openPopover()
166 Ubuntu.Mouse.forwardTo: [dragger]
167 /*
168 As we are forwarding the events to the upper mouse area, the release
169 will not get into the normal MosueArea onRelease signal as the preventStealing
170 will not have any effect on the handling. However due to the mouse
171 filter's nature, we will still be able to grab mouse events and we
172 can stop dragging. We only handle the release in case the drag hasn't
173 been active at all, otherwise the drag will not be deactivated and we
174 will end up in a binding loop on the moveToCaret() next time the caret
175 handler is grabbed.
176 */
177 Ubuntu.Mouse.onReleased: {
178 if (!dragger.drag.active) {
179 draggedItem.state = "";
180 }
181 }
182 }
183
184 // aligns the draggedItem to the caret and resets the dragger
185 function moveToCaret(cx, cy) {
186 if (cx === undefined && cy === undefined) {
187 cx = mappedCursorPosition("x") + caretX;
188 cy = mappedCursorPosition("y") + caretY;
189 } else {
190 // move mouse position to caret
191 cx += draggedItem.x;
192 cy += draggedItem.y;
193 }
194
195 draggedItem.x = cx;
196 draggedItem.y = cy;
197 dragger.resetDrag();
198 }
199 // positions caret to the dragged position
200 function positionCaret() {
201 if (dragger.drag.active) {
202 handler.positionCaret(positionProperty,
203 dragger.thumbStartX + dragger.dragAmountX + handler.flickable.contentX,
204 dragger.thumbStartY + dragger.dragAmountY + handler.flickable.contentY);
205 }
206 }
207 }
208 MouseArea {
209 id: dragger
210 objectName: cursorItem.positionProperty + "_dragger"
211 // fill the entire component area
212 parent: handler.main
213 anchors.fill: parent
214 hoverEnabled: true
215 preventStealing: drag.active
216 enabled: draggedItem.enabled && draggedItem.state === "dragging"
217
218 property int thumbStartX
219 property int dragStartX
220 property int dragAmountX: dragger.drag.target.x - dragStartX
221 property int thumbStartY
222 property int dragStartY
223 property int dragAmountY: dragger.drag.target.y - dragStartY
224
225 function resetDrag() {
226 thumbStartX = mappedCursorPosition("x");
227 thumbStartY = mappedCursorPosition("y");
228 dragStartX = drag.target.x;
229 dragStartY = drag.target.y;
230 }
231
232 // do not set minimum/maximum so we can drag outside of the Flickable area
233 drag {
234 target: draggedItem
235 axis: handler.singleLine ? Drag.XAxis : Drag.XAndYAxis
236 // deactivate dragging
237 onActiveChanged: {
238 if (!drag.active) {
239 draggedItem.state = "";
240 }
241 }
242 }
243
244 onDragAmountXChanged: draggedItem.positionCaret()
245 onDragAmountYChanged: draggedItem.positionCaret()
246 }
247
248 // fake cursor, caret is reparented to it to avoid caret clipping
249 Item {
250 id: fakeCursor
251 parent: handler.main
252 width: cursorItem.width
253 height: cursorItem.height
254 //reparent caret to it
255 Component.onCompleted: if (caret) caret.parent = fakeCursor
256
257 x: mappedCursorPosition("x")
258 y: mappedCursorPosition("y")
259
260 // manual clipping: the caret should be visible only while the cursor's
261 // top/bottom falls into the text area
262 visible: {
263 if (!caret || !cursorItem.visible || cursorItem.opacity < 1.0)
264 return false;
265
266 var leftTop = Qt.point(x - handler.frameDistance.x, y + handler.frameDistance.y + handler.lineSpacing);
267 var rightBottom = Qt.point(x - handler.frameDistance.x, y + height - handler.frameDistance.y - handler.lineSpacing);
268 return (handler.visibleArea.contains(leftTop) || handler.visibleArea.contains(rightBottom));
269 }
270 }
62}271}
63272
=== modified file 'modules/Ubuntu/Components/TextField.qml'
--- modules/Ubuntu/Components/TextField.qml 2014-04-28 06:48:28 +0000
+++ modules/Ubuntu/Components/TextField.qml 2014-05-06 12:22:48 +0000
@@ -244,10 +244,8 @@
244244
245 Note that the root item of the delegate component must be a QQuickItem or245 Note that the root item of the delegate component must be a QQuickItem or
246 QQuickItem derived item.246 QQuickItem derived item.
247
248 \qmlproperty Component cursorDelegate
249 */247 */
250 property alias cursorDelegate: editor.cursorDelegate248 property Component cursorDelegate: null
251249
252 /*!250 /*!
253 The position of the cursor in the TextField.251 The position of the cursor in the TextField.
@@ -910,20 +908,6 @@
910 }908 }
911 }909 }
912910
913 // cursor
914 Component {
915 id: cursor
916 TextCursor {
917 //FIXME: connect to root object once we have all TextInput properties exposed
918 editorItem: editor
919 height: internal.lineSize
920 popover: control.popover
921 visible: editor.cursorVisible
922
923 Component.onCompleted: inputHandler.pressAndHold.connect(openPopover)
924 }
925 }
926
927 AbstractButton {911 AbstractButton {
928 id: clearButton912 id: clearButton
929 objectName: "clear_button"913 objectName: "clear_button"
@@ -939,7 +923,6 @@
939 (control.activeFocus && ((editor.text != "") || editor.inputMethodComposing))923 (control.activeFocus && ((editor.text != "") || editor.inputMethodComposing))
940924
941 Image {925 Image {
942 //anchors.fill: parent
943 anchors.verticalCenter: parent.verticalCenter926 anchors.verticalCenter: parent.verticalCenter
944 width: units.gu(3)927 width: units.gu(3)
945 height: width928 height: width
@@ -997,9 +980,9 @@
997 // FocusScope will forward focus to this component980 // FocusScope will forward focus to this component
998 focus: true981 focus: true
999 anchors.verticalCenter: parent.verticalCenter982 anchors.verticalCenter: parent.verticalCenter
1000 // get the control's style983 cursorDelegate: TextCursor {
1001 clip: true984 handler: inputHandler
1002 cursorDelegate: cursor985 }
1003 color: control.__styleInstance.color986 color: control.__styleInstance.color
1004 selectedTextColor: Theme.palette.selected.foregroundText987 selectedTextColor: Theme.palette.selected.foregroundText
1005 selectionColor: Theme.palette.selected.foreground988 selectionColor: Theme.palette.selected.foreground
@@ -1021,6 +1004,13 @@
1021 input: editor1004 input: editor
1022 flickable: flicker1005 flickable: flicker
1023 selectionModeTimeout: control.__styleInstance.selectionModeTimeout1006 selectionModeTimeout: control.__styleInstance.selectionModeTimeout
1007 /*
1008 In x direction we use 2 times the configured spacing, as we have
1009 both the overlay and the Flickable aligned with margins. On y
1010 direction we only use the simple spacing, the Flickable moves the
1011 top downwards.
1012 */
1013 frameDistance: Qt.point(2 * internal.spacing, internal.spacing)
1024 }1014 }
1025 }1015 }
1026 }1016 }
10271017
=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/TextAreaStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/TextAreaStyle.qml 2014-04-25 12:53:58 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/TextAreaStyle.qml 2014-05-06 12:22:48 +0000
@@ -18,6 +18,7 @@
18import Ubuntu.Components 1.118import Ubuntu.Components 1.1
1919
20// frame20// frame
21// FIXME: stabilize API
21Item {22Item {
22 id: visuals23 id: visuals
23 // style properties24 // style properties
@@ -36,17 +37,31 @@
36 Spacing between the frame and the text editor area37 Spacing between the frame and the text editor area
37 */38 */
38 property real frameSpacing: units.gu(1)39 property real frameSpacing: units.gu(1)
39 property real overlaySpacing: units.gu(0.5)40 property real overlaySpacing: frameSpacing / 2
4041
41 /*!42 /*!
42 Property holding the timeout in milliseconds the component enters into selection mode.43 Property holding the timeout in milliseconds the component enters into selection mode.
43 */44 */
44 property int selectionModeTimeout: 30045 property int selectionModeTimeout: 300
4546
47 /*!
48 The following properties define the name of the style components declaring
49 the styles for the main and the selection cursors. All cursors must defive
50 from TextCursorStyle.
51 */
52 property string mainCursorStyle: "TextCursorStyle.qml"
53 property string selectionStartCursorStyle: "TextSelectionStartCursorStyle.qml"
54 property string selectionEndCursorStyle: "TextSelectionEndCursorStyle.qml"
55
56 // style body
46 anchors.fill: parent57 anchors.fill: parent
58 objectName: "textarea_style"
4759
48 z: -160 z: -1
4961
62 /*!
63 Text input background
64 */
50 property Component background: UbuntuShape {65 property Component background: UbuntuShape {
51 property bool error: (styledItem.hasOwnProperty("errorHighlight") && styledItem.errorHighlight && !styledItem.acceptableInput)66 property bool error: (styledItem.hasOwnProperty("errorHighlight") && styledItem.errorHighlight && !styledItem.acceptableInput)
52 onErrorChanged: (error) ? visuals.errorColor : visuals.backgroundColor;67 onErrorChanged: (error) ? visuals.errorColor : visuals.backgroundColor;
5368
=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/TextCursorStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/TextCursorStyle.qml 2013-07-01 06:33:24 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/TextCursorStyle.qml 2014-05-06 12:22:48 +0000
@@ -16,48 +16,66 @@
1616
17import QtQuick 2.017import QtQuick 2.0
1818
19// FIXME : move the API into Ubuntu.Components.Style
19Item {20Item {
20 id: visuals21 id: cursorStyle
21 /*!22 /*!
22 Cursor color23 Property specifying the visible timeout of the cursor. It is not mandatory
23 */24 for styles to define values for this property if the cursor blinking is not
24 property color color: Theme.palette.selected.foreground25 desired. A value of 0 turns off the cursor blinking.
2526 */
26 /*!27 property int cursorVisibleTimeout: 800
27 Properties driving cursor blinking. If either of these values are 0, no28 /*!
28 blinking is provided.29 Property specifying the hidden timeout of the cursor. It is not mandatory
29 */30 for styles to define values for this property if the cursor blinking is not
30 property bool blinking: true31 desired. A value of 0 turns off the cursor blinking.
31 property int blinkTimeoutShown: 80032 */
32 property int blinkTimeoutHidden: 40033 property int cursorHiddenTimeout: 400
3334
34 /*!35 /*!
35 Selection mode pin styles36 Component defining the default cursor visuals.
36 */37 */
37 property var pinSize: units.gu(1.2)38 property Component cursorDelegate: delegate
38 property var pinSensingOffset: units.dp(4)39
39 property color pinColor: Theme.palette.selected.foreground40 /*!
4041 The item pointing to the cursor handler. Styles should set to null if the
41 anchors.fill: parent42 cursor does not have handler at all.
42 Rectangle {43 */
43 id: cursor44 property Item caret: caretItem
4445
45 property bool showCursor: styledItem.visible46 // style body
46 property bool timerShowCursor: true47 Component {
4748 id: delegate
48 visible: showCursor && timerShowCursor49 Rectangle {
49 color: visuals.color50 width: units.dp(1)
50 anchors.fill: parent51 color: Theme.palette.selected.foreground
5152 visible: blinkTimer.timerShowCursor
52 Timer {53 Timer {
53 interval: visuals.blinkTimeoutShown54 id: blinkTimer
54 running: cursor.showCursor && (visuals.blinkTimeoutShown > 0) && (visuals.blinkTimeoutHidden > 0) && visuals.blinking55 interval: cursorStyle.cursorVisibleTimeout
55 repeat: true56 running: (cursorStyle.cursorVisibleTimeout > 0) &&
56 onTriggered: {57 (cursorStyle.cursorHiddenTimeout > 0) &&
57 interval = (interval == visuals.blinkTimeoutShown) ?58 styledItem.visible
58 visuals.blinkTimeoutHidden : visuals.blinkTimeoutShown;59 repeat: true
59 cursor.timerShowCursor = !cursor.timerShowCursor;60 property bool timerShowCursor: true
61 onTriggered: {
62 interval = (interval == cursorStyle.cursorVisibleTimeout) ?
63 cursorStyle.cursorHiddenTimeout : cursorStyle.cursorVisibleTimeout;
64 timerShowCursor = !timerShowCursor;
65 }
60 }66 }
61 }67 }
62 }68 }
69
70 // caretItem
71 Image {
72 id: caretItem
73 source: "artwork/teardrop-left.png"
74 anchors {
75 top: parent.bottom
76 horizontalCenter: parent.horizontalCenter
77 topMargin: -units.gu(0.5)
78 horizontalCenterOffset: units.gu(0.7)
79 }
80 }
63}81}
6482
=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/TextFieldStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/TextFieldStyle.qml 2013-06-27 15:20:12 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/TextFieldStyle.qml 2014-05-06 12:22:48 +0000
@@ -17,4 +17,5 @@
17import QtQuick 2.017import QtQuick 2.0
1818
19TextAreaStyle {19TextAreaStyle {
20 objectName: "textfield_style"
20}21}
2122
=== added file 'modules/Ubuntu/Components/Themes/Ambiance/TextSelectionEndCursorStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/TextSelectionEndCursorStyle.qml 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/TextSelectionEndCursorStyle.qml 2014-05-06 12:22:48 +0000
@@ -0,0 +1,66 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18
19// FIXME : move the API into Ubuntu.Components.Style
20Item {
21 id: cursorStyle
22 /*!
23 Property specifying the visible timeout of the cursor. It is not mandatory
24 for styles to define values for this property if the cursor blinking is not
25 desired. A value of 0 turns off the cursor blinking.
26 */
27 property int cursorVisibleTimeout: 0
28 /*!
29 Property specifying the hidden timeout of the cursor. It is not mandatory
30 for styles to define values for this property if the cursor blinking is not
31 desired. A value of 0 turns off the cursor blinking.
32 */
33 property int cursorHiddenTimeout: 0
34
35 /*!
36 Component defining the default cursor visuals.
37 */
38 property Component cursorDelegate: delegate
39
40 /*!
41 The item pointing to the cursor handler. Styles should set to null if the
42 cursor does not have handler at all.
43 */
44 property Item caret: caretItem
45
46 // style body
47 Component {
48 id: delegate
49 Rectangle {
50 width: units.dp(1)
51 color: Theme.palette.selected.foreground
52 }
53 }
54
55 // caretItem
56 Image {
57 id: caretItem
58 source: "artwork/teardrop-left.png"
59 anchors {
60 top: parent.bottom
61 horizontalCenter: parent.horizontalCenter
62 topMargin: -units.gu(0.5)
63 horizontalCenterOffset: units.gu(0.7)
64 }
65 }
66}
067
=== added file 'modules/Ubuntu/Components/Themes/Ambiance/TextSelectionStartCursorStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/TextSelectionStartCursorStyle.qml 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/TextSelectionStartCursorStyle.qml 2014-05-06 12:22:48 +0000
@@ -0,0 +1,66 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18
19// FIXME : move the API into Ubuntu.Components.Style
20Item {
21 id: cursorStyle
22 /*!
23 Property specifying the visible timeout of the cursor. It is not mandatory
24 for styles to define values for this property if the cursor blinking is not
25 desired. A value of 0 turns off the cursor blinking.
26 */
27 property int cursorVisibleTimeout: 0
28 /*!
29 Property specifying the hidden timeout of the cursor. It is not mandatory
30 for styles to define values for this property if the cursor blinking is not
31 desired. A value of 0 turns off the cursor blinking.
32 */
33 property int cursorHiddenTimeout: 0
34
35 /*!
36 Component defining the default cursor visuals.
37 */
38 property Component cursorDelegate: delegate
39
40 /*!
41 The item pointing to the cursor handler. Styles should set to null if the
42 cursor does not have handler at all.
43 */
44 property Item caret: caretItem
45
46 // style body
47 Component {
48 id: delegate
49 Rectangle {
50 width: units.dp(1)
51 color: Theme.palette.selected.foreground
52 }
53 }
54
55 // caretItem
56 Image {
57 id: caretItem
58 source: "artwork/teardrop-right.png"
59 anchors {
60 top: parent.bottom
61 horizontalCenter: parent.horizontalCenter
62 topMargin: -units.gu(0.5)
63 horizontalCenterOffset: -units.gu(0.7)
64 }
65 }
66}
067
=== added file 'modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-left@20.png'
1Binary files modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-left@20.png 1970-01-01 00:00:00 +0000 and modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-left@20.png 2014-05-06 12:22:48 +0000 differ68Binary files modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-left@20.png 1970-01-01 00:00:00 +0000 and modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-left@20.png 2014-05-06 12:22:48 +0000 differ
=== added file 'modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-right@20.png'
2Binary files modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-right@20.png 1970-01-01 00:00:00 +0000 and modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-right@20.png 2014-05-06 12:22:48 +0000 differ69Binary files modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-right@20.png 1970-01-01 00:00:00 +0000 and modules/Ubuntu/Components/Themes/Ambiance/artwork/teardrop-right@20.png 2014-05-06 12:22:48 +0000 differ
=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/qmldir'
--- modules/Ubuntu/Components/Themes/Ambiance/qmldir 2014-04-28 14:04:29 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/qmldir 2014-05-06 12:22:48 +0000
@@ -46,3 +46,6 @@
4646
47#version 1.147#version 1.1
48ComboButtonStyle 1.1 ComboButtonStyle.qml48ComboButtonStyle 1.1 ComboButtonStyle.qml
49
50internal TextSelectionStartCursorStyle TextSelectionStartCursorStyle.qml
51internal TextSelectionEndCursorStyle TextSelectionEndCursorStyle.qml
4952
=== modified file 'modules/Ubuntu/Test/UbuntuTestCase.qml'
--- modules/Ubuntu/Test/UbuntuTestCase.qml 2014-04-28 06:06:32 +0000
+++ modules/Ubuntu/Test/UbuntuTestCase.qml 2014-05-06 12:22:48 +0000
@@ -66,6 +66,28 @@
66 return null;66 return null;
67 }67 }
6868
69 /*!
70 Finds a visible child of an \a item having a given \a property with a given
71 \a value.
72 */
73 function findChildWithProperty(item, property, value) {
74 var childs = new Array(0);
75 childs.push(item)
76 while (childs.length > 0) {
77 var child = childs[0];
78 if (child.hasOwnProperty(property) && (child[property] === value)) {
79 return child;
80 }
81 for (var i in childs[0].children) {
82 childs.push(childs[0].children[i])
83 }
84 childs.splice(0, 1);
85 }
86 return null;
87 }
88
89
90
69 /*!91 /*!
70 Move Mouse from x,y to distance of dx, dy divided to steps with a stepdelay (ms).92 Move Mouse from x,y to distance of dx, dy divided to steps with a stepdelay (ms).
71 */93 */
@@ -152,8 +174,9 @@
152 */174 */
153 function mouseLongPress(item, x, y, button, modifiers, delay) {175 function mouseLongPress(item, x, y, button, modifiers, delay) {
154 mousePress(item, x, y, button, modifiers, delay);176 mousePress(item, x, y, button, modifiers, delay);
155 // the delay is taken from QQuickMouseArea177 // the delay is taken from QQuickMouseArea, add few miliseconds to it to make sure we have
156 wait(800);178 // the long press triggered
179 wait(900);
157 }180 }
158181
159 /*!182 /*!
160183
=== modified file 'tests/resources/inputs/TextInputs.qml'
--- tests/resources/inputs/TextInputs.qml 2014-04-07 10:37:36 +0000
+++ tests/resources/inputs/TextInputs.qml 2014-05-06 12:22:48 +0000
@@ -74,6 +74,10 @@
74 autoSize: true74 autoSize: true
75 maximumLineCount: 075 maximumLineCount: 0
76 text: "Lorem Ipsum is simply dummy text\nof the printing and typesetting\nindustry.\n"76 text: "Lorem Ipsum is simply dummy text\nof the printing and typesetting\nindustry.\n"
77 cursorDelegate: Rectangle {
78 width: units.dp(4)
79 color: "blue"
80 }
77 }81 }
78 TextArea {82 TextArea {
79 autoSize: true83 autoSize: true
8084
=== modified file 'tests/unit_x11/tst_components/tst_textarea.qml'
--- tests/unit_x11/tst_components/tst_textarea.qml 2014-04-28 06:06:32 +0000
+++ tests/unit_x11/tst_components/tst_textarea.qml 2014-05-06 12:22:48 +0000
@@ -138,7 +138,7 @@
138 }138 }
139139
140 function test_0_cursorDelegate() {140 function test_0_cursorDelegate() {
141 compare((textArea.cursorDelegate!=null),true,"TextArea.cursorDelegate is not null")141 verify(textArea.cursorDelegate === null, "TextArea.cursorDelegate is not null")
142 }142 }
143143
144 function test_0_cursorPosition() {144 function test_0_cursorPosition() {
@@ -242,15 +242,16 @@
242 compare(textArea.highlighted, textArea.focus, "highlighted is the same as focused");242 compare(textArea.highlighted, textArea.focus, "highlighted is the same as focused");
243 }243 }
244244
245 function test_contentHeight() {245 function test_0_contentHeight() {
246 compare(textArea.contentHeight>0,true,"contentHeight over 0 units on default")246 verify(textArea.contentHeight > 0, "contentHeight over 0 units on default")
247 var newValue = 200;247 var newValue = 200;
248 textArea.contentHeight = newValue;248 textArea.contentHeight = newValue;
249 compare(textArea.contentHeight,newValue,"set/get");249 compare(textArea.contentHeight,newValue,"set/get");
250 }250 }
251251
252 function test_contentWidth() {252 function test_0_contentWidth() {
253 compare(textArea.contentWidth,units.gu(30),"contentWidth is 30 units on default")253 var style = findChild(textArea, "textarea_style");
254 compare(textArea.contentWidth, units.gu(30) - 2 * style.frameSpacing, "contentWidth is the implicitWidth - 2 times the frame size on default")
254 var newValue = 200;255 var newValue = 200;
255 textArea.contentWidth = newValue;256 textArea.contentWidth = newValue;
256 compare(textArea.contentWidth,newValue,"set/get");257 compare(textArea.contentWidth,newValue,"set/get");
257258
=== modified file 'tests/unit_x11/tst_components/tst_textfield.qml'
--- tests/unit_x11/tst_components/tst_textfield.qml 2014-04-28 06:06:32 +0000
+++ tests/unit_x11/tst_components/tst_textfield.qml 2014-05-06 12:22:48 +0000
@@ -156,7 +156,7 @@
156 }156 }
157157
158 function test_0_cursorDelegate() {158 function test_0_cursorDelegate() {
159 verify(textField.cursorDelegate, "cursorDelegate set by default")159 verify(textField.cursorDelegate === null, "cursorDelegate not set by default")
160 }160 }
161161
162 function test_0_cursorPosition() {162 function test_0_cursorPosition() {
163163
=== added file 'tests/unit_x11/tst_components/tst_textinput_common.qml'
--- tests/unit_x11/tst_components/tst_textinput_common.qml 1970-01-01 00:00:00 +0000
+++ tests/unit_x11/tst_components/tst_textinput_common.qml 2014-05-06 12:22:48 +0000
@@ -0,0 +1,198 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import QtTest 1.0
19import Ubuntu.Test 1.0
20import Ubuntu.Components 1.1
21
22Item {
23 id: testMain
24 width: units.gu(40)
25 height: units.gu(71)
26
27 Column {
28 spacing: units.gu(1)
29 TextField {
30 id: textField
31 }
32 TextArea {
33 id: textArea
34 }
35 }
36
37 SignalSpy {
38 id: cursorPositionSpy
39 signalName: "onCursorPositionChanged"
40 }
41 SignalSpy {
42 id: selectionStartSpy
43 signalName: "onSelectionStartChanged"
44 }
45 SignalSpy {
46 id: selectionEndSpy
47 signalName: "onSelectionEndChanged"
48 }
49 SignalSpy {
50 id: selectedTextSpy
51 signalName: "onSelectedTextChanged"
52 }
53 SignalSpy {
54 id: popupSpy
55 signalName: "pressAndHold"
56 }
57 SignalSpy {
58 id: movementXSpy
59 signalName: "onContentXChanged"
60 }
61 SignalSpy {
62 id: movementYSpy
63 signalName: "contentYChanged"
64 }
65
66 UbuntuTestCase {
67 name: "TextInputCaretTest"
68 when: windowShown
69
70 function init() {
71 textField.text = "This is a single line text input called TextField.";
72 textArea.text = "This is a multiline text input component called TextArea. It supports fix size as well as auto-expanding behavior.";
73 textField.cursorPosition = 0;
74 textArea.cursorPosition = 0;
75 waitForRendering(textField, 500);
76 waitForRendering(textArea, 500);
77 }
78
79 function cleanup() {
80 textField.focus = false;
81 textArea.focus = false;
82 cursorPositionSpy.clear();
83 selectionStartSpy.clear();
84 selectionEndSpy.clear();
85 selectedTextSpy.clear();
86 popupSpy.clear();
87 movementXSpy.clear();
88 movementYSpy.clear();
89 }
90
91 function test_textfield_grab_caret_data() {
92 return [
93 {input: textField},
94 {input: textArea},
95 ];
96 }
97
98 function test_textfield_grab_caret(data) {
99 data.input.focus = true;
100
101 var draggedItem = findChild(data.input, "cursorPosition_draggeditem");
102 var drag_activator = findChild(data.input, "cursorPosition_activator");
103 var dragger = findChild(data.input, "cursorPosition_dragger");
104
105 // drag the cursor, observe cursorPositionChanged
106 cursorPositionSpy.target = data.input;
107 var x = drag_activator.width / 2;
108 var y = drag_activator.height / 2;
109 mousePress(drag_activator, x, y);
110 compare(draggedItem.state, "dragging", "the caret hasn't been activated");
111 // drag the mouse
112 mouseMoveSlowly(dragger, x, y, 100, 0, 10, 0);
113 mouseRelease(dragger, x + 100, y);
114 waitForRendering(data.input, 1000);
115 compare(draggedItem.state, "", "the caret hasn't been deactivated");
116 cursorPositionSpy.wait();
117 }
118
119 function test_textfield_grab_selection_cursors_data() {
120 return [
121 {input: textField, cursorSpy: selectionStartSpy, dragPrefix: "selectionStart", startDx: 0, startDy: 0, dragDx: 100, dragDy: 0, movingSpy: null},
122 {input: textArea, cursorSpy: selectionStartSpy, dragPrefix: "selectionStart", startDx: 0, startDy: 0, dragDx: 100, dragDy: 0, movingSpy: null},
123 {input: textField, cursorSpy: selectionEndSpy, dragPrefix: "selectionEnd", startDx: 0, startDy: 0, dragDx: 200, dragDy: 100, movingSpy: movementXSpy, flicker: "textfield_scroller"},
124 {input: textArea, cursorSpy: selectionEndSpy, dragPrefix: "selectionEnd", startDx: 0, startDy: 0, dragDx: 200, dragDy: 100, movingSpy: movementYSpy, flicker: "textarea_scroller"},
125 ];
126 }
127 function test_textfield_grab_selection_cursors(data) {
128 if (data.movingSpy) {
129 var flicker = findChild(data.input, data.flicker)
130 data.movingSpy.target = flicker;
131 }
132 data.input.focus = true;
133 // make sure the text is long enough
134 data.input.text += data.input.text;
135
136 // select text in front
137 data.input.select(0, 10);
138 var draggedItem = findChild(data.input, data.dragPrefix + "_draggeditem");
139 var drag_activator = findChild(data.input, data.dragPrefix + "_activator");
140 var dragger = findChild(data.input, data.dragPrefix + "_dragger");
141 data.cursorSpy.target = data.input;
142
143 // grab the selection and drag it
144 var x = drag_activator.width / 2 + data.startDx;
145 var y = drag_activator.height / 2 + data.startDy;
146 selectedTextSpy.target = data.input;
147 mousePress(drag_activator, x, y);
148 compare(draggedItem.state, "dragging", "the caret hasn't been activated");
149 // drag the mouse
150 mouseMoveSlowly(dragger, x, y, data.dragDx, data.dragDy, 15, 100);
151 mouseRelease(dragger, x + data.dragDx, y + data.dragDy);
152 waitForRendering(data.input, 500);
153 compare(draggedItem.state, "", "the caret hasn't been deactivated");
154 data.cursorSpy.wait();
155 selectedTextSpy.wait();
156 if (data.movingSpy) {
157 data.movingSpy.wait();
158 }
159 }
160
161 function test_clear_text_using_popover_data() {
162 return [
163 {input: textField},
164 {input: textArea},
165 ];
166 }
167
168 function test_clear_text_using_popover(data) {
169 var handler = findChild(data.input, "input_handler");
170 popupSpy.target = handler;
171 data.input.focus = true;
172
173 // invoke popover
174 var x = data.input.width / 2;
175 var y = data.input.height / 2;
176 mouseLongPress(data.input, x, y);
177 popupSpy.wait();
178 mouseRelease(data.input, x, y);
179 var popover = findChild(testMain, "text_input_popover");
180 verify(popover, "Cannot retrieve default TextInputPopover");
181 waitForRendering(popover);
182 // select all
183 var selectAll = findChildWithProperty(popover, "text", "Select All");
184 verify(selectAll, "Select All item not found");
185 mouseClick(selectAll, selectAll.width / 2, selectAll.height / 2);
186 waitForRendering(data.input, 1000);
187 compare(data.input.text, data.input.selectedText, "Not all the text is selected");
188 // delete with key press
189 keyClick(Qt.Key_Backspace);
190 waitForRendering(data.input, 1000);
191 compare(data.input.text, "", "The text has not been deleted");
192
193 // dismiss popover
194 mouseClick(testMain, testMain.width / 2, testMain.height / 2);
195 wait(200);
196 }
197 }
198}

Subscribers

People subscribed via source and target branches