20 ** |
20 ** |
21 ** If you have questions regarding the use of this file, please contact |
21 ** If you have questions regarding the use of this file, please contact |
22 ** Nokia at developer.feedback@nokia.com. |
22 ** Nokia at developer.feedback@nokia.com. |
23 ** |
23 ** |
24 ****************************************************************************/ |
24 ****************************************************************************/ |
|
25 |
25 #include "hbabstractvkbhost.h" |
26 #include "hbabstractvkbhost.h" |
26 #include "hbabstractvkbhost_p.h" |
27 #include "hbabstractvkbhost_p.h" |
|
28 #include "private/hbvkbgeometrylogic_p.h" |
|
29 #include "hbvkbhostcontainerwidget_p.h" |
27 #include "hbinputvirtualkeyboard.h" |
30 #include "hbinputvirtualkeyboard.h" |
28 #include "hbinputsettingproxy.h" |
31 #include "hbinputsettingproxy.h" |
29 #include "hbinputvkbhostbridge.h" |
32 #include "hbinputvkbhostbridge.h" |
|
33 #include "hbvkbconstants_p.h" |
|
34 #include "hbwidgetfeedback.h" |
30 #include "hbinputmethod.h" |
35 #include "hbinputmethod.h" |
31 #include "hbdeviceprofile.h" |
36 #include "hbdeviceprofile.h" |
|
37 #include "hbscrollarea.h" |
32 #include "hbmainwindow.h" |
38 #include "hbmainwindow.h" |
|
39 #include "hbpopup_p.h" |
33 #include "hbpopup.h" |
40 #include "hbpopup.h" |
34 #include "hbview.h" |
41 #include "hbview.h" |
35 #include "hbwidgetfeedback.h" |
|
36 #include "hbinstance.h" |
42 #include "hbinstance.h" |
37 |
43 |
38 #include <QTextEdit> |
44 #include <QTextEdit> |
39 |
45 |
40 const int HbAnimationTime = 200; |
|
41 const qreal HbEditorExtraMargin = 5.0; |
|
42 const qreal HbCursorLineMargin = 15.0; |
|
43 const qreal HbContainerBorderMargin = 20.0; |
|
44 const qreal HbHeightVerticalFactor = 0.5; |
|
45 const qreal HbHeightHorizFactor = 0.7; |
|
46 const QString KHandWritingName("Handwriting"); |
46 const QString KHandWritingName("Handwriting"); |
47 // see hbpopup.cpp for this |
47 // see hbpopup.cpp for this |
48 extern const char* KPositionManagedByVKB; |
48 extern const char* KPositionManagedByVKB; |
49 |
49 |
50 /// @cond |
50 /*! |
51 |
51 @stable |
52 HbVkbHostContainerWidget::HbVkbHostContainerWidget(QObject *containterWidget) |
52 @hbcore |
53 : mContainerWidget(containterWidget) |
|
54 { |
|
55 } |
|
56 |
|
57 // sets container widgets position to new position. |
|
58 void HbVkbHostContainerWidget::setPos(QPointF newPosition) |
|
59 { |
|
60 if (mContainerWidget) { |
|
61 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(mContainerWidget); |
|
62 if (graphicsObject) { |
|
63 graphicsObject->setPos(newPosition); |
|
64 return; |
|
65 } |
|
66 |
|
67 QWidget *qWidget = qobject_cast<QWidget *>(mContainerWidget); |
|
68 if (qWidget) { |
|
69 #ifdef Q_WS_WIN |
|
70 QPoint finalPosition = newPosition.toPoint(); |
|
71 finalPosition -= qWidget->geometry().topLeft() - qWidget->frameGeometry().topLeft(); |
|
72 qWidget->move(finalPosition); |
|
73 #else |
|
74 qWidget->move(newPosition.toPoint()); |
|
75 #endif |
|
76 return; |
|
77 } |
|
78 } |
|
79 } |
|
80 |
|
81 // returns the global position, if container widget is a QGraphicsObject, it returns |
|
82 // scene position. In case the widget is QWidget it returns global co-ordinates |
|
83 QPointF HbVkbHostContainerWidget::pos() |
|
84 { |
|
85 if (mContainerWidget) { |
|
86 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(mContainerWidget); |
|
87 if (graphicsObject) { |
|
88 return graphicsObject->pos();; |
|
89 } |
|
90 |
|
91 QWidget *qWidget = qobject_cast<QWidget *>(mContainerWidget); |
|
92 if (qWidget) { |
|
93 return qWidget->mapToGlobal(QPoint(0, 0)); |
|
94 } |
|
95 } |
|
96 |
|
97 return QPointF(0, 0); |
|
98 } |
|
99 |
|
100 // returns the bounding rect in global co-ordinate, if container widget is a QGraphicsObject |
|
101 // it returns in scene co-ordinate, incase widget is QWidget it returns in global co-ordinate |
|
102 QRectF HbVkbHostContainerWidget::sceneBoundingRect() |
|
103 { |
|
104 if (mContainerWidget) { |
|
105 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(mContainerWidget); |
|
106 if (graphicsObject) { |
|
107 return graphicsObject->sceneBoundingRect();; |
|
108 } |
|
109 |
|
110 QWidget *qWidget = qobject_cast<QWidget *>(mContainerWidget); |
|
111 if (qWidget) { |
|
112 return QRectF(qWidget->mapToGlobal(QPoint(0, 0)), qWidget->size()); |
|
113 } |
|
114 } |
|
115 |
|
116 return QRectF(0, 0, 0, 0); |
|
117 } |
|
118 |
|
119 // connect container specific signals here. |
|
120 void HbVkbHostContainerWidget::connectSignals(QObject *receiver) |
|
121 { |
|
122 if (qobject_cast<QGraphicsObject *> (mContainerWidget)) { |
|
123 QObject::connect(mContainerWidget, SIGNAL(yChanged()), |
|
124 receiver, SLOT(ensureCursorVisibility())); |
|
125 } |
|
126 |
|
127 HbPopup *popup = qobject_cast<HbPopup *>(mContainerWidget); |
|
128 if (popup) { |
|
129 QObject::connect(popup, SIGNAL(aboutToHide()), receiver, SLOT(containerAboutToClose())); |
|
130 } |
|
131 |
|
132 HbView *view = qobject_cast<HbView *>(mContainerWidget); |
|
133 if (view) { |
|
134 QObject::connect(view->mainWindow(), SIGNAL(currentViewChanged(HbView *)), |
|
135 receiver, SLOT(currentViewChanged(HbView *))); |
|
136 } |
|
137 } |
|
138 |
|
139 // disconnect container specific signals here. |
|
140 void HbVkbHostContainerWidget::disconnectSignals(QObject *receiver) |
|
141 { |
|
142 if (qobject_cast<QGraphicsObject *> (mContainerWidget)) { |
|
143 QObject::disconnect(mContainerWidget, SIGNAL(yChanged()), |
|
144 receiver, SLOT(ensureCursorVisibility())); |
|
145 } |
|
146 |
|
147 HbPopup *popup = qobject_cast<HbPopup *>(mContainerWidget); |
|
148 if (popup) { |
|
149 QObject::disconnect(popup, SIGNAL(aboutToHide()), receiver, SLOT(containerAboutToClose())); |
|
150 } |
|
151 |
|
152 HbPopup *view = qobject_cast<HbPopup *>(mContainerWidget); |
|
153 if (view) { |
|
154 QObject::disconnect(view->mainWindow(), SIGNAL(currentViewChanged(HbView *)), |
|
155 receiver, SLOT(currentViewChanged(HbView *))); |
|
156 } |
|
157 } |
|
158 |
|
159 /// @endcond |
|
160 |
|
161 /*! |
|
162 \proto |
|
163 \class HbAbstractVkbHost |
53 \class HbAbstractVkbHost |
164 \brief Base class for HbCore's virtual keyboard hosts. |
54 \brief The default virtual keyboard host |
165 |
55 |
166 This class contains common code for HbCore's virtual keyboard hosts. |
56 This class implements the default virtual keyboard host. A virtual keyboard |
167 */ |
57 host is responsible for the interaction between application background |
168 |
58 and the virtual keyboard widget when a virtual keyboard becomes visible. |
169 /// @cond |
59 |
|
60 Its main task is to guarantee that editor's cursor line remains visible |
|
61 and that the virtual keyboard widget doesn't cover it. |
|
62 |
|
63 The abstract vkb host does this by moving the editor container around in suitable way. |
|
64 |
|
65 See \ref vkbHandling "virtual keyboard handling guide" for more information |
|
66 |
|
67 \sa HbVkbHost |
|
68 \sa HbShrinkingVkbHost |
|
69 \sa HbStaticVkbHost |
|
70 */ |
170 |
71 |
171 HbAbstractVkbHostPrivate::HbAbstractVkbHostPrivate(HbAbstractVkbHost *myHost, QObject *containerWidget) |
72 HbAbstractVkbHostPrivate::HbAbstractVkbHostPrivate(HbAbstractVkbHost *myHost, QObject *containerWidget) |
172 : q_ptr(myHost), |
73 : q_ptr(myHost), |
173 mCallback(0), |
74 mCallback(0), |
174 mKeypad(0), |
75 mKeypad(0), |
175 mContainerWidget(new HbVkbHostContainerWidget(containerWidget)), |
76 mContainerWidget(new HbVkbHostContainerWidget(containerWidget)), |
176 mTimeLine(HbAnimationTime), |
77 mTimeLine(HbVkbAnimationTime), |
177 mKeypadStatus(HbVkbHost::HbVkbStatusClosed), |
78 mKeypadStatus(HbVkbHost::HbVkbStatusClosed), |
178 mKeypadOperationOngoing(false), |
79 mKeypadOperationOngoing(false), |
179 mOriginalContainerPosition(QPointF(0, 0)), |
80 mOriginalContainerPosition(QPointF(0, 0)), |
180 mContainerMovementStartingPoint(QPointF(0, 0)), |
81 mContainerMovementStartingPoint(QPointF(0, 0)), |
181 mContainerMovementVector(QPointF(0, 0)), |
82 mContainerMovementVector(QPointF(0, 0)), |
182 mKeypadMovementStartingPoint(QPointF(0, 0)), |
83 mKeypadMovementStartingPoint(QPointF(0, 0)), |
183 mKeypadMovementVector(QPointF(0, 0)), |
84 mKeypadMovementVector(QPointF(0, 0)), |
184 mInputMethod(0), |
85 mInputMethod(0), |
185 mKeypadStatusBeforeOrientationChange(HbVkbHost::HbVkbStatusClosed) |
86 mKeypadStatusBeforeOrientationChange(HbVkbHost::HbVkbStatusClosed), |
|
87 mTitleBarHiddenByVkbHost(false), |
|
88 mStatusBarHiddenByVkbHost(false), |
|
89 mMarginInPixels(0) |
186 { |
90 { |
187 mTimeLine.setUpdateInterval(16); |
91 mTimeLine.setUpdateInterval(16); |
|
92 mMarginInPixels = HbDeviceProfile::current().unitValue() * HbVkbHostMargin; |
188 } |
93 } |
189 |
94 |
190 HbAbstractVkbHostPrivate::~HbAbstractVkbHostPrivate() |
95 HbAbstractVkbHostPrivate::~HbAbstractVkbHostPrivate() |
191 { |
96 { |
192 delete mContainerWidget; |
97 delete mContainerWidget; |
193 } |
98 } |
194 |
99 |
|
100 /*! |
|
101 \internal |
|
102 Initializes starting values to parameters needed for running the keypad and |
|
103 container widget animation effects. |
|
104 */ |
195 void HbAbstractVkbHostPrivate::prepareAnimationsCommon() |
105 void HbAbstractVkbHostPrivate::prepareAnimationsCommon() |
196 { |
106 { |
197 if (mContainerWidget->widgetObject() && mKeypad) { |
107 // Initialize movement variables to starting values. These will |
|
108 // be fine tuned later. |
|
109 mKeypadMovementVector = QPointF(0, 0); |
|
110 mContainerMovementVector = QPointF(0, 0); |
|
111 mContainerMovementStartingPoint = QPointF(); |
|
112 mKeypadMovementStartingPoint = QPointF(); |
|
113 mScrollAreaRect = QRectF(); |
|
114 |
|
115 if (mContainerWidget && mContainerWidget->widgetObject() && mKeypad) { |
198 // If the keyboard is not already open, remember the original position. |
116 // If the keyboard is not already open, remember the original position. |
199 // That is where the container will eventually be returned to. |
117 // That is where the container will eventually be returned to. |
200 if (mKeypadStatus == HbVkbHost::HbVkbStatusClosed) { |
118 if (mKeypadStatus == HbVkbHost::HbVkbStatusClosed) { |
201 mOriginalContainerPosition = mContainerWidget->pos(); |
119 mOriginalContainerPosition = mContainerWidget->pos(); |
202 } |
120 } |
203 |
121 |
204 // Initialize movement variables to starting values. These will |
|
205 // be fine tuned later. |
|
206 mKeypadMovementVector = QPointF(0, 0); |
|
207 mContainerMovementVector = QPointF(0, 0); |
|
208 mContainerMovementStartingPoint = mContainerWidget->pos(); |
122 mContainerMovementStartingPoint = mContainerWidget->pos(); |
209 mKeypadMovementStartingPoint = mKeypad->pos(); |
123 mKeypadMovementStartingPoint = mKeypad->pos(); |
210 } |
124 } |
211 |
125 |
212 mScreenSize = screenSize(); |
126 mScreenSize = screenSize(); |
213 } |
127 |
214 |
128 // Make sure that the editor is completely visible inside a scroll area. |
|
129 ensureVisibilityInsideScrollArea(); |
|
130 } |
|
131 |
|
132 /*! |
|
133 \internal |
|
134 Sets up view and focus object variables. |
|
135 */ |
|
136 bool HbAbstractVkbHostPrivate::getViewAndFocusObjects(HbView*& currentView, HbInputFocusObject*& focusObject) |
|
137 { |
|
138 if (!mKeypad || !mInputMethod || !mContainerWidget ) { |
|
139 return false; |
|
140 } |
|
141 |
|
142 HbMainWindow* window = mainWindow(); |
|
143 if (!window) { |
|
144 return false; |
|
145 } |
|
146 |
|
147 // Update margin pixel value while you're at it. |
|
148 mMarginInPixels = HbDeviceProfile::profile(window).unitValue() * HbVkbHostMargin; |
|
149 |
|
150 currentView = window->currentView(); |
|
151 if (!currentView) { |
|
152 return false; |
|
153 } |
|
154 |
|
155 focusObject = mInputMethod->focusObject(); |
|
156 if (!focusObject) { |
|
157 return false; |
|
158 } |
|
159 |
|
160 return true; |
|
161 } |
|
162 |
|
163 /*! |
|
164 \internal |
|
165 Sets up the container widget animation effect. |
|
166 */ |
215 bool HbAbstractVkbHostPrivate::prepareContainerAnimation(HbVkbHost::HbVkbStatus status) |
167 bool HbAbstractVkbHostPrivate::prepareContainerAnimation(HbVkbHost::HbVkbStatus status) |
216 { |
168 { |
217 if (!mKeypad || !mContainerWidget->widgetObject() || !mInputMethod || !mInputMethod->focusObject()) { |
169 // Init and check main objects |
|
170 HbView* currentView = 0; |
|
171 HbInputFocusObject* focusObject = 0; |
|
172 if (!getViewAndFocusObjects(currentView, focusObject)) { |
218 return false; |
173 return false; |
219 } |
174 } |
220 |
175 |
|
176 bool result = false; |
|
177 |
221 if (status == HbVkbHost::HbVkbStatusOpened) { |
178 if (status == HbVkbHost::HbVkbStatusOpened) { |
222 // Calculate the area that remains visible when the keypad is open. |
179 // Init parameters before calling. |
223 QRectF visibleArea = QRectF(0.0, 0.0, mScreenSize.width(), mScreenSize.height() - mKeypad->size().height()); |
180 QSizeF keypadSize = mKeypad->size(); |
224 |
181 QRectF viewRect = currentView->sceneBoundingRect(); |
225 // Find out the container area. |
182 bool isPopupType = qobject_cast<HbPopup *>(mContainerWidget->widgetObject()) != 0; |
226 QRectF containerArea = mContainerWidget->sceneBoundingRect(); |
183 bool vkbOpen = mKeypadStatus == HbVkbHost::HbVkbStatusOpened; |
227 containerArea.adjust(0.0, -HbContainerBorderMargin, 0.0, HbContainerBorderMargin); |
184 QRectF containerRect = mContainerWidget->sceneBoundingRect(); |
228 |
185 QRectF editorRect = findEditorRect(focusObject); |
229 if (visibleArea.contains(containerArea)) { |
186 QRectF cursorRect = focusObject->microFocus(); |
230 // The whole container is already inside the visible area, nothing to do. |
187 QPointF fixedMovement = mContainerWidget->fixedContainerMovement(); |
231 return false; |
188 |
232 } |
189 // We know that the container will be moved at least the amount of |
233 |
190 // fixed movement vector (which typically, if non-zero, is the |
234 if (visibleArea.height() >= containerArea.height()) { |
191 // height of the title bar). So we reduce the keypad area |
235 // It isn't in the visible area yet but fits there. Let's move it there. |
192 // to make the calculations match (fixed movement points |
236 mContainerMovementVector = QPointF(0.0, visibleArea.bottom() - containerArea.bottom()); |
193 // to negative direction, that's why addition). |
|
194 if (!vkbOpen) { |
|
195 keypadSize.setHeight(keypadSize.height() + fixedMovement.y()); |
|
196 } |
|
197 |
|
198 // Initialize geometry calculation unit to handle all geometry calculations. |
|
199 HbVkbGeometryLogicPrivate unit = HbVkbGeometryLogicPrivate( |
|
200 mScreenSize, |
|
201 keypadSize, |
|
202 viewRect, |
|
203 isPopupType, |
|
204 vkbOpen, |
|
205 containerRect, |
|
206 editorRect, |
|
207 cursorRect, |
|
208 mMarginInPixels); |
|
209 |
|
210 result = unit.calculateContainerMovement(mContainerMovementVector); |
|
211 if (!vkbOpen) { |
|
212 // Apply fixed movement only if the keyboard is not already open. |
|
213 // Fixed movement is used for hiding the title bar. |
|
214 mContainerMovementVector = selectLongestVerticalVector(fixedMovement, mContainerMovementVector); |
|
215 } |
|
216 } else if (status == HbVkbHost::HbVkbStatusClosed) { |
|
217 if (mContainerMovementStartingPoint != mOriginalContainerPosition) { |
|
218 mContainerMovementVector = mOriginalContainerPosition - mContainerMovementStartingPoint; |
|
219 result = true; |
|
220 } |
|
221 } |
|
222 |
|
223 return result; |
|
224 } |
|
225 |
|
226 /*! |
|
227 \internal |
|
228 Sets up the keypad widget animation effect. |
|
229 */ |
|
230 bool HbAbstractVkbHostPrivate::prepareKeypadAnimation(HbVkbHost::HbVkbStatus status) |
|
231 { |
|
232 if (mKeypad) { |
|
233 if (status == HbVkbHost::HbVkbStatusOpened) { |
|
234 if (mKeypadStatus == HbVkbHost::HbVkbStatusClosed) { |
|
235 // Set up keyboard open animation. |
|
236 mKeypadMovementStartingPoint.setY(mScreenSize.height()); |
|
237 mKeypadMovementVector.setY(-mKeypad->size().height()); |
|
238 if (!disableCursorShift()) { |
|
239 // Initialize keypad position |
|
240 mKeypad->setPos(mKeypadMovementStartingPoint); |
|
241 } |
|
242 return true; |
|
243 } |
|
244 } else { |
|
245 // It is going to be closed. |
|
246 mKeypadMovementVector = QPointF(0, mKeypad->size().height()); |
237 return true; |
247 return true; |
238 } |
248 } |
239 |
|
240 // Find out the editor bounding box and add a small margin to height. |
|
241 QRectF editorGeometry = mInputMethod->focusObject()->editorGeometry(); |
|
242 editorGeometry.adjust(0.0, -HbCursorLineMargin, 0.0, HbCursorLineMargin); |
|
243 |
|
244 // Then see if the editor is already inside the visible area. |
|
245 // If it isn't, see if it would fit there. |
|
246 if (!visibleArea.contains(editorGeometry)) { |
|
247 if (editorGeometry.width() <= visibleArea.width() && |
|
248 editorGeometry.height() <= visibleArea.height()) { |
|
249 // Yes, it fits into visible area, let's move it there so that |
|
250 // the whole editor area is in use right away. |
|
251 // First check if we want to move it to upper or lower |
|
252 // part of the visible area. |
|
253 if (editorGeometry.top() <= visibleArea.top()) { |
|
254 // It goes to the upper part of the visible area. |
|
255 mContainerMovementVector = QPointF(0.0, -editorGeometry.top()); |
|
256 } else { |
|
257 mContainerMovementVector = QPointF(0.0, visibleArea.bottom() - editorGeometry.bottom()); |
|
258 } |
|
259 |
|
260 return true; |
|
261 } |
|
262 } |
|
263 |
|
264 // The editor is either already inside the visible area or doesn't fit there. |
|
265 // Let's see if the cursor is visble. |
|
266 // First find out micro focus rectangle and increase the height by a small margin. |
|
267 QRectF microFocus = mInputMethod->focusObject()->microFocus(); |
|
268 microFocus.setTop(microFocus.top() - HbEditorExtraMargin); |
|
269 microFocus.setBottom(microFocus.bottom() + HbEditorExtraMargin); |
|
270 |
|
271 // Check whether the cursor rectangle is inside visible area. |
|
272 if (!visibleArea.contains(microFocus)) { |
|
273 QRectF realEditorGeometry = editorGeometry; |
|
274 realEditorGeometry.adjust(0.0, HbCursorLineMargin, 0.0, -HbCursorLineMargin); |
|
275 if (!realEditorGeometry.contains(microFocus)) { |
|
276 // A sanity check. If the microFocus rectangle is outside the editor |
|
277 // bounding rect, don't do anything. The situation in editor widget is not |
|
278 // up to date. |
|
279 return false; |
|
280 } |
|
281 // The cursor is outside the visible area. Figure out how much and |
|
282 // to which direction the container has to be moved. |
|
283 if (microFocus.bottom() <= visibleArea.top()) { |
|
284 // First see what would happen if we returned the container to original position. |
|
285 // Is the cursor visible then? |
|
286 // This is always preferred, use it if possible. |
|
287 QPointF toOriginalPos = mOriginalContainerPosition - mContainerWidget->pos(); |
|
288 QRectF translatedMicroFocus = microFocus.translated(toOriginalPos); |
|
289 if (visibleArea.contains(translatedMicroFocus)) { |
|
290 mContainerMovementVector = toOriginalPos; |
|
291 } else { |
|
292 // It goes to the upper part of the visible area. |
|
293 mContainerMovementVector = QPointF(0.0, HbCursorLineMargin - microFocus.top()); |
|
294 } |
|
295 } else { |
|
296 mContainerMovementVector = QPointF(0.0, visibleArea.bottom() - HbCursorLineMargin - microFocus.bottom()); |
|
297 } |
|
298 |
|
299 return true; |
|
300 } |
|
301 } else { |
|
302 // It is going to be closed or minimized. |
|
303 mContainerMovementVector = mOriginalContainerPosition - mContainerMovementStartingPoint; |
|
304 return true; |
|
305 } |
249 } |
306 |
250 |
307 return false; |
251 return false; |
308 } |
252 } |
309 |
253 |
310 bool HbAbstractVkbHostPrivate::prepareKeypadAnimation(HbVkbHost::HbVkbStatus status) |
254 /*! |
311 { |
255 \internal |
312 if (status == HbVkbHost::HbVkbStatusOpened) { |
256 Sets up all the animation effects. |
313 if (mKeypadStatus == HbVkbHost::HbVkbStatusClosed) { |
257 */ |
314 // Set up keyboard open animation. |
|
315 mKeypadMovementStartingPoint.setY(mScreenSize.height()); |
|
316 mKeypadMovementVector.setY(-mKeypad->size().height()); |
|
317 if (!disableCursorShift()) { |
|
318 // Initialize keypad position |
|
319 mKeypad->setPos(mKeypadMovementStartingPoint); |
|
320 } |
|
321 return true; |
|
322 } else if (mKeypadStatus == HbVkbHost::HbVkbStatusMinimized && mCallback) { |
|
323 mKeypadMovementVector.setY(-(mKeypad->size().height() - mCallback->minimizedKeyboardSize().height())); |
|
324 return true; |
|
325 } |
|
326 } else if (status == HbVkbHost::HbVkbStatusMinimized && mCallback) { |
|
327 mKeypadMovementVector = QPointF(0, mKeypad->size().height() - mCallback->minimizedKeyboardSize().height()); |
|
328 return true; |
|
329 } else { |
|
330 // It is going to be closed. |
|
331 mKeypadMovementVector = QPointF(0, mKeypad->size().height()); |
|
332 return true; |
|
333 } |
|
334 |
|
335 return false; |
|
336 } |
|
337 |
|
338 bool HbAbstractVkbHostPrivate::prepareAnimations(HbVkbHost::HbVkbStatus status) |
258 bool HbAbstractVkbHostPrivate::prepareAnimations(HbVkbHost::HbVkbStatus status) |
339 { |
259 { |
340 prepareAnimationsCommon(); |
260 prepareAnimationsCommon(); |
341 |
261 |
342 bool containerResult = prepareContainerAnimation(status); |
262 bool containerResult = prepareContainerAnimation(status); |
454 // Move the keypad |
382 // Move the keypad |
455 mKeypad->setPos(mKeypadMovementStartingPoint + mKeypadMovementVector); |
383 mKeypad->setPos(mKeypadMovementStartingPoint + mKeypadMovementVector); |
456 } |
384 } |
457 |
385 |
458 mKeypadStatus = HbVkbHost::HbVkbStatusOpened; |
386 mKeypadStatus = HbVkbHost::HbVkbStatusOpened; |
459 mCallback->keyboardOpened(q_ptr); |
387 if (mCallback) { |
460 } |
388 mCallback->keyboardOpened(q_ptr); |
461 } |
389 } |
462 } |
390 } |
463 |
391 } |
464 void HbAbstractVkbHostPrivate::openMinimizedKeypad() |
392 |
465 { |
393 ensureVisibilityInsideScrollArea(); |
466 // No need of any animation as this minimized keypad is very small to be a candidate for an |
394 ensureVisibilityInsideVisibleArea(); |
467 // animation. |
395 } |
468 HbMainWindow *mainWin = mainWindow(); |
396 |
469 if (mainWin && mKeypad && mContainerWidget->widgetObject()) { |
397 /*! |
470 if (mKeypad->scene() != mainWin->scene()) { |
398 \internal |
471 // Add item to scene if it is not already in there. |
399 Closes the keypad widget without animating it. |
472 mainWin->scene()->addItem(mKeypad); |
400 */ |
473 } |
|
474 |
|
475 if (mKeypadStatus != HbVkbHost::HbVkbStatusMinimized) { |
|
476 mCallback->aboutToOpen(q_ptr); |
|
477 q_ptr->resizeKeyboard(); // Make sure that the keyboard doesn't exceed given boundaries. |
|
478 } |
|
479 |
|
480 if (prepareAnimations(HbVkbHost::HbVkbStatusMinimized)) { |
|
481 if (!disableCursorShift()) { |
|
482 mKeypad->setPos(0.0, mScreenSize.height() - mCallback->minimizedKeyboardSize().height()); |
|
483 } |
|
484 mKeypadStatus = HbVkbHost::HbVkbStatusMinimized; |
|
485 mCallback->keyboardMinimized(q_ptr); |
|
486 } |
|
487 } |
|
488 } |
|
489 |
|
490 void HbAbstractVkbHostPrivate::closeKeypadWithoutAnimation() |
401 void HbAbstractVkbHostPrivate::closeKeypadWithoutAnimation() |
491 { |
402 { |
492 if (mKeypadStatus != HbVkbHost::HbVkbStatusClosed && mKeypad) { |
403 if (mKeypadStatus != HbVkbHost::HbVkbStatusClosed && mKeypad && mCallback) { |
493 mCallback->aboutToClose(q_ptr); |
404 mCallback->aboutToClose(q_ptr); |
|
405 |
494 // Set original content widget position |
406 // Set original content widget position |
495 mKeypadStatus = HbVkbHost::HbVkbStatusClosed; |
407 mKeypadStatus = HbVkbHost::HbVkbStatusClosed; |
496 |
408 |
497 if (!disableCursorShift()) { |
409 if (!disableCursorShift()) { |
498 // Return the container widget to original position. |
410 // Return the container widget to original position. |
499 mContainerWidget->setPos(mOriginalContainerPosition); |
411 mContainerWidget->setPos(mOriginalContainerPosition); |
500 mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false ); |
412 mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false); |
501 } |
413 } |
502 |
414 |
503 // Hide the keypad |
415 // Hide the keypad |
504 mKeypad->hide(); |
416 mKeypad->hide(); |
505 mCallback->keyboardClosed(q_ptr); |
417 mCallback->keyboardClosed(q_ptr); |
506 mCallback = 0; |
418 mCallback = 0; |
507 } |
419 } |
508 } |
420 } |
509 |
421 |
510 void HbAbstractVkbHostPrivate::minimizeKeypadWithoutAnimation() |
422 /*! |
511 { |
423 \internal |
512 HbMainWindow *mainWin = mainWindow(); |
424 Cancels the ongoing keypad animation and resets the timeline timer. |
513 if (mKeypadStatus != HbVkbHost::HbVkbStatusMinimized && mKeypad && mainWin) { |
425 */ |
514 mCallback->aboutToClose(q_ptr); |
|
515 if (mKeypad->scene() != mainWin->scene()) { |
|
516 // Add item to scene if it is not already in there. |
|
517 mainWin->scene()->addItem(mKeypad); |
|
518 } |
|
519 |
|
520 mKeypadStatus = HbVkbHost::HbVkbStatusMinimized; |
|
521 if (!disableCursorShift()) { |
|
522 // Return the container widget to original position. |
|
523 mContainerWidget->setPos(mOriginalContainerPosition); |
|
524 |
|
525 // Set the keypad to minimized position. |
|
526 mKeypad->setPos(QPointF(0.0, mScreenSize.height() - mCallback->minimizedKeyboardSize().height())); |
|
527 } |
|
528 } |
|
529 } |
|
530 |
|
531 void HbAbstractVkbHostPrivate::cancelAnimationAndHideVkbWidget() |
426 void HbAbstractVkbHostPrivate::cancelAnimationAndHideVkbWidget() |
532 { |
427 { |
533 if (mTimeLine.state() == QTimeLine::Running) { |
428 if (mTimeLine.state() == QTimeLine::Running) { |
534 mTimeLine.stop(); |
429 mTimeLine.stop(); |
535 |
430 |
536 if (!disableCursorShift()) { |
431 if (!disableCursorShift() && mContainerWidget && mContainerWidget->widgetObject()) { |
537 mContainerWidget->setPos(mOriginalContainerPosition); |
432 mContainerWidget->setPos(mOriginalContainerPosition); |
538 mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false ); |
433 mContainerWidget->widgetObject()->setProperty(KPositionManagedByVKB, false); |
539 } |
434 } |
540 |
435 |
541 if (mKeypad) { |
436 if (mKeypad) { |
542 mKeypad->hide(); |
437 mKeypad->hide(); |
543 } |
438 } |
605 return true; |
507 return true; |
606 } |
508 } |
607 return false; |
509 return false; |
608 } |
510 } |
609 |
511 |
610 |
512 /*! |
611 /// @endcond |
513 \internal |
612 |
514 Closes the keypad. This slot is connected to various signals from |
|
515 different container classes. |
|
516 */ |
|
517 void HbAbstractVkbHostPrivate::_q_containerAboutToClose() |
|
518 { |
|
519 Q_Q(HbAbstractVkbHost); |
|
520 q->closeKeypad(); |
|
521 } |
|
522 |
|
523 /*! |
|
524 \internal |
|
525 Finds out if given editor is inside a scroll area and makes sure the cursor position is visible inside the |
|
526 scroll area. |
|
527 */ |
|
528 void HbAbstractVkbHostPrivate::ensureVisibilityInsideScrollArea() const |
|
529 { |
|
530 if (mInputMethod && mInputMethod->focusObject()) { |
|
531 HbInputFocusObject *fo = mInputMethod->focusObject(); |
|
532 HbScrollArea *scrollArea = 0; |
|
533 |
|
534 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(fo->object()); |
|
535 if (graphicsObject) { |
|
536 for (QGraphicsWidget *parent = graphicsObject->parentWidget(); parent; parent = parent->parentWidget()) { |
|
537 scrollArea = qobject_cast<HbScrollArea*>(parent); |
|
538 if (scrollArea) { |
|
539 break; |
|
540 } |
|
541 } |
|
542 } |
|
543 |
|
544 if (scrollArea && scrollArea->contentWidget()) { |
|
545 QRectF scrollRect = scrollArea->sceneBoundingRect(); |
|
546 mScrollAreaRect = scrollRect; |
|
547 QRectF editorRect = fo->editorGeometry(); |
|
548 |
|
549 if (!scrollRect.contains(editorRect)) { |
|
550 // The editor is not visible inside a scroll area. |
|
551 // Calculate how much the area needs to be scrolled |
|
552 // to make the cursor line visible inside the scroll |
|
553 // area. The call scroll area's ensure visibility and |
|
554 // return the calculated value (it needs to be factored in |
|
555 // to container animation calculations). |
|
556 if (editorRect.height() < scrollRect.height()) { |
|
557 // Whole editor rect fits into scroll area. Move it there. |
|
558 if (editorRect.bottom() > scrollRect.bottom()) { |
|
559 // Scroll upwards. |
|
560 scrollArea->ensureVisible(scrollArea->contentWidget()->mapFromScene(editorRect.bottomLeft()), 0.0, mMarginInPixels); |
|
561 } else { |
|
562 // Scroll downwards. |
|
563 scrollArea->ensureVisible(scrollArea->contentWidget()->mapFromScene(editorRect.topLeft()), 0.0, mMarginInPixels); |
|
564 } |
|
565 } else { |
|
566 // Whole editor doesn't fit into scroll area. Used micro focus position instead. |
|
567 QRectF microFocus = fo->microFocus(); |
|
568 if (microFocus.bottom() > scrollRect.bottom()) { |
|
569 // Scroll upwards. |
|
570 scrollArea->ensureVisible(scrollArea->contentWidget()->mapFromScene(microFocus.bottomLeft()), 0.0, mMarginInPixels); |
|
571 } else { |
|
572 // Scroll downwards. |
|
573 scrollArea->ensureVisible(scrollArea->contentWidget()->mapFromScene(microFocus.topLeft()), 0.0, mMarginInPixels); |
|
574 } |
|
575 } |
|
576 } |
|
577 } |
|
578 } |
|
579 } |
|
580 |
|
581 /*! |
|
582 \internal |
|
583 Finds out if given editor is inside a scroll area and makes sure the cursor position is visible inside the |
|
584 visible area. |
|
585 */ |
|
586 void HbAbstractVkbHostPrivate::ensureVisibilityInsideVisibleArea() const |
|
587 { |
|
588 Q_Q(const HbAbstractVkbHost); |
|
589 if (mInputMethod && mInputMethod->focusObject()) { |
|
590 HbInputFocusObject *fo = mInputMethod->focusObject(); |
|
591 HbScrollArea *scrollArea = 0; |
|
592 |
|
593 QGraphicsObject *graphicsObject = qobject_cast<QGraphicsObject *>(fo->object()); |
|
594 if (graphicsObject) { |
|
595 for (QGraphicsWidget *parent = graphicsObject->parentWidget(); parent; parent = parent->parentWidget()) { |
|
596 scrollArea = qobject_cast<HbScrollArea*>(parent); |
|
597 if (scrollArea) { |
|
598 break; |
|
599 } |
|
600 } |
|
601 } |
|
602 |
|
603 if (scrollArea && scrollArea->contentWidget()) { |
|
604 QRectF editorRect = fo->editorGeometry(); |
|
605 QRectF visibleArea = q->applicationArea(); |
|
606 if (!visibleArea.isValid() && mContainerWidget) { |
|
607 visibleArea = mContainerWidget->sceneBoundingRect(); |
|
608 } |
|
609 |
|
610 if (!visibleArea.contains(editorRect)) { |
|
611 // Editor is inside scroll area but not on visible area so scroll it to be visible |
|
612 if (editorRect.bottom() > visibleArea.bottom()) { |
|
613 // Scroll upwards. |
|
614 QPointF point = QPointF(0.0, -scrollArea->contentWidget()->pos().y() + (editorRect.bottom() - visibleArea.bottom()) + mMarginInPixels); |
|
615 scrollArea->scrollContentsTo(point); |
|
616 } else { |
|
617 // Scroll downwards. |
|
618 QPointF point = QPointF(0.0, -scrollArea->contentWidget()->pos().y() + editorRect.y() - mMarginInPixels); |
|
619 scrollArea->scrollContentsTo(point); |
|
620 } |
|
621 } |
|
622 } |
|
623 } |
|
624 } |
|
625 |
|
626 /*! |
|
627 \internal |
|
628 Returns the editor bounding rect. If the editor is inside a scroll area, then we actually |
|
629 need to use the intersection of scroll area bounding rect and the editor rect in |
|
630 our calculations. |
|
631 */ |
|
632 QRectF HbAbstractVkbHostPrivate::findEditorRect(HbInputFocusObject* fo) const |
|
633 { |
|
634 if (fo) { |
|
635 QRectF editorRect = fo->editorGeometry(); |
|
636 if (!mScrollAreaRect.isEmpty()) { |
|
637 QRectF adjustedSrcollArea = mScrollAreaRect; |
|
638 // Cancel out the to-be-added margin |
|
639 adjustedSrcollArea.adjust(0, mMarginInPixels, 0, -mMarginInPixels); |
|
640 return editorRect.intersected(adjustedSrcollArea); |
|
641 } |
|
642 return editorRect; |
|
643 } |
|
644 |
|
645 return QRectF(); |
|
646 } |
|
647 |
|
648 /*! |
|
649 \internal |
|
650 Returns true if the container is a popup and it is still running its opening animation |
|
651 when the open keypad call comes in. |
|
652 */ |
|
653 bool HbAbstractVkbHostPrivate::popupAnimationInProgress() const |
|
654 { |
|
655 HbPopup *popup = qobject_cast<HbPopup *>(mContainerWidget->widgetObject()); |
|
656 if (popup) { |
|
657 HbPopupPrivate *popupPrivate = HbPopupPrivate::d_ptr(popup); |
|
658 return popupPrivate->showingInProgress; |
|
659 } |
|
660 |
|
661 return false; |
|
662 } |
|
663 |
|
664 /*! |
|
665 \internal |
|
666 From two given vector, returns the longest along the y-axis that points to the direction defined |
|
667 by v1. |
|
668 */ |
|
669 QPointF HbAbstractVkbHostPrivate::selectLongestVerticalVector(const QPointF &v1, const QPointF &v2) const |
|
670 { |
|
671 if (v1.y() * v2.y() < 0) { |
|
672 // They point to opposite directions. |
|
673 return v1; |
|
674 } |
|
675 |
|
676 if (qAbs(v2.y()) > qAbs(v1.y())) { |
|
677 // v2 is longer. |
|
678 return v2; |
|
679 } |
|
680 |
|
681 return v1; |
|
682 } |
613 |
683 |
614 HbAbstractVkbHost::HbAbstractVkbHost(HbWidget *containerWidget) : d_ptr(new HbAbstractVkbHostPrivate(this, containerWidget)) |
684 HbAbstractVkbHost::HbAbstractVkbHost(HbWidget *containerWidget) : d_ptr(new HbAbstractVkbHostPrivate(this, containerWidget)) |
615 { |
685 { |
616 Q_D(HbAbstractVkbHost); |
686 Q_D(HbAbstractVkbHost); |
617 |
687 |
618 setParent(containerWidget); |
688 setParent(containerWidget); |
619 HbVkbHost::attachHost(this, containerWidget); |
689 HbVkbHost::attachHost(this, containerWidget); |
|
690 if (containerWidget) { |
|
691 containerWidget->setFlag(QGraphicsItem::ItemSendsGeometryChanges); |
|
692 } |
620 |
693 |
621 connect(&d->mTimeLine, SIGNAL(finished()), this, SLOT(animationFinished())); |
694 connect(&d->mTimeLine, SIGNAL(finished()), this, SLOT(animationFinished())); |
622 connect(&d->mTimeLine, SIGNAL(valueChanged(qreal)), this, SLOT(animValueChanged(qreal))); |
695 connect(&d->mTimeLine, SIGNAL(valueChanged(qreal)), this, SLOT(animValueChanged(qreal))); |
623 } |
696 } |
624 |
697 |