modify Klockwork bug
[platform/framework/native/uifw.git] / src / ui / controls / FUiCtrl_OptionMenuPresenter.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0/
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an ”AS IS” BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 /**
19  * @file                FUiCtrl_OptionMenuListPresenter.cpp
20  * @brief               This is the implementation file for the _OptionMenuPresenter class.
21  */
22
23 #include <FBaseErrorDefine.h>
24 #include <FBaseSysLog.h>
25 #include <FGrp_BitmapImpl.h>
26 #include <FGrp_CanvasImpl.h>
27 #include <FGrp_TextTextSimple.h>
28 #include "FUi_AccessibilityContainer.h"
29 #include "FUi_AccessibilityElement.h"
30 #include "FUi_CoordinateSystemUtils.h"
31 #include "FUi_Math.h"
32 #include "FUi_ResourceManager.h"
33 #include "FUiAnim_MatrixUtil.h"
34 #include "FUiCtrl_ActionEvent.h"
35 #include "FUiCtrl_IActionEventListener.h"
36
37 #include "FUiCtrl_OptionMenuPresenter.h"
38
39 using namespace Tizen::Graphics;
40 using namespace Tizen::Ui;
41 using namespace Tizen::Base;
42 using namespace Tizen::Base::Runtime;
43 using namespace Tizen::Graphics::_Text;
44 using namespace Tizen::Ui::Animations;
45
46 namespace {
47 static const float TOUCH_PRESS_THRESHOLD_INSENSITIVE = 0.16f;
48 static const int OPTION_MENU_LIST_ELEMENT_TEXT = 0;
49 static const int OPTION_MENU_LIST_ELEMENT_BITMAP = 1;
50 }
51
52 namespace Tizen { namespace Ui { namespace Controls
53 {
54
55 float
56 SineThirtyThreeTimingFunction::CalculateProgress(float timeProgress) const
57 {
58         const float segments[2][3] = {{0.0f, 0.050f, 0.495f}, {0.495f, 0.940f, 1.0f}};
59
60         float loc_5 = timeProgress;
61         int loc_6 = 2;  //Length of the segments array
62         int loc_9 = (int)floor(loc_6 * loc_5);
63
64         if (loc_9 >= loc_6)
65         {
66                 loc_9 = loc_6 - 1;
67         }
68
69         float loc_7 = (loc_5 - loc_9 * (1.0f / loc_6)) * loc_6;
70
71         float loc_8[3];
72
73         for (int i = 0; i < 3; i++)
74         {
75                 loc_8[i] = segments[loc_9][i];
76         }
77
78         float ret = 0 + 1 * (loc_8[0] + loc_7 * (2 * (1 - loc_7) * (loc_8[1] - loc_8[0]) + loc_7 * (loc_8[2] - loc_8[0])));
79         return ret;
80 }
81
82 float
83 SineSixtyTimingFunction::CalculateProgress(float timeProgress) const
84 {
85         const float segments[3][3] = {{0.0f, 0.01f, 0.37f}, {0.37f, 0.72f, 0.888f}, {0.888f, 0.9999f, 1.0f}};
86         float loc_5 = timeProgress;
87         int loc_6 = 3;  //Length of the segments array
88         int loc_9 = (int)floor(loc_6 * loc_5);
89
90         if (loc_9 >= loc_6)
91         {
92                 loc_9 = loc_6 - 1;
93         }
94         float loc_7 = (loc_5 - loc_9 * (1.0 / loc_6)) * loc_6;
95         float loc_8[3];
96
97         for (int i = 0; i < 3; i++)
98         {
99                 loc_8[i] = segments[loc_9][i];
100         }
101
102         float ret = 0 + 1 * (loc_8[0] + loc_7 * (2 * (1 - loc_7) * (loc_8[1] - loc_8[0]) + loc_7 * (loc_8[2] - loc_8[0])));
103
104         return ret;
105 }
106
107 _OptionMenuPresenter::_OptionMenuPresenter(_OptionMenu* pOptionMenu)
108         : __pOptionMenu(pOptionMenu)
109         , __pModel(null)
110         , __pFont(null)
111         , __layoutSize(FloatDimension(0.0f, 0.0f))
112         , __touchOutRect(false)
113         , __selectedIndex(-1)
114         , __scrollEnable(false)
115         , __maxWidth(0.0f)
116         , __minWidth(0.0f)
117         , __topMargin(0.0f)
118         , __bottomMargin(0.0f)
119         , __leftMargin(0.0f)
120         , __rightMargin(0.0f)
121         , __itemWidth(0.0f)
122         , __itemMinWidth(0.0f)
123         , __itemHeight(0.0f)
124         , __itemMaxWidth(0.0f)
125         , __itemGap(0.0f)
126         , __itemBitmapWidth(0.0f)
127         , __itemBitmapHeight(0.0f)
128         , __itemFontSize(0.0f)
129         , __dividerHeight(0.0f)
130         , __focusedIndex(-1)
131 {
132
133 }
134
135 _OptionMenuPresenter::~_OptionMenuPresenter(void)
136 {
137         __pOptionMenu = null;
138
139         delete __pModel;
140         __pModel = null;
141
142         __pFont = null;
143
144 }
145
146 result
147 _OptionMenuPresenter::Install(void)
148 {
149         result r = E_SUCCESS;
150
151         LoadShape();
152
153         __pModel = new (std::nothrow) _OptionMenuModel;
154         SysTryReturnResult(NID_UI_CTRL, __pModel != null, E_OUT_OF_MEMORY, "Memory allocation failed.");
155
156         r = __pModel->Construct();
157         SysTryCatch(NID_UI_CTRL, r == E_SUCCESS, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
158
159         __pFont = __pOptionMenu->GetFallbackFont();
160         r = GetLastResult();
161         SysTryCatch(NID_UI_CTRL, (__pFont != null), , r, "[%s] Propagating.", GetErrorMessage(r));
162
163         return r;
164
165 CATCH:
166         delete __pModel;
167         __pModel = null;
168
169         __pFont = null;
170
171         return r;
172 }
173
174 void
175 _OptionMenuPresenter::LoadShape(void)
176 {
177         GET_SHAPE_CONFIG(OPTIONMENU::LIST_MIN_WIDTH, _CONTROL_ORIENTATION_PORTRAIT, __itemMinWidth);
178         GET_SHAPE_CONFIG(OPTIONMENU::LIST_MAX_WIDTH, _CONTROL_ORIENTATION_PORTRAIT, __itemMaxWidth);
179         GET_SHAPE_CONFIG(OPTIONMENU::LIST_ITEM_HEIGHT, _CONTROL_ORIENTATION_PORTRAIT, __itemHeight);
180         GET_SHAPE_CONFIG(OPTIONMENU::LIST_ITEM_GAP, _CONTROL_ORIENTATION_PORTRAIT, __itemGap);
181
182         GET_SHAPE_CONFIG(OPTIONMENU::LIST_TOP_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, __topMargin);
183         GET_SHAPE_CONFIG(OPTIONMENU::LIST_BOTTOM_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, __bottomMargin);
184         GET_SHAPE_CONFIG(OPTIONMENU::LIST_LEFT_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, __leftMargin);
185         GET_SHAPE_CONFIG(OPTIONMENU::LIST_RIGHT_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, __rightMargin);
186
187         GET_SHAPE_CONFIG(OPTIONMENU::LIST_ICON_WIDTH, _CONTROL_ORIENTATION_PORTRAIT, __itemBitmapWidth);
188         GET_SHAPE_CONFIG(OPTIONMENU::LIST_ICON_HEIGHT, _CONTROL_ORIENTATION_PORTRAIT, __itemBitmapHeight);
189
190         GET_SHAPE_CONFIG(OPTIONMENU::LIST_ITEM_FONT_SIZE, _CONTROL_ORIENTATION_PORTRAIT, __itemFontSize);
191         GET_SHAPE_CONFIG(OPTIONMENU::LIST_DIVIDER_HEIGHT, _CONTROL_ORIENTATION_PORTRAIT, __dividerHeight);
192
193         __itemWidth = __itemMinWidth;
194 }
195
196 _OptionMenuItem*
197 _OptionMenuPresenter::CreateItemN(const String& text, int actionId, const Bitmap* pNormalBitmap, const Bitmap* pPressedBitmap, const Bitmap* pHighlightedBitmap, bool isSubItem)
198 {
199         _OptionMenuItem* pItem = _OptionMenuItem::CreateOptionMenuItemN();
200         SysTryReturn(NID_UI_CTRL, pItem != null, null, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
201
202         OptionMenuItemDrawingType itemType = OPTION_MENU_ITEM_DRAWING_TYPE_TEXT;
203         _Label* pLabel = null;
204         result r = E_SUCCESS;
205
206         // add bitmap label
207         pLabel = _Label::CreateLabelN();
208         if (GetLastResult() != E_SUCCESS)
209         {
210                 delete pItem;
211                 return null;
212         }
213
214         pLabel->SetBackgroundBitmap(*pNormalBitmap);
215         pLabel->SetBackgroundColor(Color(0, 0, 0, 0));
216
217         int bitmapY = (__itemHeight - __itemBitmapHeight) / 2;
218         pLabel->SetBounds(FloatRectangle(__leftMargin, bitmapY,  __itemBitmapWidth, __itemBitmapHeight));
219         pLabel->SetTouchPressThreshold(TOUCH_PRESS_THRESHOLD_INSENSITIVE);
220         pItem->AttachChild(*pLabel);
221         pItem->SetBitmapLabel(pLabel);
222
223         _AccessibilityContainer* pContainer = pLabel->GetAccessibilityContainer();
224         if (pContainer != null)
225         {
226                 pContainer->Activate(false);
227         }
228
229         if (pNormalBitmap != null)
230         {
231                 r = pItem->SetBitmap(OPTION_MENU_ITEM_DRAWING_STATUS_NORMAL, pNormalBitmap);
232                 if (r != E_SUCCESS)
233                 {
234                         delete pItem;
235                         return null;
236                 }
237
238                 itemType = OPTION_MENU_ITEM_DRAWING_TYPE_BITMAP;
239         }
240
241         if (pPressedBitmap != null)
242         {
243                 r = pItem->SetBitmap(OPTION_MENU_ITEM_DRAWING_STATUS_PRESSED, pPressedBitmap);
244                 if (r != E_SUCCESS)
245                 {
246                         delete pItem;
247                         return null;
248                 }
249         }
250
251         if (pHighlightedBitmap != null)
252         {
253                 r = pItem->SetBitmap(OPTION_MENU_ITEM_DRAWING_STATUS_HIGHLIGHTED, pHighlightedBitmap);
254                 if (r != E_SUCCESS)
255                 {
256                         delete pItem;
257                         return null;
258                 }
259         }
260
261         pItem->SetType(itemType);
262         pItem->SetActionId(actionId);
263
264         pItem->SetTextSize(__itemFontSize);
265         r = pItem->SetText(text);
266         if (r != E_SUCCESS)
267         {
268                 delete pItem;
269                 return null;
270         }
271
272         // calculate item size
273         float bitmapWidth = 0.0f;
274
275         if (itemType == OPTION_MENU_ITEM_DRAWING_TYPE_BITMAP)
276         {
277                 bitmapWidth = __itemBitmapWidth;
278         }
279
280         FloatDimension textArea(0.0f, 0.0f);
281         FloatDimension itemSize(0.0f, 0.0f);
282
283         CalculateItemSize(text, itemType, textArea, itemSize);
284
285         float labelLeftMargin = 0.0f;
286         GET_SHAPE_CONFIG(LABEL::LEFT_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, labelLeftMargin);
287         pItem->SetSize(itemSize);
288
289         // add text label
290         float textLabelX = labelLeftMargin + bitmapWidth;
291
292         pLabel = _Label::CreateLabelN();
293         if (GetLastResult() != E_SUCCESS)
294         {
295                 delete pItem;
296                 return null;
297         }
298
299         pLabel->SetText(text);
300         OptionMenuCoreItemStatus itemStatus = OPTION_MENU_CORE_ITEM_STATUS_NORMAL;
301         pLabel->SetTextColor(__pOptionMenu->GetTextColor(itemStatus));
302         pLabel->SetBackgroundColor(Color(0, 0, 0, 0));
303
304         itemSize = pItem->GetSize();
305         pLabel->SetBounds(FloatRectangle(textLabelX, (itemSize.height - textArea.height) / 2.0f, textArea.width, textArea.height));
306         pLabel->SetTextVerticalAlignment(ALIGNMENT_MIDDLE);
307         pLabel->SetTextHorizontalAlignment(ALIGNMENT_LEFT);
308         pLabel->SetTextConfig(__itemFontSize, LABEL_TEXT_STYLE_NORMAL);
309
310         pLabel->SetTouchPressThreshold(TOUCH_PRESS_THRESHOLD_INSENSITIVE);
311         pItem->AttachChild(*pLabel);
312
313         pContainer = pLabel->GetAccessibilityContainer();
314
315         if (pContainer != null)
316         {
317                 pContainer->Activate(false);
318         }
319         pItem->SetTextLabel(pLabel);
320
321         if (!isSubItem)
322         {
323                 __itemWidth = __itemWidth < itemSize.width ? itemSize.width : __itemWidth;
324         }
325
326         pItem->SetTouchPressThreshold(TOUCH_PRESS_THRESHOLD_INSENSITIVE);
327         return pItem;
328 }
329
330 void
331 _OptionMenuPresenter::CalculateItemSize(const String &text, OptionMenuItemDrawingType itemType, FloatDimension &textArea, FloatDimension &itemSize)
332 {
333         float labelLeftMargin = 0.0f;
334         float labelTopMargin = 0.0f;
335         __pFont->GetTextExtent(text, text.GetLength(), textArea);
336
337         GET_SHAPE_CONFIG(LABEL::LEFT_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, labelLeftMargin);
338         GET_SHAPE_CONFIG(LABEL::TOP_MARGIN,  _CONTROL_ORIENTATION_PORTRAIT, labelTopMargin);
339
340         textArea.width  += 2.0f * labelLeftMargin;
341         textArea.height += 2.0f * labelTopMargin;
342         itemSize.height = __itemHeight + (__dividerHeight * 2.0f);
343         itemSize.width =  __leftMargin + textArea.width + __rightMargin;
344
345         if (itemType == OPTION_MENU_ITEM_DRAWING_TYPE_BITMAP)
346         {
347                 itemSize.width =  itemSize.width + __itemBitmapWidth;
348         }
349
350         itemSize.width = itemSize.width < __itemMinWidth ? __itemMinWidth : itemSize.width;
351
352         if (itemSize.width > __itemMaxWidth)
353         {
354                 textArea.width -= itemSize.width - __itemMaxWidth;
355                 itemSize.width = __itemMaxWidth;
356         }
357 }
358
359 result
360 _OptionMenuPresenter::AddItem(const String& text, int actionId, const Bitmap* normalBitmap, const Bitmap* pPressedBitmap, const Bitmap* pHighlightedBitmap)
361 {
362         _OptionMenuItem* pItem = CreateItemN(text, actionId, normalBitmap, pPressedBitmap, pHighlightedBitmap);
363         SysTryReturnResult(NID_UI_CTRL, pItem != null, GetLastResult(), "Failed to create item.");
364
365         result r = __pModel->AddItem(pItem);
366
367         if (r != E_SUCCESS)
368         {
369                 delete pItem;
370                 SysTryReturnResult(NID_UI_CTRL, false, r, "Failed to add item.");
371         }
372
373         return r;
374 }
375
376 result
377 _OptionMenuPresenter::AddSubItem(int mainIndex, const String& text, int actionId)
378 {
379         SysTryReturnResult(NID_UI_CTRL, mainIndex >=0 && mainIndex < __pModel->GetItemCount(), E_INVALID_ARG, "Invalid argument is used. mainIndex (%d) is invalid.", mainIndex);
380
381         _OptionMenuItem* pItem = CreateItemN(text, actionId, null, null, null, true);
382         SysTryReturnResult(NID_UI_CTRL, pItem != null, GetLastResult(), "Failed to create item.");
383
384         result r = __pModel->AddItem(pItem, mainIndex);
385
386         if (r != E_SUCCESS)
387         {
388                 delete pItem;
389                 SysTryReturnResult(NID_UI_CTRL, false, r, "Failed to add item.");
390         }
391
392         return r;
393 }
394
395 int
396 _OptionMenuPresenter::GetItemIndexFromActionId(int actionId) const
397 {
398         return __pModel->GetItemIndexFromActionId(actionId);
399 }
400
401 int
402 _OptionMenuPresenter::GetItemActionIdAt(int mainIndex) const
403 {
404         _OptionMenuItem* pItem = __pModel->GetItem(mainIndex);
405         if (pItem == null)
406         {
407                 return -1;
408         }
409
410         return pItem->GetActionId();
411 }
412
413 result
414 _OptionMenuPresenter::InsertItem(int mainIndex, const String& text, int actionId, const Bitmap* normalBitmap,
415                 const Bitmap* pPressedBitmap, const Bitmap* pHighlightedBitmap)
416 {
417         _OptionMenuItem* pItem = CreateItemN(text, actionId, normalBitmap, pPressedBitmap, pHighlightedBitmap);
418         SysTryReturnResult(NID_UI_CTRL, pItem != null, GetLastResult(), "Failed to create item.");
419
420         result r = __pModel->InsertItemAt(pItem, mainIndex);
421         if (r != E_SUCCESS)
422         {
423                 delete pItem;
424                 SysTryReturnResult(NID_UI_CTRL, false, r, "Failed to add item.");
425         }
426
427         return E_SUCCESS;
428 }
429
430 result
431 _OptionMenuPresenter::InsertSubItemAt(int mainIndex, int subIndex, const String& text, int actionId)
432 {
433         SysTryReturnResult(NID_UI_CTRL, mainIndex >=0 && mainIndex < __pModel->GetItemCount(), E_INVALID_ARG, " Invalid argument is used. mainIndex (%d) is invalid.", mainIndex);
434         SysTryReturnResult(NID_UI_CTRL, subIndex >=0 && subIndex <= __pModel->GetSubItemCount(mainIndex), E_INVALID_ARG, " Invalid subIndex %d.", subIndex);
435
436         _OptionMenuItem* pItem = CreateItemN(text, actionId, null, null, null, true);
437         SysTryReturnResult(NID_UI_CTRL, pItem != null, GetLastResult(), "Failed to create item.");
438
439         result r = __pModel->InsertItemAt(pItem, mainIndex, subIndex);
440         SysTryReturnResult(NID_UI_CTRL, (r == E_SUCCESS), r, "Propagating.");
441
442         return E_SUCCESS;
443 }
444
445 result
446 _OptionMenuPresenter::SetSubItemAt(int mainIndex, int subIndex, const String& text, int actionId)
447 {
448         SysTryReturnResult(NID_UI_CTRL, mainIndex >=0 && mainIndex < __pModel->GetItemCount(), E_INVALID_ARG, "Invalid argument is used. mainIndex (%d) is invalid.", mainIndex);
449         SysTryReturnResult(NID_UI_CTRL, subIndex >=0 && subIndex < __pModel->GetSubItemCount(mainIndex), E_INVALID_ARG, "Invalid argument is used. SubIndex (%d) is invalid.", subIndex);
450
451         result r = __pModel->SetItemAt(mainIndex, text, actionId, null, null, null, __itemFontSize, subIndex);
452         SysTryReturnResult(NID_UI_CTRL, (r == E_SUCCESS), r, "Propagating.");
453
454         return E_SUCCESS;
455 }
456
457 result
458 _OptionMenuPresenter::RemoveSubItemAt(int mainIndex, int subIndex)
459 {
460         SysTryReturnResult(NID_UI_CTRL, mainIndex >=0 && mainIndex < __pModel->GetItemCount(), E_INVALID_ARG, "Invalid argument is used. mainIndex (%d) is invalid", mainIndex);
461         SysTryReturnResult(NID_UI_CTRL, subIndex >=0 && subIndex < __pModel->GetSubItemCount(mainIndex), E_INVALID_ARG, "Invalid argument is used. SubIndex (%d) is invalid.", subIndex);
462
463         result r = __pModel->RemoveItem(mainIndex, subIndex);
464         SysTryReturnResult(NID_UI_CTRL, (r == E_SUCCESS), r, "Propagating.");
465
466         return E_SUCCESS;
467 }
468
469 int
470 _OptionMenuPresenter::GetSubItemCount(int mainIndex) const
471 {
472         SysTryReturn(NID_UI_CTRL, mainIndex >=0 && mainIndex < __pModel->GetItemCount(), -1, E_INVALID_ARG, "[%s] Invalid argument is used. mainIndex (%d) is invalid.", GetErrorMessage(E_INVALID_ARG), mainIndex);
473         return __pModel->GetSubItemCount(mainIndex);
474 }
475
476 int
477 _OptionMenuPresenter::GetSubItemIndexFromActionId(int actionId) const
478 {
479         int mainIndex = -1;
480         return __pModel->GetSubItemIndexFromActionId(actionId, mainIndex);
481 }
482
483 int
484 _OptionMenuPresenter::GetSubItemActionIdAt(int mainIndex, int subIndex) const
485 {
486         _OptionMenuItem* pItem = __pModel->GetItem(mainIndex, subIndex);
487         if (pItem == null)
488         {
489                 return -1;
490         }
491
492         return pItem->GetActionId();
493 }
494
495 void
496 _OptionMenuPresenter::CalculateItemMaximumWidth(void)
497 {
498         FloatDimension itemSize(0.0f, 0.0f);
499         FloatDimension textArea(0.0f, 0.0f);
500         float maxItemWidth = __itemMinWidth;
501
502         for (int i = 0; i < __pModel->GetItemCount(); i++)
503         {
504                 _OptionMenuItem* pItem = null;
505
506                 pItem = __pModel->GetItem(i);
507                 SysTryReturnVoidResult(NID_UI_CTRL, pItem != null, E_SYSTEM, "[%s] A system has error occurred. Unable to get the item.", GetErrorMessage(E_SYSTEM));
508
509                 CalculateItemSize(pItem->GetText(), pItem->GetType(), textArea, itemSize);
510
511                 if (maxItemWidth < itemSize.width)
512                 {
513                         maxItemWidth = itemSize.width;
514                 }
515
516         }
517         __itemWidth = maxItemWidth;
518 }
519
520 result
521 _OptionMenuPresenter::SetItem(int index, const String& text, int actionId, const Bitmap* normalBitmap, const Bitmap* pPressedBitmap, const Bitmap* pHighlightedBitmap)
522 {
523         SysTryReturnResult(NID_UI_CTRL, index >=0 && index < __pModel->GetItemCount(), E_INVALID_ARG, "Invalid argument is used. mainIndex (%d) is invalid.", index);
524
525         result r = __pModel->SetItemAt(index, text, actionId, normalBitmap, pPressedBitmap, pHighlightedBitmap, __itemFontSize);
526         SysTryReturnResult(NID_UI_CTRL, r == E_SUCCESS, r, "Propagating.");
527
528         _OptionMenuItem* pItem = __pModel->GetItem(index);
529
530         SysTryReturnResult(NID_UI_CTRL, pItem != null, r, "Propagating.");
531         CalculateItemMaximumWidth();
532
533         return r;
534 }
535
536 result
537 _OptionMenuPresenter::DeleteItem(int index)
538 {
539         SysTryReturnResult(NID_UI_CTRL, (index < __pOptionMenu->GetItemCount()), E_INVALID_ARG,
540                         "Invalid argument is used. The specified index (%d) is invalid.", index);
541
542         result r = E_SUCCESS;
543         _OptionMenuItem* pItem = null;
544
545         pItem = __pModel->GetItem(index);
546
547         if (pItem != null && pItem->HasParent())
548         {
549                 r = __pOptionMenu->GetScrollPanel()->DetachChild(*__pModel->GetItem(index));
550                 SysTryReturnResult(NID_UI_CTRL, r == E_SUCCESS, r, "Failed to detach item.");
551         }
552
553         r = __pModel->RemoveItem(index);
554         SysTryReturnResult(NID_UI_CTRL, r == E_SUCCESS, r, "Failed to delete item.");
555
556         CalculateItemMaximumWidth();
557
558         return r;
559 }
560
561 result
562 _OptionMenuPresenter::DeleteItemAll(void)
563 {
564         SysTryReturnResult(NID_UI_CTRL, (__pOptionMenu->GetItemCount() > 0), E_SYSTEM,
565                         "A system error has occurred. No items exists.");
566
567         __pOptionMenu->GetScrollPanel()->DetachAllChildren();
568
569         result r =  __pModel->RemoveAllItem();
570         SysTryReturnResult(NID_UI_CTRL, r == E_SUCCESS, r, "Failed to delete all items.");
571
572         return r;
573 }
574
575 result
576 _OptionMenuPresenter::CalculateWindowRect(void)
577 {
578         result r = CalculateRect();
579         AdjustItemPosition();
580
581         return r;
582 }
583
584 result
585 _OptionMenuPresenter::ApplyColorProperty(void)
586 {
587         int count;
588         count = __pOptionMenu->GetItemCount();
589
590         for (int i = 0; i < count; i++)
591         {
592                 _OptionMenuItem* pItem = null;
593                 Color color = __pOptionMenu->GetItemColor(OPTION_MENU_CORE_ITEM_STATUS_PRESSED);
594
595                 pItem = __pModel->GetItem(i);
596                 pItem->SetPressedItemColor(color);
597         }
598
599         return E_SUCCESS;
600 }
601
602 result
603 _OptionMenuPresenter::CalculateRect(void)
604 {
605         FloatRectangle windowRect = FloatRectangle(0.0f, 0.0f, 0.0f, 0.0f);     // OptionMenu window itself
606         FloatRectangle bodyRect   = FloatRectangle(0.0f, 0.0f, 0.0f, 0.0f);     // bg surronding showing items, relative to window
607         FloatRectangle itemRect   = FloatRectangle(0.0f, 0.0f, 0.0f, 0.0f);     // relative to window
608
609         float bodyTopMargin = __topMargin;
610         float bodyBottomMargin = __bottomMargin;
611         float bodyLeftMargin = __leftMargin;
612         float bodyRightMargin = __rightMargin;
613
614         int scrollPanelMargin;
615         GET_SHAPE_CONFIG(OPTIONMENU::SCROLL_PANEL_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, scrollPanelMargin);
616
617         FloatDimension screen = _ControlManager::GetInstance()->GetScreenSizeF();
618         _ControlRotation rotation = __pOptionMenu->GetRotation();
619
620         if (__pOptionMenu->GetLayout() == _CONTROL_ORIENTATION_LANDSCAPE)
621         {
622                 screen.SetSize(screen.height, screen.width);
623         }
624
625         AdjustItemLayout();
626
627         bodyRect.width = __layoutSize.width + bodyLeftMargin + bodyRightMargin;
628         bodyRect.height = __layoutSize.height + bodyTopMargin + bodyBottomMargin + 2 * scrollPanelMargin;
629
630         if (rotation == _CONTROL_ROTATION_270 && __pOptionMenu->GetLayout() == _CONTROL_ORIENTATION_LANDSCAPE)
631         {
632                 bodyRect.x = screen.width - bodyRect.width;
633         }
634
635         bodyRect.y =  screen.height - bodyRect.height;
636
637         bodyRect = CoordinateSystem::AlignToDevice(bodyRect);
638
639         windowRect = bodyRect;
640
641         bodyRect.x = 0.0f;
642         bodyRect.y = 0.0f;
643
644         itemRect.x      = bodyRect.x + bodyLeftMargin;
645         itemRect.y      = bodyRect.y + bodyTopMargin + scrollPanelMargin;
646         itemRect.width  = __layoutSize.width;
647         itemRect.height = __layoutSize.height;
648
649         __pOptionMenu->SetWindowRect(windowRect);
650         __pOptionMenu->SetBodyRect(bodyRect);
651         __pOptionMenu->SetItemRect(itemRect);
652
653         // _ScrollPanel API call sequence: SetBounds() -> SetScrollAreaBounds()
654         // _Scroll visual interaction if Bounds < ScrollAreaBounds
655         if (__pOptionMenu->IsVisible())
656         {
657                 __pOptionMenu->GetScrollPanel()->SetBounds(FloatRectangle(bodyRect.x + bodyLeftMargin, bodyRect.y + bodyTopMargin + scrollPanelMargin,
658                                 __layoutSize.width, __layoutSize.height));
659                 int itemCount = __pModel->GetItemCount();
660                 float itemHeight = __itemHeight + (__dividerHeight * 2.0f);
661                 float layoutClientHeight = itemCount * itemHeight - (__dividerHeight * 2.0f);
662                 __pOptionMenu->GetScrollPanel()->SetClientAreaHeight(layoutClientHeight);
663         }
664
665         __pOptionMenu->SetMovable(true);
666         __pOptionMenu->SetResizable(true);
667
668         __pOptionMenu->SetBounds(windowRect);
669
670         __pOptionMenu->SetMovable(false);
671         __pOptionMenu->SetResizable(false);
672
673         return E_SUCCESS;
674 }
675
676 void
677 _OptionMenuPresenter::AdjustItemLayout(void)
678 {
679         FloatDimension layoutSize(0.0f, 0.0f);
680
681         int itemCount = __pModel->GetItemCount();
682
683         if (itemCount <= 0)
684         {
685                 __layoutSize.width = __itemWidth;
686                 __layoutSize.height = __itemHeight;
687                 return;
688         }
689
690         layoutSize = AdjustItemLayoutStyle();
691
692         FloatDimension screen = _ControlManager::GetInstance()->GetScreenSizeF();
693         if (__pOptionMenu->GetLayout() == _CONTROL_ORIENTATION_LANDSCAPE)
694         {
695                 screen.SetSize(screen.height, screen.width);
696         }
697
698         int maxHeight = screen.height;
699         if (layoutSize.height > maxHeight)
700         {
701                 layoutSize.height = maxHeight;
702         }
703
704         __layoutSize = layoutSize;
705 }
706
707 FloatDimension
708 _OptionMenuPresenter::AdjustItemLayoutStyle(void)
709 {
710         int itemMaxCount = __pOptionMenu->GetMaximumVisibleItemsCount();
711
712         int itemCount = __pModel->GetItemCount();
713         float itemHeight = __itemHeight + (__dividerHeight * 2.0f);
714
715         FloatDimension layoutSize(__itemWidth, 0.0f);
716
717         float layoutClientHeight = itemCount * itemHeight - (__dividerHeight * 2.0f);
718         float layoutMaxHeight = itemMaxCount * itemHeight - (__dividerHeight * 2.0f);
719         if (layoutClientHeight > layoutMaxHeight)
720         {
721                 __scrollEnable = true;
722                 layoutSize.height = layoutMaxHeight + itemHeight / 2;
723         }
724         else
725         {
726                 __scrollEnable = false;
727                 layoutSize.height = layoutClientHeight;
728         }
729
730         return layoutSize;
731 }
732
733 void
734 _OptionMenuPresenter::AdjustItemPosition(void)
735 {
736         int itemCount = __pModel->GetItemCount();
737         if (itemCount <= 0)
738         {
739                 return;
740         }
741
742         float itemHeight = __itemHeight + (__dividerHeight * 2.0f);
743         float drawItemY = 0.0f;
744
745         float x = __pOptionMenu->GetBodyRect().x + __leftMargin;
746         float y = __pOptionMenu->GetBodyRect().y +  __topMargin;
747
748         _OptionMenuItem* pItem = null;
749
750         for (int i = 0; i < itemCount; i++)
751         {
752                 pItem = __pModel->GetItem(i);
753
754                 if (pItem == null)
755                 {
756                         break;
757                 }
758
759                 FloatRectangle drawRect(x, drawItemY + y, __itemWidth, itemHeight);
760
761                 pItem->SetDrawRect(drawRect);
762                 pItem->SetUpperDivider(i > 0);
763                 pItem->SetLowerDivider(i < itemCount - 1);
764                 pItem->SetParentScrollEnable(__scrollEnable);
765                 pItem->SetBounds(FloatRectangle(0.0f, drawItemY, drawRect.width, drawRect.height));
766
767                 if (!pItem->HasParent())
768                 {
769                         __pOptionMenu->GetScrollPanel()->AttachChild(*pItem);
770                 }
771
772                 drawItemY += itemHeight;
773         }
774 }
775
776 int
777 _OptionMenuPresenter::GetItemIndexFromPosition(const FloatPoint& point) const
778 {
779         int index = -1;
780         int itemCount = __pModel->GetItemCount();
781
782         if (itemCount < 0)
783         {
784                 return -1;
785         }
786
787         _OptionMenuItem* pItem = null;
788
789         float scrollPosition = __pOptionMenu->GetScrollPanel()->GetScrollPosition();
790         FloatPoint position(point.x, point.y + scrollPosition);
791
792         for (int i = 0; i < itemCount; i++)
793         {
794                 pItem = __pModel->GetItem(i);
795
796                 if (pItem == null)
797                 {
798                         break;
799                 }
800
801                 FloatRectangle drawRect = pItem->GetDrawRect();
802
803                 if (drawRect.Contains(position))
804                 {
805                         index = i;
806                         break;
807                 }
808         }
809
810         return index;
811 }
812
813 result
814 _OptionMenuPresenter::Draw(void)
815 {
816         result r = E_SUCCESS;
817
818         Canvas* pCanvas = __pOptionMenu->GetCanvasN();
819         SysTryReturnResult(NID_UI_CTRL, pCanvas != null, GetLastResult(), "Propagating");
820
821         // Clear canvas for drawing area of the OptionMenu.
822         pCanvas->SetBackgroundColor(Color(0, 0, 0, 0));
823         FloatRectangle bounds(__pOptionMenu->GetWindowRect());
824         pCanvas->Clear(FloatRectangle(0.0f, 0.0f, bounds.width, bounds.height));
825
826         r = DrawBackground(pCanvas);
827         if (r != E_SUCCESS)
828         {
829                 SysLog(NID_UI_CTRL, "[%s] Failed to draw background.", GetErrorMessage(r));
830         }
831
832         delete pCanvas;
833         return r;
834 }
835
836 result
837 _OptionMenuPresenter::DrawFocus(int index)
838 {
839
840         result r = E_SUCCESS;
841
842         ClearFocus();
843         _OptionMenuItem* pItem = __pModel->GetItem(index);
844         if (pItem != null)
845         {
846                 pItem->SetHighlighted(true);
847                 pItem->Invalidate(true);
848                 pItem->DrawFocus();
849                 __focusedIndex = index;
850         }
851
852         return r;
853 }
854
855 void
856 _OptionMenuPresenter::ClearFocus(void)
857 {
858         _OptionMenuItem* pPreviousItem;
859         if (__focusedIndex != -1)
860         {
861                 pPreviousItem = __pModel->GetItem(__focusedIndex);
862                 if (pPreviousItem != null)
863                 {
864                         pPreviousItem->SetHighlighted(false);
865                         pPreviousItem->RemoveFocusRing();
866                         pPreviousItem->Invalidate(true);
867                 }
868         }
869 }
870
871 void
872 _OptionMenuPresenter::OnEnterKeyReleased(int selectedIndex)
873 {
874         _OptionMenuItem* pItem = null;
875         pItem = __pModel->GetItem(selectedIndex);
876         __selectedIndex = -1;
877         ClearFocus();
878
879         if (pItem != null)
880         {
881                 if (pItem->HasSubItem())
882                 {
883                         // Show SubItem
884                         __pOptionMenu->ShowSubMenu(selectedIndex, *pItem);
885                         return ;
886                 }
887                 else
888                 {
889                         __pOptionMenu->CloseAnimation(pItem->GetActionId());
890                 }
891         }
892         return;
893 }
894
895 result
896 _OptionMenuPresenter::DrawBackground(Canvas* pCanvas)
897 {
898         SysTryReturnResult(NID_UI_CTRL, pCanvas != null, E_SYSTEM, "A system error has occurred. pCanvas is null");
899
900         result r = E_SUCCESS;
901
902         FloatRectangle bodyRect = __pOptionMenu->GetBodyRect();
903
904         const Bitmap* pBackgroundNormalBitmap = __pOptionMenu->GetBackgroundNormalBitmap();
905         const Bitmap* pBackgroundEffectBitmap = __pOptionMenu->GetBackgroundEffectBitmap();
906
907         if (pBackgroundNormalBitmap == null && pBackgroundEffectBitmap == null)
908         {
909                 pCanvas->SetForegroundColor(__pOptionMenu->GetColor());
910                 pCanvas->DrawRectangle(bodyRect);
911         }
912         else
913         {
914                 if (pBackgroundNormalBitmap != null)
915                 {
916                         r = DrawBitmap(*pCanvas, bodyRect, *pBackgroundNormalBitmap);
917                 }
918
919                 if (pBackgroundEffectBitmap != null)
920                 {
921                         r = DrawBitmap(*pCanvas, bodyRect, *pBackgroundEffectBitmap);
922                 }
923         }
924
925         return r;
926 }
927
928 _UiTouchEventDelivery
929 _OptionMenuPresenter::OnPreviewTouchPressed(const _Control& source, const _TouchInfo& touchinfo)
930 {
931         return _UI_TOUCH_EVENT_DELIVERY_FORCED_YES;
932 }
933
934 bool
935 _OptionMenuPresenter::OnTouchPressed(const _Control& source, const _TouchInfo& touchinfo)
936 {
937         FloatPoint touchPosition = touchinfo.GetCurrentPosition();
938         FloatRectangle itemRect = __pOptionMenu->GetItemRect();
939
940         if (__pOptionMenu->IsSubMenuShown())
941         {
942                 __pOptionMenu->DestroySubMenu();
943                 __pOptionMenu->SetTouchCapture(false, false);
944                 return true;
945         }
946
947         if (!itemRect.Contains(touchPosition))
948         {
949                 __selectedIndex = -1;
950                 __touchOutRect = true;
951                 return true;
952         }
953
954         __selectedIndex = GetItemIndexFromPosition(touchPosition);
955         __touchOutRect = false;
956         return true;
957 }
958
959 _UiTouchEventDelivery
960 _OptionMenuPresenter::OnPreviewTouchReleased(const _Control& source, const _TouchInfo& touchinfo)
961 {
962         return _UI_TOUCH_EVENT_DELIVERY_FORCED_YES;
963 }
964
965 bool
966 _OptionMenuPresenter::OnTouchReleased(const _Control& source, const _TouchInfo& touchinfo)
967 {
968         FloatPoint touchPosition = touchinfo.GetCurrentPosition();
969
970         if (__touchOutRect)
971         {
972                 FloatRectangle itemRect = __pOptionMenu->GetItemRect();
973                 if (!itemRect.Contains(touchPosition))
974                 {
975                         __selectedIndex = -1;
976                         __pOptionMenu->CloseAnimation(-1);
977                         return true;
978                 }
979         }
980
981         __pOptionMenu->Invalidate(true);
982
983         int currentSelectedIndex = GetItemIndexFromPosition(touchPosition);
984         if (__selectedIndex != -1 && (__selectedIndex == currentSelectedIndex))
985         {
986                 _OptionMenuItem* pItem = null;
987                 pItem = __pModel->GetItem(__selectedIndex);
988                 __selectedIndex = -1;
989
990                 if (pItem != null)
991                 {
992                         if (pItem->HasSubItem())
993                         {
994                                 // Show SubItem
995                                 __pOptionMenu->ShowSubMenu(__selectedIndex, *pItem);
996                                 return true;
997                         }
998                         else
999                         {
1000                                 // Fire Action Event
1001                                 __pOptionMenu->CloseAnimation(pItem->GetActionId());
1002                                 PLAY_FEEDBACK(_RESOURCE_FEEDBACK_PATTERN_TAP, __pOptionMenu);
1003                         }
1004                 }
1005
1006         }
1007
1008         return true;
1009 }
1010
1011 _UiTouchEventDelivery
1012 _OptionMenuPresenter::OnPreviewTouchMoved(const _Control& source, const _TouchInfo& touchinfo)
1013 {
1014         return _UI_TOUCH_EVENT_DELIVERY_FORCED_YES;
1015 }
1016
1017 bool
1018 _OptionMenuPresenter::OnTouchMoved(const _Control& source, const _TouchInfo& touchinfo)
1019 {
1020         if (__scrollEnable)
1021         {
1022                 __selectedIndex = -1;
1023         }
1024         ResetSelectedItem();
1025
1026         return true;
1027 }
1028
1029 bool
1030 _OptionMenuPresenter::OnTouchCanceled(const _Control& source, const _TouchInfo& touchinfo)
1031 {
1032         __pModel->ResetAllItem();
1033         return true;
1034 }
1035
1036 void
1037 _OptionMenuPresenter::ResetSelectedItem(void)
1038 {
1039         __pModel->ResetSelectedItem(__selectedIndex);
1040 }
1041
1042 void
1043 _OptionMenuPresenter::OnActionPerformed(const _Control& source, int actionId)
1044 {
1045         // for SubMenu Events
1046         __pOptionMenu->DestroySubMenu();
1047         __pOptionMenu->CloseAnimation(actionId);
1048 }
1049
1050 void
1051 _OptionMenuPresenter::OnFontChanged(Font* pFont)
1052 {
1053         __pFont = pFont;
1054         String fontName = __pOptionMenu->GetFont();
1055
1056         int itemCount = __pModel->GetItemCount();
1057         for (int i = 0; i < itemCount; i++)
1058         {
1059                 _OptionMenuItem* pItem = __pModel->GetItem(i);
1060                 if (pItem != null)
1061                 {
1062                         pItem->SetFont(fontName);
1063                 }
1064         }
1065 }
1066
1067 void
1068 _OptionMenuPresenter::OnFontInfoRequested(unsigned long& style, float& size)
1069 {
1070         style = FONT_STYLE_PLAIN;
1071         size = __itemFontSize;
1072 }
1073
1074 void
1075 _OptionMenuPresenter::SetAllAccessibilityElement(void)
1076 {
1077         _AccessibilityContainer* pContainerOptionMenu = __pOptionMenu->GetAccessibilityContainer();
1078         if (pContainerOptionMenu != null)
1079         {
1080                 _AccessibilityElement* pElementOptionMenu = new (std::nothrow) _AccessibilityElement(true);
1081                 SysTryReturnVoidResult(NID_UI_CTRL, pElementOptionMenu, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
1082
1083                 pElementOptionMenu->SetSupportOperatingGesture(false);
1084                 //pElementOptionMenu->SetTraitWithStringId("IDS_TPLATFORM_BODY_CONTEXTUAL_POP_UP_T_TTS");
1085                 pElementOptionMenu->SetHintWithStringId("IDS_TPLATFORM_BODY_CONTEXTUAL_POP_UP_IS_OPEN_DOUBLE_TAP_TO_CLOSE_THE_POP_UP_T_TTS");
1086                 pElementOptionMenu->SetBounds(FloatRectangle(0.0f, 0.0f, __pOptionMenu->GetBoundsF().width, __pOptionMenu->GetBoundsF().height));
1087                 pContainerOptionMenu->AddElement(*pElementOptionMenu);
1088                 __pOptionMenu->AddAccessibilityElement(*pElementOptionMenu);
1089
1090                 int itemCount = __pModel->GetItemCount();
1091                 for (int i = 0; i < itemCount; i++)
1092                 {
1093                         _OptionMenuItem* pItem = __pModel->GetItem(i);
1094                         if (pItem != null)
1095                         {
1096                                 _AccessibilityContainer* pContainer = pItem->GetAccessibilityContainer();
1097                                 if (pContainer != null)
1098                                 {
1099                                         LinkedListT<_AccessibilityElement*> accessibilityElements;
1100                                         _AccessibilityElement* pElement = null;
1101
1102                                         pContainer->GetElements(accessibilityElements);
1103                                         if (accessibilityElements.GetAt(0, pElement) == E_SUCCESS)
1104                                         {
1105                                                 pElement->SetName(L"OptionMenuItem" + Integer::ToString(i));
1106                                                 if (pItem->GetType() == OPTION_MENU_ITEM_DRAWING_TYPE_BITMAP)
1107                                                 {
1108                                                         String string;
1109                                                         GET_STRING_CONFIG(IDS_TPLATFORM_BODY_ICON, string);
1110                                                         pElement->SetLabel(string + pItem->GetText());
1111                                                 }
1112                                                 else
1113                                                 {
1114                                                         pElement->SetLabel(pItem->GetText());
1115                                                 }
1116
1117                                                 pElement->SetBounds(FloatRectangle(0.0f, 0.0f, pItem->GetBoundsF().width, pItem->GetBoundsF().height));
1118                                         }
1119                                         pContainerOptionMenu->AddChildContainer(*pContainer);
1120                                 }
1121                         }
1122                 }
1123         }
1124 }
1125
1126 _OptionMenuItemInfo
1127 _OptionMenuPresenter::GetItemFromPosition(const FloatPoint& position)
1128 {
1129         _OptionMenuItemInfo itemInfo;
1130         int index = GetItemIndexFromPosition(position);
1131         itemInfo.pOptionMenuItem = __pModel->GetItem(index);
1132
1133         itemInfo.bListItem = false;
1134         itemInfo.pListItem = null;
1135         return itemInfo;
1136 }
1137
1138 _OptionMenuItemInfo
1139 _OptionMenuPresenter::FindItem(int index)
1140 {
1141         _OptionMenuItemInfo itemInfo;
1142         itemInfo.bListItem = false;
1143         itemInfo.pListItem = null;
1144         itemInfo.pOptionMenuItem = __pModel->GetItem(index);
1145         return itemInfo;
1146 }
1147
1148 result
1149 _OptionMenuPresenter::SetTopDrawnItemIndex(int index)
1150 {
1151         return E_SUCCESS;
1152 }
1153
1154 result
1155 _OptionMenuPresenter::DrawBitmap(Canvas& canvas, const FloatRectangle& bounds, const Bitmap& bitmap)
1156 {
1157         result r = E_SUCCESS;
1158         if (_BitmapImpl::CheckNinePatchedBitmapStrictly(bitmap))
1159         {
1160                 r = canvas.DrawNinePatchedBitmap(bounds, bitmap);
1161                 SysTryReturnResult(NID_UI_CTRL, r == E_SUCCESS, r, "Fail to draw ninepatched bitmap.");
1162         }
1163         else
1164         {
1165                 r = canvas.DrawBitmap(bounds, bitmap);
1166                 SysTryReturnResult(NID_UI_CTRL, r == E_SUCCESS, r, "Fail to draw bitmap.");
1167         }
1168
1169         return r;
1170 }
1171
1172 }}} // Tizen::Ui: Control