submenu crash fix in optionmenu
[platform/framework/native/uifw.git] / src / ui / controls / FUiCtrl_ContextMenuItem.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  * @file                FUiCtrl_ContextMenuItem.cpp
19  * @brief               This is the implementation file for the _ContextMenuItem class.
20  */
21
22 #include <FBaseSysLog.h>
23 #include <FGrp_BitmapImpl.h>
24 #include "FUi_AccessibilityContainer.h"
25 #include "FUi_AccessibilityElement.h"
26 #include "FUi_CoordinateSystemUtils.h"
27 #include "FUi_Math.h"
28 #include "FUi_ResourceManager.h"
29
30 #include "FUiCtrl_ScrollPanel.h"
31 #include "FUiCtrl_ContextMenuItem.h"
32
33 using namespace Tizen::Base;
34 using namespace Tizen::Graphics;
35 using namespace Tizen::Ui;
36
37 namespace {
38 static const float TOUCH_PRESS_THRESHOLD_INSENSITIVE = 0.16f;
39 }
40
41 namespace Tizen { namespace Ui { namespace Controls
42 {
43
44 _ContextMenuItem::_ContextMenuItem(void)
45         : __type(CONTEXT_MENU_ITEM_DRAWING_TYPE_NONE)
46         , __actionId(-1)
47         , __upperDividerLine(false)
48         , __lowerDividerLine(false)
49         , __selected(false)
50         , __parentScrollEnable(false)
51         , __leftMargin(0.0f)
52         , __rightMargin(0.0f)
53         , __dividerHeight(0.0f)
54         , __bgPressedMargin(0.0f)
55         , __textSize(0.0f)
56         , __text(L"")
57         , __pMagentaBgBitmap(null)
58         , __size(FloatDimension(0.0f, 0.0f))
59         , __drawRect(FloatRectangle(0.0f, 0.0f, 0.0f, 0.0f))
60         , __pBitmapLabel(null)
61         , __pTextLabel(null)
62         , __pUpperDividerLineLabel(null)
63         , __pBackgroundLabel(null)
64         , __pLowerDividerLineLabel(null)
65 {
66         __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_NORMAL] = null;
67         __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_PRESSED] = null;
68         __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_HIGHLIGHTED] = null;
69
70         GET_SHAPE_CONFIG(CONTEXTMENU::LIST_LEFT_MARGIN,  _CONTROL_ORIENTATION_PORTRAIT, __leftMargin);
71         GET_SHAPE_CONFIG(CONTEXTMENU::LIST_RIGHT_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, __rightMargin);
72         GET_SHAPE_CONFIG(CONTEXTMENU::LIST_DIVIDER_HEIGHT, _CONTROL_ORIENTATION_PORTRAIT, __dividerHeight);
73         GET_SHAPE_CONFIG(CONTEXTMENU::ITEM_BG_PRESSED_MARGIN, _CONTROL_ORIENTATION_PORTRAIT, __bgPressedMargin);
74
75         GET_COLOR_CONFIG(CONTEXTMENU::ITEM_BG_PRESSED, __selectedBgColor);
76         GET_COLOR_CONFIG(CONTEXTMENU::LIST_ITEM_DIVIDER_01_NORMAL, __lowerDividerLineColor);    // lower divider of item n and
77         GET_COLOR_CONFIG(CONTEXTMENU::LIST_ITEM_DIVIDER_02_NORMAL, __upperDividerLineColor);    // upper divider of item n+1 are bonded together.
78         GET_BITMAP_CONFIG_N(CONTEXTMENU::ITEM_BG_PRESSED, BITMAP_PIXEL_FORMAT_ARGB8888, __pMagentaBgBitmap);
79
80         InitializeAccessibilityElement();
81 }
82
83 _ContextMenuItem::~_ContextMenuItem(void)
84 {
85         if (__pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_NORMAL] != null)
86         {
87                 delete __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_NORMAL];
88                 __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_NORMAL] = null;
89         }
90
91         if (__pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_PRESSED] != null)
92         {
93                 delete __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_PRESSED];
94                 __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_PRESSED] = null;
95         }
96
97         if (__pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_HIGHLIGHTED] != null)
98         {
99                 delete __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_HIGHLIGHTED];
100                 __pBitmap[CONTEXT_MENU_ITEM_DRAWING_STATUS_HIGHLIGHTED] = null;
101         }
102
103         if (__pUpperDividerLineLabel != null)
104         {
105                 DetachChild(*__pUpperDividerLineLabel);
106                 delete __pUpperDividerLineLabel;
107                 __pUpperDividerLineLabel = null;
108         }
109
110         if (__pBackgroundLabel != null)
111         {
112                 DetachChild(*__pBackgroundLabel);
113                 delete __pBackgroundLabel;
114                 __pBackgroundLabel = null;
115         }
116
117         delete __pMagentaBgBitmap;
118         __pMagentaBgBitmap = null;
119
120         if (__pLowerDividerLineLabel != null)
121         {
122                 DetachChild(*__pLowerDividerLineLabel);
123                 delete __pLowerDividerLineLabel;
124                 __pLowerDividerLineLabel = null;
125         }
126
127         if (__pTextLabel != null)
128         {
129                 DetachChild(*__pTextLabel);
130                 delete __pTextLabel;
131                 __pTextLabel = null;
132         }
133
134         if (__pBitmapLabel != null)
135         {
136                 DetachChild(*__pBitmapLabel);
137                 delete __pBitmapLabel;
138                 __pBitmapLabel = null;
139         }
140
141         _AccessibilityContainer* pContainer = GetAccessibilityContainer();
142         if (pContainer)
143         {
144                 pContainer->RemoveAllElement();
145         }
146 }
147
148 _ContextMenuItem*
149 _ContextMenuItem::CreateContextMenuItemN(void)
150 {
151         ClearLastResult();
152
153         _ContextMenuItem* pItem = null;
154
155         pItem = new (std::nothrow) _ContextMenuItem();
156         if (pItem == null)
157         {
158                 SetLastResult(E_OUT_OF_MEMORY);
159                 return null;
160         }
161
162         pItem->AcquireHandle();
163
164         SetLastResult(E_SUCCESS);
165         return pItem;
166 }
167
168 void
169 _ContextMenuItem::InitializeAccessibilityElement(void)
170 {
171         _AccessibilityContainer* pContainer = GetAccessibilityContainer();
172         if (pContainer)
173         {
174                 pContainer->Activate(true);
175                 _AccessibilityElement* pElement = new (std::nothrow) _AccessibilityElement(true);
176                 SysTryReturnVoidResult(NID_UI_CTRL, pElement, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] Memory shortage.");
177
178                 pElement->SetTraitWithStringId("IDS_TPLATFORM_BODY_CONTEXTUAL_POP_UP_T_TTS");
179                 pElement->SetBounds(FloatRectangle(0.0f, 0.0f, GetBoundsF().width, GetBoundsF().height));
180                 pContainer->AddElement(*pElement);
181         }
182
183         return;
184 }
185
186 void
187 _ContextMenuItem::SetBitmapLabel(_Label* pLabel)
188 {
189         __pBitmapLabel = pLabel;
190 }
191
192 void
193 _ContextMenuItem::SetTextLabel(_Label* pLabel)
194 {
195         __pTextLabel = pLabel;
196 }
197
198
199 void
200 _ContextMenuItem::SetType(ContextMenuItemDrawingType type)
201 {
202         __type = type;
203 }
204
205 ContextMenuItemDrawingType
206 _ContextMenuItem::GetType(void) const
207 {
208         return __type;
209 }
210
211 void
212 _ContextMenuItem::SetActionId(int actionId)
213 {
214         __actionId = actionId;
215 }
216
217 int
218 _ContextMenuItem::GetActionId(void) const
219 {
220         return __actionId;
221 }
222
223 void
224 _ContextMenuItem::SetUpperDivider(bool drawDivider)
225 {
226         __upperDividerLine = drawDivider;
227 }
228
229 void
230 _ContextMenuItem::SetLowerDivider(bool drawDivider)
231 {
232         __lowerDividerLine = drawDivider;
233 }
234
235 bool
236 _ContextMenuItem::HasUpperDivider(void) const
237 {
238         return __upperDividerLine;
239 }
240
241 bool
242 _ContextMenuItem::HasLowerDivider(void) const
243 {
244         return __lowerDividerLine;
245 }
246
247 void
248 _ContextMenuItem::SetTextSize(float size)
249 {
250         __textSize = size;
251 }
252
253 result
254 _ContextMenuItem::SetText(const Tizen::Base::String& text)
255 {
256         if (text.GetLength() <= 0)
257         {
258                 return E_INVALID_ARG;
259         }
260
261         __text = text;
262
263         return E_SUCCESS;
264 }
265
266 const Tizen::Base::String&
267 _ContextMenuItem::GetText(void) const
268 {
269         return __text;
270 }
271
272 result
273 _ContextMenuItem::SetBitmap(ContextMenuItemDrawingStatus status, const Tizen::Graphics::Bitmap* pBitmap)
274 {
275         if (status < CONTEXT_MENU_ITEM_DRAWING_STATUS_NORMAL || status > CONTEXT_MENU_ITEM_DRAWING_STATUS_HIGHLIGHTED)
276         {
277                 return E_INVALID_ARG;
278         }
279
280         SysTryReturn(NID_UI_CTRL, (status != CONTEXT_MENU_ITEM_DRAWING_STATUS_NORMAL || pBitmap != null), E_INVALID_ARG,
281                                 E_INVALID_ARG,
282                                 "[E_INVALID_ARG] The normal bitmap must not be null.");
283
284         Bitmap* pClonedBitmap = _BitmapImpl::CloneN(*pBitmap);
285
286         // If bitmap is in _ContextMenuItem, delete old one.
287         if (__pBitmap[status] != null)
288         {
289                 delete __pBitmap[status];
290                 __pBitmap[status] = null;
291         }
292
293         __pBitmap[status] = pClonedBitmap;
294
295         return E_SUCCESS;
296 }
297
298 const Tizen::Graphics::Bitmap*
299 _ContextMenuItem::GetBitmap(ContextMenuItemDrawingStatus status) const
300 {
301         if (status < CONTEXT_MENU_ITEM_DRAWING_STATUS_NORMAL || status > CONTEXT_MENU_ITEM_DRAWING_STATUS_HIGHLIGHTED)
302         {
303                 return null;
304         }
305
306         return __pBitmap[status];
307 }
308
309 void
310 _ContextMenuItem::SetSize(Tizen::Graphics::FloatDimension size)
311 {
312         __size = size;
313 }
314
315 Tizen::Graphics::FloatDimension
316 _ContextMenuItem::GetSize(void) const
317 {
318         return __size;
319 }
320
321 void
322 _ContextMenuItem::SetDrawRect(Tizen::Graphics::FloatRectangle rect)
323 {
324         __drawRect = rect;
325
326 }
327
328 Tizen::Graphics::FloatRectangle
329 _ContextMenuItem::GetDrawRect(void) const
330 {
331         return __drawRect;
332 }
333
334 void
335 _ContextMenuItem::SetPressedDrawRect(Tizen::Graphics::FloatRectangle rect)
336 {
337         __pressedDrawRect = rect;
338
339 }
340
341 Tizen::Graphics::FloatRectangle
342 _ContextMenuItem::GetPressedDrawRect(void) const
343 {
344         return __pressedDrawRect;
345 }
346
347 int
348 _ContextMenuItem::Release(void)
349 {
350         delete this;
351
352         return 0;
353 }
354
355 void
356 _ContextMenuItem::OnBoundsChanged(void)
357 {
358         _AccessibilityContainer* pContainer = GetAccessibilityContainer();
359         if (pContainer)
360         {
361                 _AccessibilityElement* pElement = pContainer->GetChildElement(0);
362                 if (pElement)
363                 {
364                         pElement->SetBounds(FloatRectangle(0.0f, 0.0f, GetBoundsF().width, GetBoundsF().height));
365                 }
366         }
367 }
368
369 void
370 _ContextMenuItem::OnDraw(void)
371 {
372         DrawItem();
373 }
374
375 void
376 _ContextMenuItem::DrawItem(void)
377 {
378         if (__upperDividerLine)
379         {
380                 DrawItemUpperDivider();
381         }
382
383         if (__lowerDividerLine)
384         {
385                 DrawItemLowerDivider();
386         }
387
388         DrawItemBackground();
389 }
390
391 void
392 _ContextMenuItem::DrawItemUpperDivider(void)
393 {
394         if (__pUpperDividerLineLabel == null)
395         {
396                 __pUpperDividerLineLabel = _Label::CreateLabelN();
397                 SysTryReturnVoidResult(NID_UI_CTRL, __pUpperDividerLineLabel, E_OUT_OF_MEMORY, "[%s] Propagating.", GetErrorMessage(GetLastResult()));
398
399                 FloatRectangle bounds = GetBoundsF();
400                 __pUpperDividerLineLabel->SetBounds(FloatRectangle(__leftMargin, 0.0f, bounds.width - __leftMargin - __rightMargin, __dividerHeight));
401
402                 AttachChild(*__pUpperDividerLineLabel);
403
404                 _AccessibilityContainer* pContainer = __pUpperDividerLineLabel->GetAccessibilityContainer();
405                 if (pContainer)
406                 {
407                         pContainer->Activate(false);
408                 }
409         }
410
411         Color dividerLineColor = Color(0, 0, 0, 0);
412         if (__selected == false)
413         {
414                 dividerLineColor = __upperDividerLineColor;
415         }
416
417         __pUpperDividerLineLabel->SetBackgroundColor(dividerLineColor);
418         __pUpperDividerLineLabel->Invalidate();
419 }
420
421 void
422 _ContextMenuItem::DrawItemBackground(void)
423 {
424         float topMargin = 0.0f, bottomMargin = 0.0f;
425
426         SetBackgroundColor(Color(0, 0, 0, 0));
427
428         if (__pBackgroundLabel == null)
429         {
430                 __pBackgroundLabel = _Label::CreateLabelN();
431                 SysTryReturnVoidResult(NID_UI_CTRL, __pBackgroundLabel, E_OUT_OF_MEMORY, "[%s] Propagating.", GetErrorMessage(GetLastResult()));
432
433                 __pBackgroundLabel->SetTouchPressThreshold(TOUCH_PRESS_THRESHOLD_INSENSITIVE);
434                 AttachChild(*__pBackgroundLabel);
435                 MoveChildToBottom(*__pBackgroundLabel);
436
437                 _AccessibilityContainer* pContainer = __pBackgroundLabel->GetAccessibilityContainer();
438                 if (pContainer)
439                 {
440                         pContainer->Activate(false);
441                 }
442         }
443
444         Color color= Color(0, 0, 0, 0);
445         if (__selected == true)
446         {
447                 color = __selectedBgColor;
448         }
449
450         FloatRectangle bounds = GetBoundsF();
451         _ScrollPanel* pScrollPanel = static_cast<_ScrollPanel*>(GetParent());
452         FloatRectangle boundsScrollPanel = pScrollPanel->GetBoundsF();
453
454         float topOverlap = pScrollPanel->GetScrollPosition() - bounds.y;
455         if (topOverlap > 0.0f)
456         {
457                 topMargin = topOverlap + __bgPressedMargin;
458         }
459         else if (!__upperDividerLine)
460         {
461                 topMargin = __bgPressedMargin;
462         }
463
464         float bottomOverlap = bounds.y + bounds.height - (pScrollPanel->GetScrollPosition() + boundsScrollPanel.height);
465         if (bottomOverlap > 0.0f)
466         {
467                 bottomMargin = bottomOverlap + __bgPressedMargin;
468         }
469         else if (!__lowerDividerLine)
470         {
471                 bottomMargin = __bgPressedMargin;
472         }
473
474         __pBackgroundLabel->SetBounds(FloatRectangle(__bgPressedMargin, topMargin, bounds.width - __bgPressedMargin * 2.0f, bounds.height - topMargin - bottomMargin));
475
476         Bitmap* BgBitmap = _BitmapImpl::GetColorReplacedBitmapN(*__pMagentaBgBitmap, Color::GetColor(COLOR_ID_MAGENTA), color);
477         SysTryReturnVoidResult(NID_UI_CTRL, BgBitmap, E_OUT_OF_MEMORY, "[%s] Propagating.", GetErrorMessage(GetLastResult()));
478
479         __pBackgroundLabel->SetBackgroundBitmap(*BgBitmap);
480         delete BgBitmap;
481         BgBitmap = null;
482
483         __pBackgroundLabel->Invalidate();
484 }
485
486 void
487 _ContextMenuItem::DrawItemLowerDivider(void)
488 {
489         if (__pLowerDividerLineLabel == null)
490         {
491                 __pLowerDividerLineLabel = _Label::CreateLabelN();
492                 SysTryReturnVoidResult(NID_UI_CTRL, __pLowerDividerLineLabel, E_OUT_OF_MEMORY, "[%s] Propagating.", GetErrorMessage(GetLastResult()));
493
494                 FloatRectangle bounds = GetBoundsF();
495                 __pLowerDividerLineLabel->SetBounds(FloatRectangle(__leftMargin, bounds.height - __dividerHeight, bounds.width - __leftMargin - __rightMargin, __dividerHeight));
496
497                 AttachChild(*__pLowerDividerLineLabel);
498
499                 _AccessibilityContainer* pContainer = __pLowerDividerLineLabel->GetAccessibilityContainer();
500                 if (pContainer)
501                 {
502                         pContainer->Activate(false);
503                 }
504         }
505
506         Color dividerLineColor = Color(0, 0, 0, 0);
507         if (__selected == false)
508         {
509                 dividerLineColor = __lowerDividerLineColor;
510         }
511
512         __pLowerDividerLineLabel->SetBackgroundColor(dividerLineColor);
513         __pLowerDividerLineLabel->Invalidate();
514 }
515
516 _UiTouchEventDelivery
517 _ContextMenuItem::OnPreviewTouchPressed(const _Control& source, const _TouchInfo& touchinfo)
518 {
519         SetAndInvalidate(true);
520
521         return _UI_TOUCH_EVENT_DELIVERY_FORCED_YES;
522 }
523
524 bool
525 _ContextMenuItem::OnTouchPressed(const _Control& source, const _TouchInfo& touchinfo)
526 {
527         SetAndInvalidate(true);
528
529         return false;
530 }
531
532 _UiTouchEventDelivery
533 _ContextMenuItem::OnPreviewTouchMoved(const _Control& source, const _TouchInfo& touchinfo)
534 {
535         TouchMoved(source, touchinfo);
536
537         return _UI_TOUCH_EVENT_DELIVERY_FORCED_YES;
538 }
539
540 bool
541 _ContextMenuItem::OnTouchMoved(const _Control& source, const _TouchInfo& touchinfo)
542 {
543         TouchMoved(source, touchinfo);
544
545         return false;
546 }
547
548 _UiTouchEventDelivery
549 _ContextMenuItem::OnPreviewTouchReleased(const _Control& source, const _TouchInfo& touchinfo)
550 {
551         SetAndInvalidate(false);
552
553         return _UI_TOUCH_EVENT_DELIVERY_FORCED_YES;
554 }
555
556 bool
557 _ContextMenuItem::OnTouchReleased(const _Control& source, const _TouchInfo& touchinfo)
558 {
559         SetAndInvalidate(false);
560
561         return false;
562 }
563
564 _UiTouchEventDelivery
565 _ContextMenuItem::OnPreviewTouchCanceled(const _Control& source, const _TouchInfo& touchinfo)
566 {
567         return _UI_TOUCH_EVENT_DELIVERY_FORCED_YES;
568 }
569
570 bool
571 _ContextMenuItem::OnTouchCanceled(const _Control& source, const _TouchInfo& touchinfo)
572 {
573         SetAndInvalidate(false);
574
575         return false;
576 }
577
578 void
579 _ContextMenuItem::TouchMoved(const _Control& source, const _TouchInfo& touchinfo)
580 {
581         FloatPoint touchPosition = touchinfo.GetCurrentPosition();
582
583         if (__pressed)
584         {
585                 if (__parentScrollEnable)
586                 {
587                         if (__selected)
588                         {
589                                 __selected = false;
590                                 Invalidate();
591                         }
592                 }
593                 else
594                 {
595                         int oldSelected = __selected;
596
597                         FloatRectangle bounds(0.0f, 0.0f, __size.width, __size.height);
598                         if (bounds.Contains(touchPosition))
599                         {
600                                 __selected = true;
601                         }
602                         else
603                         {
604                                 __selected = false;
605                         }
606
607                         if (oldSelected != __selected)
608                         {
609                                 Invalidate();
610                         }
611                 }
612         }
613 }
614
615 void
616 _ContextMenuItem::OnFontChanged(Tizen::Graphics::Font* pFont)
617 {
618         String fontName = _Control::GetFont();
619
620         if (__pTextLabel != null)
621         {
622                 __pTextLabel->SetFont(fontName);
623         }
624 }
625
626 void
627 _ContextMenuItem::OnFontInfoRequested(unsigned long& style, float& size)
628 {
629         style = FONT_STYLE_PLAIN;
630         size = __textSize;
631 }
632
633 void
634 _ContextMenuItem::SetParentScrollEnable(bool enable)
635 {
636         __parentScrollEnable = enable;
637 }
638
639 bool
640 _ContextMenuItem::GetParentScrollEnable() const
641 {
642         return __parentScrollEnable;
643 }
644
645 bool
646 _ContextMenuItem::IsSelected() const
647 {
648         return __selected;
649 }
650
651 void
652 _ContextMenuItem::SetAndInvalidate(bool flag)
653 {
654         __selected = flag;
655         __pressed = flag;
656         Invalidate();
657 }
658
659 const Tizen::Graphics::Bitmap*
660 _ContextMenuItem::GetMagentaBgBitmap() const
661 {
662         return __pMagentaBgBitmap;
663 }
664
665 }}} // Tizen::Ui::Controls