1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the Qt Components project.
9 ** $QT_BEGIN_LICENSE:BSD$
10 ** You may use this file under the terms of the BSD license as follows:
12 ** "Redistribution and use in source and binary forms, with or without
13 ** modification, are permitted provided that the following conditions are
15 ** * Redistributions of source code must retain the above copyright
16 ** notice, this list of conditions and the following disclaimer.
17 ** * Redistributions in binary form must reproduce the above copyright
18 ** notice, this list of conditions and the following disclaimer in
19 ** the documentation and/or other materials provided with the
21 ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22 ** the names of its contributors may be used to endorse or promote
23 ** products derived from this software without specific prior written
26 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
39 ****************************************************************************/
41 function findFlickable(component) {
42 var nextParent = component
43 var flickableItem = null
45 if(nextParent.flicking !== undefined && nextParent.flickableDirection !== undefined)
46 flickableItem = nextParent
48 nextParent = nextParent.parent
50 if (flickableItem) return flickableItem
54 function animateContentY(animation, flickable, newContentY) {
55 animation.target = flickable
56 animation.to = newContentY
57 animation.running = true
60 function locateFlickableY(flickable) {
61 switch(screen.currentOrientation) {
62 case Screen.Landscape:
63 return flickable.mapToItem(null, flickable.x, flickable.y).y
65 case Screen.LandscapeInverted:
66 return screen.displayHeight - flickable.mapToItem(null, flickable.x, flickable.y).y
69 return flickable.mapToItem(null, flickable.x, flickable.y).x
71 case Screen.PortraitInverted:
72 return screen.displayWidth - flickable.mapToItem(null, flickable.x, flickable.y).x
76 function getMargin() {
77 switch(screen.currentOrientation) {
78 case Screen.Landscape:
79 case Screen.LandscapeInverted:
82 case Screen.PortraitInverted:
89 function repositionFlickable(animation) {
90 inputContext.updateMicroFocus()
91 var mf = inputContext.microFocus
93 if(mf.x == -1 && mf.y == -1)
96 var object = findFlickable(parent)
99 var flickable = object
101 // Specifies area from bottom and top when repositioning should be triggered
102 var margin = getMargin()
103 var newContentY = flickable.contentY
104 var flickableY = locateFlickableY(flickable)
106 switch(screen.currentOrientation) {
107 case Screen.Landscape:
108 if(flickableY + flickable.height - mf.height - margin < mf.y) {
109 // Find dY just to make textfield visible
110 var dY = mf.y - flickableY - flickable.height
112 dY += flickable.height / 2
114 } else if(flickableY + margin > mf.y) {
115 var dY = flickableY - mf.y
116 dY += flickable.height / 2
122 case Screen.LandscapeInverted:
123 // In inverted screen we need to compensate for the focus height
124 var invertedMfY = screen.displayHeight - mf.y - mf.height
126 if(flickableY + flickable.height - mf.height - margin < invertedMfY) {
127 var dY = invertedMfY - flickableY - flickable.height
128 dY += flickable.height / 2 + mf.height / 2
129 } else if(flickableY + margin > invertedMfY){
130 var dY = flickableY - invertedMfY
131 dY += flickable.height / 2 - mf.height / 2
137 case Screen.Portrait:
138 if(flickableY + flickable.height - mf.width - margin < mf.x) {
139 var dY = mf.x - flickableY - flickable.height
140 dY += flickable.height / 2
142 } else if(flickableY + margin > mf.x){
143 var dY = flickableY - mf.x
144 dY += flickable.height / 2
150 case Screen.PortraitInverted:
151 var invertedMfX = screen.displayWidth - mf.x - mf.width
153 if(flickableY + flickable.height - mf.width - margin < invertedMfX) {
154 var dY = invertedMfX - flickableY - flickable.height + mf.height
155 dY += flickable.height / 2 + mf.height
157 } else if(flickableY + margin > invertedMfX){
158 var dY = flickableY - invertedMfX
159 dY += flickable.height / 2 - mf.height
166 // If overpanned, set contentY to max possible value (reached bottom)
167 if(newContentY > flickable.contentHeight - flickable.height)
168 newContentY = flickable.contentHeight - flickable.height
170 // If overpanned, set contentY to min possible value (reached top)
174 if(newContentY != flickable.contentY) {
175 animateContentY(animation, flickable, newContentY)
180 function injectWordToPreedit(newCursorPosition) {
181 var preeditStart = previousWordStart(newCursorPosition);
182 var preeditEnd = nextWordEnd(newCursorPosition);
184 // copy word to preedit text
185 var preeditText = root.text.substring(preeditStart,preeditEnd);
188 cursorPosition = preeditStart;
190 var eventCursorPosition = newCursorPosition-preeditStart;
192 return inputContext.setPreeditText(preeditText, eventCursorPosition, 0, preeditText.length);
195 function previousWordStart(pos) {
198 if (ret && atWordSeparator(ret - 1)) {
200 while (ret && atWordSeparator(ret - 1))
203 while (ret && !atSpace(ret - 1) && !atWordSeparator(ret - 1))
210 function nextWordEnd(pos) {
212 var len = root.text.length;
214 if (ret < len && atWordSeparator(ret)) {
216 while (ret < len && atWordSeparator(ret))
219 while (ret < len && !atSpace(ret) && !atWordSeparator(ret))
226 function atSpace(pos) {
227 var c = root.text.charAt(pos);
234 function atWordSeparator(pos) {
235 switch (root.text.charAt(pos)) {
272 var MIN_UPDATE_INTERVAL = 30
274 function filteredInputContextUpdate() {
275 if (Date.now() - lastUpdateTime > MIN_UPDATE_INTERVAL || !lastUpdateTime) {
276 inputContext.update();
277 lastUpdateTime = Date.now();