|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (developer.feedback@nokia.com) |
|
6 ** |
|
7 ** This file is part of the HbPlugins module of the UI Extensions for Mobile. |
|
8 ** |
|
9 ** GNU Lesser General Public License Usage |
|
10 ** This file may be used under the terms of the GNU Lesser General Public |
|
11 ** License version 2.1 as published by the Free Software Foundation and |
|
12 ** appearing in the file LICENSE.LGPL included in the packaging of this file. |
|
13 ** Please review the following information to ensure the GNU Lesser General |
|
14 ** Public License version 2.1 requirements will be met: |
|
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
16 ** |
|
17 ** In addition, as a special exception, Nokia gives you certain additional |
|
18 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
20 ** |
|
21 ** If you have questions regarding the use of this file, please contact |
|
22 ** Nokia at developer.feedback@nokia.com. |
|
23 ** |
|
24 ****************************************************************************/ |
|
25 |
|
26 #include "hbnamespace_p.h" |
|
27 #include "hbfeedbackeffectutils.h" |
|
28 |
|
29 #include <hbtoolbutton.h> |
|
30 #include <hbabstractbutton.h> |
|
31 #include <hbabstractedit.h> |
|
32 #include <hbtextedit.h> |
|
33 #include <hblineedit.h> |
|
34 #include <hbabstractslidercontrol.h> |
|
35 #include <hbprogressslider.h> |
|
36 #include <hbscrollbar.h> |
|
37 #include <hbabstractviewitem.h> |
|
38 #include <hbabstractitemview.h> |
|
39 #include <hbgridview.h> |
|
40 #include <hbgridviewitem.h> |
|
41 #include <hblistview.h> |
|
42 #include <hbtreeview.h> |
|
43 #include <hbtreeviewitem.h> |
|
44 #include <hbdataformviewitem.h> |
|
45 #include <hbpopup.h> |
|
46 #include <hbmenu.h> |
|
47 #include <hbview.h> |
|
48 #include <hbmainwindow.h> |
|
49 #include <QGraphicsScene> |
|
50 #include <QPointF> |
|
51 #include <QRectF> |
|
52 |
|
53 const int continuousSliderStepLimit = 15; |
|
54 |
|
55 #define IF_INSTANCEOF_SET_FAMILY(className, widgetFamily) \ |
|
56 if (qobject_cast<const className *>(widget)) \ |
|
57 { \ |
|
58 family = HbFeedbackEffectUtils::widgetFamily; \ |
|
59 } |
|
60 |
|
61 /*! |
|
62 Finds out the graphics item type of the parent widget. |
|
63 */ |
|
64 int HbFeedbackEffectUtils::parentItemType(const HbWidget *widget) |
|
65 { |
|
66 int graphicsItemType = 0; |
|
67 if (const HbWidget *parent = dynamic_cast<const HbWidget *>(widget->parentItem())) { |
|
68 graphicsItemType = parent->type(); |
|
69 } |
|
70 return graphicsItemType; |
|
71 } |
|
72 |
|
73 /*! |
|
74 Returns the widget family for a widget. |
|
75 */ |
|
76 HbFeedbackEffectUtils::WidgetFamily HbFeedbackEffectUtils::widgetFamily(const HbWidget *widget) |
|
77 { |
|
78 HbFeedbackEffectUtils::WidgetFamily family = Undefined; |
|
79 switch(widget->type()) { |
|
80 |
|
81 case Hb::ItemType_AbstractButton: |
|
82 |
|
83 case Hb::ItemType_PushButton: |
|
84 |
|
85 case Hb::ItemType_ToolButton: |
|
86 |
|
87 case Hb::ItemType_CheckBox: |
|
88 |
|
89 case HbPrivate::ItemType_SliderElement: |
|
90 |
|
91 case HbPrivate::ItemType_IndicatorGroup: |
|
92 |
|
93 case HbPrivate::ItemType_TitlePane: |
|
94 |
|
95 case Hb::ItemType_InputCharacterButton: |
|
96 |
|
97 case Hb::ItemType_InputFunctionButton: |
|
98 |
|
99 case Hb::ItemType_ComboBox: |
|
100 |
|
101 family = HbFeedbackEffectUtils::Button; |
|
102 break; |
|
103 |
|
104 case Hb::ItemType_MenuItem: |
|
105 |
|
106 case Hb::ItemType_FormViewItem: |
|
107 |
|
108 case Hb::ItemType_FormView: |
|
109 |
|
110 case Hb::ItemType_AbstractItemContainer: |
|
111 |
|
112 case Hb::ItemType_AbstractItemView: |
|
113 |
|
114 case Hb::ItemType_ListView: |
|
115 |
|
116 case Hb::ItemType_AbstractViewItem: |
|
117 |
|
118 case Hb::ItemType_ListViewItem: |
|
119 |
|
120 case Hb::ItemType_ItemHighlight: |
|
121 |
|
122 case Hb::ItemType_ListWidgetItem: |
|
123 |
|
124 case Hb::ItemType_ListWidgetViewItem: |
|
125 |
|
126 case Hb::ItemType_RadioButtonList: |
|
127 |
|
128 case Hb::ItemType_RoundRobinLabel: |
|
129 |
|
130 case Hb::ItemType_CarouselView: |
|
131 |
|
132 case HbPrivate::ItemType_MenuListView: |
|
133 |
|
134 case HbPrivate::ItemType_GroupBoxHeadingWidget: |
|
135 |
|
136 family = HbFeedbackEffectUtils::List; |
|
137 IF_INSTANCEOF_SET_FAMILY(HbGridView, Grid) |
|
138 break; |
|
139 |
|
140 case Hb::ItemType_GridViewItem: |
|
141 family = HbFeedbackEffectUtils::Grid; |
|
142 break; |
|
143 |
|
144 case Hb::ItemType_AbstractSlider: |
|
145 |
|
146 case Hb::ItemType_Slider: |
|
147 |
|
148 case HbPrivate::ItemType_SliderControl: |
|
149 |
|
150 case HbPrivate::ItemType_SliderHandle: |
|
151 |
|
152 case HbPrivate::ItemType_SliderTickmarks: |
|
153 |
|
154 case HbPrivate::ItemType_ZoomSlider: |
|
155 |
|
156 case HbPrivate::ItemType_VolumeSlider: |
|
157 |
|
158 case Hb::ItemType_ProgressBar: |
|
159 |
|
160 case Hb::ItemType_ProgressSlider: |
|
161 |
|
162 case HbPrivate::ItemType_ProgressSliderHandle: |
|
163 |
|
164 case Hb::ItemType_ScrollBar: |
|
165 |
|
166 family = HbFeedbackEffectUtils::Slider; |
|
167 break; |
|
168 |
|
169 case Hb::ItemType_Menu: |
|
170 |
|
171 case HbPrivate::ItemType_IndicatorMenu: |
|
172 |
|
173 case Hb::ItemType_Popup: |
|
174 |
|
175 case Hb::ItemType_ToolBarExtension: |
|
176 |
|
177 case HbPrivate::ItemType_ToolTipLabel: |
|
178 |
|
179 case Hb::ItemType_InputVkbWidget: |
|
180 |
|
181 case Hb::ItemType_ColorDialog: |
|
182 |
|
183 family = HbFeedbackEffectUtils::Popup; |
|
184 break; |
|
185 |
|
186 case Hb::ItemType_LineEdit: |
|
187 |
|
188 case Hb::ItemType_TextEdit: |
|
189 |
|
190 case Hb::ItemType_AbstractEdit: |
|
191 |
|
192 case Hb::ItemType_VirtualTrackPoint: |
|
193 |
|
194 case Hb::ItemType_WritingBox: |
|
195 |
|
196 family = HbFeedbackEffectUtils::Editor; |
|
197 break; |
|
198 |
|
199 default: |
|
200 break; |
|
201 } |
|
202 |
|
203 // fallback if item type cannot be found |
|
204 if (family == HbFeedbackEffectUtils::Undefined) { |
|
205 IF_INSTANCEOF_SET_FAMILY(HbAbstractButton, Button) |
|
206 IF_INSTANCEOF_SET_FAMILY(HbAbstractEdit, Editor) |
|
207 IF_INSTANCEOF_SET_FAMILY(HbAbstractSliderControl, Slider) |
|
208 IF_INSTANCEOF_SET_FAMILY(HbPopup, Popup) |
|
209 IF_INSTANCEOF_SET_FAMILY(HbAbstractItemView, List) |
|
210 IF_INSTANCEOF_SET_FAMILY(HbAbstractViewItem, List) |
|
211 IF_INSTANCEOF_SET_FAMILY(HbGridView, Grid) |
|
212 IF_INSTANCEOF_SET_FAMILY(HbGridViewItem, Grid) |
|
213 } |
|
214 return family; |
|
215 } |
|
216 |
|
217 /*! |
|
218 Returns the instant feedback effect on press interaction. |
|
219 */ |
|
220 HbFeedback::InstantEffect HbFeedbackEffectUtils::instantOnPress(const HbWidget *widget, Hb::InteractionModifiers modifiers) |
|
221 { |
|
222 HbFeedback::InstantEffect effect = HbFeedback::Sensitive; |
|
223 |
|
224 switch (widgetFamily(widget)) { |
|
225 |
|
226 case HbFeedbackEffectUtils::Undefined: |
|
227 effect = HbFeedback::None; |
|
228 break; |
|
229 |
|
230 case HbFeedbackEffectUtils::Button: |
|
231 effect = HbFeedback::SensitiveButton; |
|
232 |
|
233 // latched down button special case (isChecked information required) |
|
234 if (const HbAbstractButton* button = qobject_cast<const HbAbstractButton *>(widget)) { |
|
235 if (button->type() == Hb::ItemType_PushButton) { |
|
236 // toggleable push button |
|
237 if (button->isCheckable()) { |
|
238 if (button->isChecked()) { |
|
239 effect = HbFeedback::SensitiveButton; |
|
240 } else { |
|
241 effect = HbFeedback::BasicButton; |
|
242 } |
|
243 // normal push button |
|
244 } else { |
|
245 effect = HbFeedback::BasicButton; |
|
246 } |
|
247 } |
|
248 } |
|
249 |
|
250 if (widget->type() == HbPrivate::ItemType_NavigationButton || |
|
251 widget->type() == HbPrivate::ItemType_IndicatorButton) { |
|
252 effect = HbFeedback::BasicButton; |
|
253 } |
|
254 |
|
255 // input widget special case |
|
256 if (widget->type() == Hb::ItemType_InputCharacterButton) { |
|
257 effect = HbFeedback::SensitiveKeypad; |
|
258 } |
|
259 else if (widget->type() == Hb::ItemType_InputFunctionButton) { |
|
260 effect = HbFeedback::BasicKeypad; |
|
261 } |
|
262 else if (widget->type() == Hb::ItemType_CheckBox) { |
|
263 effect = HbFeedback::None; // Checkbox deferred to release |
|
264 } |
|
265 |
|
266 // title pane specific special case |
|
267 if (widget->type() == HbPrivate::ItemType_TitlePane) { |
|
268 if (isOptionsMenuEmpty(widget)) { |
|
269 effect = HbFeedback::None; |
|
270 } |
|
271 } |
|
272 break; |
|
273 |
|
274 case HbFeedbackEffectUtils::List: |
|
275 if (modifiers & Hb::ModifierCollapsedItem) { |
|
276 effect = HbFeedback::BasicItem; |
|
277 } |
|
278 else { |
|
279 effect = HbFeedback::SensitiveItem; |
|
280 } |
|
281 break; |
|
282 |
|
283 case HbFeedbackEffectUtils::Grid: |
|
284 effect = HbFeedback::SensitiveItem; |
|
285 break; |
|
286 |
|
287 case HbFeedbackEffectUtils::Slider: |
|
288 |
|
289 // slider area |
|
290 effect = HbFeedback::None; |
|
291 if (const HbProgressSlider *progressSlider = qobject_cast<const HbProgressSlider *>(widget)) { |
|
292 Q_UNUSED(progressSlider) |
|
293 effect = HbFeedback::BasicSlider; |
|
294 } else if (const HbScrollBar *scrollBar = qobject_cast<const HbScrollBar *>(widget)) { |
|
295 Q_UNUSED(scrollBar) |
|
296 effect = HbFeedback::SensitiveSlider; |
|
297 } |
|
298 |
|
299 // slider handle |
|
300 if (modifiers & Hb::ModifierSliderHandle) { |
|
301 effect = HbFeedback::SensitiveSlider; |
|
302 } |
|
303 |
|
304 // slider elements |
|
305 if (modifiers & Hb::ModifierSliderElement) { |
|
306 effect = HbFeedback::SensitiveButton; |
|
307 } |
|
308 break; |
|
309 |
|
310 case HbFeedbackEffectUtils::Popup: |
|
311 |
|
312 if (widget->type() == Hb::ItemType_InputVkbWidget) { |
|
313 effect = HbFeedback::SensitiveButton; |
|
314 } |
|
315 else { |
|
316 effect = HbFeedback::None; |
|
317 } |
|
318 break; |
|
319 |
|
320 case HbFeedbackEffectUtils::Editor: |
|
321 effect = HbFeedback::Editor; |
|
322 break; |
|
323 |
|
324 default: |
|
325 break; |
|
326 } |
|
327 |
|
328 if (widget->type() == Hb::ItemType_MenuItem) { |
|
329 if (modifiers & Hb::ModifierScrolling) { |
|
330 effect = HbFeedback::StopFlick; |
|
331 } |
|
332 } |
|
333 // item view specific special cases |
|
334 if ( const HbAbstractViewItem * viewItem = qobject_cast<const HbAbstractViewItem *>(widget)) { |
|
335 const HbAbstractItemView* itemView = viewItem->itemView(); |
|
336 if (itemView) { |
|
337 // checkable item is checked with a press |
|
338 switch (itemView->selectionMode()) { |
|
339 case HbAbstractItemView::SingleSelection: |
|
340 case HbAbstractItemView::MultiSelection: |
|
341 case HbAbstractItemView::ContiguousSelection: { |
|
342 effect = HbFeedback::None; |
|
343 break; |
|
344 } |
|
345 case HbAbstractItemView::NoSelection: |
|
346 if (const HbListView * listView = qobject_cast<const HbListView *>(itemView)) { |
|
347 if (listView->arrangeMode() |
|
348 && !(modifiers & Hb::ModifierScrolling)) { |
|
349 effect = HbFeedback::ItemPick; |
|
350 } |
|
351 } |
|
352 break; |
|
353 default: |
|
354 break; |
|
355 } |
|
356 |
|
357 // radio button list works like a normal list item |
|
358 if (viewItem->type() == Hb::ItemType_RadioButtonListViewItem) { |
|
359 effect = HbFeedback::SensitiveItem; |
|
360 } |
|
361 else if(viewItem->type() == Hb::ItemType_TumbleViewItem ) { |
|
362 effect = HbFeedback::SensitiveItem; |
|
363 } |
|
364 |
|
365 // expandable or collapsable items give a BasicItem feedback |
|
366 if (const HbTreeViewItem* treeItem = qobject_cast<const HbTreeViewItem *>(widget)) { |
|
367 if (itemView->model()->rowCount(treeItem->modelIndex()) > 0) { |
|
368 effect = HbFeedback::BasicItem; |
|
369 } |
|
370 else { |
|
371 effect = HbFeedback::SensitiveItem; |
|
372 } |
|
373 } |
|
374 |
|
375 // Expandable or collapsible data form item gives BasicItem feedback |
|
376 if (const HbDataFormViewItem* dataFormItem = qobject_cast<const HbDataFormViewItem *>(widget)) { |
|
377 if (itemView->model()->rowCount(dataFormItem->modelIndex()) > 0) { |
|
378 effect = HbFeedback::BasicItem; |
|
379 } |
|
380 else { |
|
381 effect = HbFeedback::SensitiveItem; |
|
382 } |
|
383 } |
|
384 |
|
385 if (modifiers & Hb::ModifierScrolling) { |
|
386 effect = HbFeedback::StopFlick; |
|
387 } |
|
388 } |
|
389 } |
|
390 if (widget->type() == Hb::ItemType_VirtualTrackPoint) { |
|
391 effect = HbFeedback::Editor; |
|
392 } |
|
393 |
|
394 return effect; |
|
395 } |
|
396 |
|
397 /*! |
|
398 Returns the instant feedback effect on release interaction. |
|
399 */ |
|
400 HbFeedback::InstantEffect HbFeedbackEffectUtils::instantOnRelease(const HbWidget *widget, Hb::InteractionModifiers modifiers) |
|
401 { |
|
402 // mostly the same as when the widget is pressed |
|
403 HbFeedback::InstantEffect effect = instantOnPress(widget, modifiers); |
|
404 |
|
405 // clicking on a sub menu item, indicator group or title pane causes release feedback |
|
406 // even if all of those widgets open a new menu popup, which initiates IncreasingPopUp |
|
407 switch (widgetFamily(widget)) { |
|
408 |
|
409 case HbFeedbackEffectUtils::Undefined: |
|
410 effect = HbFeedback::None; |
|
411 break; |
|
412 |
|
413 case HbFeedbackEffectUtils::Button: |
|
414 effect = HbFeedback::SensitiveButton; |
|
415 |
|
416 // latched down button special case (isChecked information required) |
|
417 if (const HbAbstractButton* button = qobject_cast<const HbAbstractButton *>(widget)) { |
|
418 if (button->type() == Hb::ItemType_PushButton) { |
|
419 // toggleable push button |
|
420 if (button->isCheckable()) { |
|
421 if (button->isChecked()) { |
|
422 effect = HbFeedback::BasicButton; |
|
423 } else { |
|
424 effect = HbFeedback::None; |
|
425 } |
|
426 // normal push button |
|
427 } else { |
|
428 effect = HbFeedback::BasicButton; |
|
429 } |
|
430 } |
|
431 } |
|
432 |
|
433 if (widget->type() == HbPrivate::ItemType_NavigationButton || |
|
434 widget->type() == HbPrivate::ItemType_IndicatorButton) { |
|
435 effect = HbFeedback::BasicButton; |
|
436 } |
|
437 |
|
438 // input widget special case |
|
439 if (widget->type() == Hb::ItemType_InputCharacterButton |
|
440 || widget->type() == Hb::ItemType_InputFunctionButton) { |
|
441 effect = HbFeedback::SensitiveKeypad; |
|
442 } else if (widget->type() == Hb::ItemType_CheckBox) { |
|
443 effect = HbFeedback::Checkbox; // deferred from press |
|
444 } |
|
445 |
|
446 // title pane specific special case |
|
447 if (widget->type() == HbPrivate::ItemType_TitlePane) { |
|
448 if (isOptionsMenuEmpty(widget)) { |
|
449 effect = HbFeedback::None; |
|
450 } |
|
451 } |
|
452 |
|
453 if (widget->type() == Hb::ItemType_ComboBox) { |
|
454 effect = HbFeedback::PopupOpen; |
|
455 } |
|
456 |
|
457 break; |
|
458 |
|
459 case HbFeedbackEffectUtils::List: |
|
460 if (modifiers & Hb::ModifierCollapsedItem) { |
|
461 effect = HbFeedback::BasicItem; |
|
462 } |
|
463 else { |
|
464 effect = HbFeedback::SensitiveItem; |
|
465 } |
|
466 // menu items give popop closed feedback on release |
|
467 if (widget->type() == Hb::ItemType_MenuItem) { |
|
468 effect = HbFeedback::None; |
|
469 } |
|
470 break; |
|
471 |
|
472 case HbFeedbackEffectUtils::Grid: |
|
473 effect = HbFeedback::SensitiveItem; |
|
474 break; |
|
475 |
|
476 case HbFeedbackEffectUtils::Slider: |
|
477 |
|
478 // slider area |
|
479 effect = HbFeedback::None; |
|
480 |
|
481 // slider handle |
|
482 if (modifiers & Hb::ModifierSliderHandle) { |
|
483 effect = HbFeedback::SensitiveSlider; |
|
484 } |
|
485 |
|
486 // slider elements |
|
487 if (modifiers & Hb::ModifierSliderElement) { |
|
488 effect = HbFeedback::SensitiveButton; |
|
489 } |
|
490 break; |
|
491 |
|
492 case HbFeedbackEffectUtils::Editor: |
|
493 effect = HbFeedback::None; |
|
494 break; |
|
495 |
|
496 default: |
|
497 break; |
|
498 } |
|
499 |
|
500 // item view specific special cases |
|
501 if ( const HbAbstractViewItem * viewItem = qobject_cast<const HbAbstractViewItem *>(widget)) { |
|
502 const HbAbstractItemView* itemView = viewItem->itemView(); |
|
503 if (itemView) { |
|
504 switch (itemView->selectionMode()) { |
|
505 case HbAbstractItemView::SingleSelection: |
|
506 effect = HbFeedback::Checkbox; // deferred from press |
|
507 break; |
|
508 case HbAbstractItemView::MultiSelection: |
|
509 case HbAbstractItemView::ContiguousSelection: { |
|
510 effect = HbFeedback::None; |
|
511 break; |
|
512 } |
|
513 |
|
514 case HbAbstractItemView::NoSelection: |
|
515 if (const HbListView * listView = qobject_cast<const HbListView *>(itemView)) { |
|
516 if (listView->arrangeMode()) { |
|
517 if(modifiers & Hb::ModifierScrolling) { |
|
518 effect = HbFeedback::None; |
|
519 } |
|
520 else { |
|
521 effect = HbFeedback::ItemDrop; |
|
522 } |
|
523 } |
|
524 } |
|
525 default: { |
|
526 |
|
527 break; |
|
528 } |
|
529 } |
|
530 |
|
531 // radio button list works like a normal list item |
|
532 if (viewItem->type() == Hb::ItemType_RadioButtonListViewItem) { |
|
533 effect = HbFeedback::SensitiveItem; |
|
534 } |
|
535 else if(viewItem->type() == Hb::ItemType_TumbleViewItem ) { |
|
536 effect = HbFeedback::SensitiveItem; |
|
537 } |
|
538 |
|
539 if (modifiers & Hb::ModifierExpandedItem || modifiers & Hb::ModifierCollapsedItem) { |
|
540 effect = HbFeedback::BasicItem; |
|
541 } |
|
542 } |
|
543 } |
|
544 return effect; |
|
545 } |
|
546 |
|
547 /*! |
|
548 Returns the instant feedback effect on key repeat interaction. |
|
549 */ |
|
550 HbFeedback::InstantEffect HbFeedbackEffectUtils::instantOnKeyRepeat(const HbWidget *widget) |
|
551 { |
|
552 HbFeedback::InstantEffect effect = HbFeedback::Sensitive; |
|
553 |
|
554 // rule of thumb: key repeats cause sensitive version of the feedback effect |
|
555 switch (widgetFamily(widget)) { |
|
556 |
|
557 case HbFeedbackEffectUtils::Undefined: |
|
558 effect = HbFeedback::None; |
|
559 break; |
|
560 |
|
561 case HbFeedbackEffectUtils::Button: |
|
562 effect = HbFeedback::SensitiveButton; |
|
563 |
|
564 // input widget special case |
|
565 if (widget->type() == Hb::ItemType_InputCharacterButton |
|
566 || widget->type() == Hb::ItemType_InputFunctionButton) { |
|
567 effect = HbFeedback::SensitiveKeypad; |
|
568 } |
|
569 break; |
|
570 |
|
571 case HbFeedbackEffectUtils::List: |
|
572 effect = HbFeedback::SensitiveItem; |
|
573 break; |
|
574 |
|
575 case HbFeedbackEffectUtils::Grid: |
|
576 effect = HbFeedback::SensitiveItem; |
|
577 break; |
|
578 |
|
579 case HbFeedbackEffectUtils::Slider: |
|
580 effect = HbFeedback::SensitiveSlider; |
|
581 break; |
|
582 |
|
583 case HbFeedbackEffectUtils::Tab: |
|
584 |
|
585 case HbFeedbackEffectUtils::Popup: |
|
586 |
|
587 case HbFeedbackEffectUtils::Editor: |
|
588 effect = HbFeedback::None; |
|
589 break; |
|
590 |
|
591 default: |
|
592 break; |
|
593 } |
|
594 |
|
595 |
|
596 return effect; |
|
597 } |
|
598 |
|
599 /*! |
|
600 Returns the instant feedback effect on drag interaction. |
|
601 */ |
|
602 HbFeedback::InstantEffect HbFeedbackEffectUtils::instantOnDrag(const HbWidget *widget, Hb::InteractionModifiers modifiers) |
|
603 { |
|
604 // mostly the same as when the widget is pressed |
|
605 HbFeedback::InstantEffect effect = instantOnPress(widget, modifiers); |
|
606 |
|
607 if (const HbAbstractViewItem * viewItem = qobject_cast<const HbAbstractViewItem *>(widget)) { |
|
608 const HbAbstractItemView* itemView = viewItem->itemView(); |
|
609 if (itemView) { |
|
610 if (itemView->selectionMode() == HbAbstractItemView::ContiguousSelection) { |
|
611 effect = HbFeedback::MultipleCheckbox; |
|
612 } |
|
613 else if (const HbListView * listView = qobject_cast<const HbListView *>(itemView)) { |
|
614 if (listView->arrangeMode()) { |
|
615 effect = HbFeedback::ItemMoveOver; |
|
616 } |
|
617 } |
|
618 } |
|
619 } |
|
620 if (widget->type() == Hb::ItemType_VirtualTrackPoint) { |
|
621 effect = HbFeedback::Editor; |
|
622 } |
|
623 if (widget->type() == Hb::ItemType_Menu) { |
|
624 effect = HbFeedback::ItemScroll; |
|
625 } |
|
626 return effect; |
|
627 } |
|
628 |
|
629 /*! |
|
630 Returns the instant feedback effect on editor highlighting. |
|
631 */ |
|
632 HbFeedback::InstantEffect HbFeedbackEffectUtils::instantOnEditorHighlight(const HbWidget *widget, int previousCursorPosition) |
|
633 { |
|
634 HbFeedback::InstantEffect effect = HbFeedback::None; |
|
635 int dist = 0; |
|
636 bool emptyline = false; |
|
637 |
|
638 if (const HbTextEdit* textEdit = qobject_cast<const HbTextEdit*>(widget)) { |
|
639 |
|
640 int index = textEdit->cursorPosition(); |
|
641 QTextDocument* text = textEdit->document(); |
|
642 |
|
643 if (text->characterCount() > 0 && index < text->characterCount()) { |
|
644 dist = abs(index - previousCursorPosition); |
|
645 |
|
646 if (previousCursorPosition < index) { |
|
647 index--; |
|
648 } |
|
649 emptyline = text->characterAt(index).category() == QChar::Separator_Paragraph; |
|
650 QChar character = text->characterAt(index); |
|
651 |
|
652 if (emptyline) { |
|
653 effect = HbFeedback::EmptyLineSelection; |
|
654 } |
|
655 else if (dist > 1) { |
|
656 effect = HbFeedback::LineSelection; |
|
657 } |
|
658 else if (character.isSpace()) { |
|
659 effect = HbFeedback::BlankSelection; |
|
660 } |
|
661 else { |
|
662 effect = HbFeedback::TextSelection; |
|
663 } |
|
664 } |
|
665 } |
|
666 else if (const HbLineEdit* lineEdit = qobject_cast<const HbLineEdit*>(widget)) { |
|
667 |
|
668 int index = lineEdit->cursorPosition(); |
|
669 QString text = lineEdit->text(); |
|
670 |
|
671 if (!text.isEmpty() && index < text.count()) { |
|
672 if (previousCursorPosition < index) { |
|
673 index--; |
|
674 } |
|
675 QChar character = text.at(index); |
|
676 |
|
677 if (character.isSpace()) { |
|
678 effect = HbFeedback::BlankSelection; |
|
679 } |
|
680 else { |
|
681 effect = HbFeedback::TextSelection; |
|
682 } |
|
683 } |
|
684 } |
|
685 return effect; |
|
686 } |
|
687 |
|
688 /*! |
|
689 Checks if feedback is allowed for certain types of popup widgets. |
|
690 */ |
|
691 bool HbFeedbackEffectUtils::isFeedbackAllowedForPopup(const HbWidget *widget) |
|
692 { |
|
693 bool feedbackAllowed(false); |
|
694 if (widgetFamily(widget) == HbFeedbackEffectUtils::Popup) { |
|
695 feedbackAllowed = true; |
|
696 if (widget->type() == HbPrivate::ItemType_ToolTipLabel |
|
697 || widget->type() == Hb::ItemType_InputCharPreviewPane |
|
698 || widget->type() == Hb::ItemType_InputVkbWidget) { |
|
699 feedbackAllowed = false; |
|
700 } |
|
701 else if (QString(widget->metaObject()->className()) == "HbSelectionControl") { |
|
702 feedbackAllowed = false; |
|
703 } |
|
704 } |
|
705 return feedbackAllowed; |
|
706 } |
|
707 |
|
708 /*! |
|
709 Returns the instant feedback effect on key press interaction. |
|
710 */ |
|
711 HbFeedback::InstantEffect HbFeedbackEffectUtils::instantOnKeyPress(const HbWidget *widget, Hb::InteractionModifiers modifiers) |
|
712 { |
|
713 // mostly the same as when the widget is pressed |
|
714 return instantOnPress(widget, modifiers); |
|
715 } |
|
716 |
|
717 /*! |
|
718 Returns the instant feedback effect on selection changed events. |
|
719 */ |
|
720 HbFeedback::InstantEffect HbFeedbackEffectUtils::instantOnSelectionChanged(const HbWidget *widget) |
|
721 { |
|
722 HbFeedback::InstantEffect effect = HbFeedback::None; |
|
723 |
|
724 if ( const HbAbstractViewItem * viewItem = qobject_cast<const HbAbstractViewItem *>(widget)) { |
|
725 const HbAbstractItemView* itemView = viewItem->itemView(); |
|
726 if (itemView) { |
|
727 switch (itemView->selectionMode()) { |
|
728 case HbAbstractItemView::SingleSelection: { |
|
729 // Single selection is handled with a release |
|
730 effect = HbFeedback::None; |
|
731 break; |
|
732 } |
|
733 case HbAbstractItemView::MultiSelection: { |
|
734 effect = HbFeedback::Checkbox; |
|
735 break; |
|
736 } |
|
737 case HbAbstractItemView::ContiguousSelection: { |
|
738 effect = HbFeedback::MultipleCheckbox; |
|
739 break; |
|
740 } |
|
741 default: |
|
742 break; |
|
743 } |
|
744 } |
|
745 } |
|
746 |
|
747 return effect; |
|
748 } |
|
749 |
|
750 /*! |
|
751 Returns the instant continuous feedback effect for a continuous interaction. |
|
752 */ |
|
753 HbFeedback::ContinuousEffect HbFeedbackEffectUtils::continuousEffect(const HbWidget *widget, Hb::ContinuousInteraction interaction) |
|
754 { |
|
755 HbFeedback::ContinuousEffect effect = HbFeedback::ContinuousSmooth; |
|
756 |
|
757 switch (widgetFamily(widget)) { |
|
758 |
|
759 case HbFeedbackEffectUtils::Undefined: |
|
760 effect = HbFeedback::ContinuousNone; |
|
761 break; |
|
762 |
|
763 case HbFeedbackEffectUtils::Slider: |
|
764 effect = HbFeedback::ContinuousSlider; |
|
765 break; |
|
766 |
|
767 default: |
|
768 break; |
|
769 |
|
770 } |
|
771 |
|
772 if (interaction == Hb::ContinuousPinched) { |
|
773 effect = HbFeedback::ContinuousPinch; |
|
774 } |
|
775 else if (interaction == Hb::ContinuousRotated) { |
|
776 effect = HbFeedback::ContinuousSmooth; |
|
777 } |
|
778 |
|
779 return effect; |
|
780 } |
|
781 |
|
782 /*! |
|
783 Returns the intensity of the feedback for a continuous interaction. |
|
784 */ |
|
785 int HbFeedbackEffectUtils::intensity(const HbWidget *widget, Hb::ContinuousInteraction interaction, QPointF delta) |
|
786 { |
|
787 Q_UNUSED(interaction); |
|
788 int intensity = HbFeedback::IntensitySmooth; |
|
789 if (const HbAbstractSliderControl *slider = qobject_cast<const HbAbstractSliderControl *>(widget)) { |
|
790 switch(parentItemType(slider)) { |
|
791 case HbPrivate::ItemType_ZoomSlider: |
|
792 |
|
793 case HbPrivate::ItemType_VolumeSlider: |
|
794 { |
|
795 qreal min = slider->minimum(); |
|
796 qreal max = slider->maximum(); |
|
797 qreal pos = slider->sliderPosition(); |
|
798 qreal sliderRange = max - min; |
|
799 qreal relativePos = pos - min; |
|
800 intensity = int((qreal)(HbFeedback::IntensityFull) * (qreal)(relativePos) / (qreal)(sliderRange)); |
|
801 break; |
|
802 } |
|
803 default: |
|
804 break; |
|
805 } |
|
806 } else if (const HbProgressSlider *progressbar = qobject_cast<const HbProgressSlider *>(widget)) { |
|
807 Q_UNUSED(progressbar); |
|
808 intensity = HbFeedback::IntensitySmooth; |
|
809 } else if (const HbScrollBar *scrollbar = qobject_cast<const HbScrollBar *>(widget)) { |
|
810 Q_UNUSED(scrollbar); |
|
811 intensity = HbFeedback::IntensitySmooth; |
|
812 } else if (const HbGridView *gridView = qobject_cast<const HbGridView *>(widget)) { |
|
813 Q_UNUSED(gridView); |
|
814 intensity = HbFeedback::IntensitySmooth; |
|
815 } else if (widget->type() == Hb::ItemType_VirtualTrackPoint) { |
|
816 intensity = HbFeedback::IntensityFull; |
|
817 } else if (widget->type() == Hb::ItemType_WritingBox) { |
|
818 intensity = HbFeedback::IntensitySmooth; |
|
819 } else { |
|
820 intensity = int((abs(25*HbFeedback::IntensityFull*delta.toPoint().y()) / widget->rect().height()) + (abs(25*HbFeedback::IntensityFull*delta.toPoint().x()) / widget->rect().width())); |
|
821 |
|
822 if (intensity > HbFeedback::IntensityFull) { |
|
823 intensity = HbFeedback::IntensityFull; |
|
824 } |
|
825 } |
|
826 |
|
827 if (interaction == Hb::ContinuousRotated) { |
|
828 intensity = HbFeedback::IntensitySmooth; |
|
829 } |
|
830 |
|
831 return intensity; |
|
832 } |
|
833 |
|
834 /*! |
|
835 Checks if the feedback is allowed. |
|
836 */ |
|
837 bool HbFeedbackEffectUtils::isFeedbackAllowed(const HbWidget* widget) |
|
838 { |
|
839 // either widget is already visible or a popup about to be visible |
|
840 bool widgetVisible = widget && widget->isEnabled() && widget->isVisible() && widget->scene(); |
|
841 bool popupAboutToBeVisible = widget && widget->isEnabled() && qobject_cast<const HbPopup*>(widget); |
|
842 return widgetVisible || popupAboutToBeVisible; |
|
843 } |
|
844 |
|
845 /*! |
|
846 Decides if the feedback regarding sliders should be continuous or instant. |
|
847 */ |
|
848 bool HbFeedbackEffectUtils::isSliderMoveContinuous(const HbWidget *widget) |
|
849 { |
|
850 bool continuous(true); |
|
851 if (const HbAbstractSliderControl *slider = qobject_cast<const HbAbstractSliderControl *>(widget)) { |
|
852 if (!slider->isSliderDown()) { |
|
853 int range = slider->maximum() - slider->minimum(); |
|
854 int numberOfSteps = range / slider->singleStep(); |
|
855 continuous = numberOfSteps > continuousSliderStepLimit; |
|
856 } |
|
857 } |
|
858 else if (const HbProgressSlider *progressSlider = qobject_cast<const HbProgressSlider *>(widget)) { |
|
859 Q_UNUSED(progressSlider); |
|
860 continuous = true; |
|
861 } |
|
862 return continuous; |
|
863 } |
|
864 |
|
865 /*! |
|
866 Returns the status of the options menu. |
|
867 */ |
|
868 bool HbFeedbackEffectUtils::isOptionsMenuEmpty(const HbWidget *widget) |
|
869 { |
|
870 bool menuEmpty(false); |
|
871 HbMainWindow* window = widget->mainWindow(); |
|
872 if (window) { |
|
873 HbView* view = window->currentView(); |
|
874 if (view) { |
|
875 HbMenu *menu = view->menu(); |
|
876 if (menu && menu->isEmpty()) { |
|
877 menuEmpty = true; |
|
878 } |
|
879 } |
|
880 } |
|
881 return menuEmpty; |
|
882 } |
|
883 |