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