1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4
5 #include "CGUIContextMenu.h"
6
7 #ifdef _IRR_COMPILE_WITH_GUI_
8
9 #include "IGUISkin.h"
10 #include "IGUIEnvironment.h"
11 #include "IVideoDriver.h"
12 #include "IGUIFont.h"
13 #include "IGUISpriteBank.h"
14 #include "os.h"
15
16 namespace irr
17 {
18 namespace gui
19 {
20
21
22 //! constructor
CGUIContextMenu(IGUIEnvironment * environment,IGUIElement * parent,s32 id,core::rect<s32> rectangle,bool getFocus,bool allowFocus)23 CGUIContextMenu::CGUIContextMenu(IGUIEnvironment* environment,
24 IGUIElement* parent, s32 id,
25 core::rect<s32> rectangle, bool getFocus, bool allowFocus)
26 : IGUIContextMenu(environment, parent, id, rectangle), EventParent(0), LastFont(0),
27 CloseHandling(ECMC_REMOVE), HighLighted(-1), ChangeTime(0), AllowFocus(allowFocus)
28 {
29 #ifdef _DEBUG
30 setDebugName("CGUIContextMenu");
31 #endif
32
33 Pos = rectangle.UpperLeftCorner;
34 recalculateSize();
35
36 if (getFocus)
37 Environment->setFocus(this);
38
39 setNotClipped(true);
40 }
41
42
43 //! destructor
~CGUIContextMenu()44 CGUIContextMenu::~CGUIContextMenu()
45 {
46 for (u32 i=0; i<Items.size(); ++i)
47 if (Items[i].SubMenu)
48 Items[i].SubMenu->drop();
49
50 if (LastFont)
51 LastFont->drop();
52 }
53
54 //! set behavior when menus are closed
setCloseHandling(ECONTEXT_MENU_CLOSE onClose)55 void CGUIContextMenu::setCloseHandling(ECONTEXT_MENU_CLOSE onClose)
56 {
57 CloseHandling = onClose;
58 }
59
60 //! get current behavior when the menue will be closed
getCloseHandling() const61 ECONTEXT_MENU_CLOSE CGUIContextMenu::getCloseHandling() const
62 {
63 return CloseHandling;
64 }
65
66 //! Returns amount of menu items
getItemCount() const67 u32 CGUIContextMenu::getItemCount() const
68 {
69 return Items.size();
70 }
71
72
73 //! Adds a menu item.
addItem(const wchar_t * text,s32 commandId,bool enabled,bool hasSubMenu,bool checked,bool autoChecking)74 u32 CGUIContextMenu::addItem(const wchar_t* text, s32 commandId, bool enabled, bool hasSubMenu, bool checked, bool autoChecking)
75 {
76 return insertItem(Items.size(), text, commandId, enabled, hasSubMenu, checked, autoChecking);
77 }
78
79 //! Insert a menu item at specified position.
insertItem(u32 idx,const wchar_t * text,s32 commandId,bool enabled,bool hasSubMenu,bool checked,bool autoChecking)80 u32 CGUIContextMenu::insertItem(u32 idx, const wchar_t* text, s32 commandId, bool enabled,
81 bool hasSubMenu, bool checked, bool autoChecking)
82 {
83 SItem s;
84 s.Enabled = enabled;
85 s.Checked = checked;
86 s.AutoChecking = autoChecking;
87 s.Text = text;
88 s.IsSeparator = (text == 0);
89 s.SubMenu = 0;
90 s.CommandId = commandId;
91
92 if (hasSubMenu)
93 {
94 s.SubMenu = new CGUIContextMenu(Environment, this, commandId,
95 core::rect<s32>(0,0,100,100), false, false);
96 s.SubMenu->setVisible(false);
97 }
98
99 u32 result = idx;
100 if ( idx < Items.size() )
101 {
102 Items.insert(s, idx);
103 }
104 else
105 {
106 Items.push_back(s);
107 result = Items.size() - 1;
108 }
109
110 recalculateSize();
111 return result;
112 }
113
findItemWithCommandId(s32 commandId,u32 idxStartSearch) const114 s32 CGUIContextMenu::findItemWithCommandId(s32 commandId, u32 idxStartSearch) const
115 {
116 for ( u32 i=idxStartSearch; i<Items.size(); ++i )
117 {
118 if ( Items[i].CommandId == commandId )
119 {
120 return (s32)i;
121 }
122 }
123 return -1;
124 }
125
126 //! Adds a sub menu from an element that already exists.
setSubMenu(u32 index,CGUIContextMenu * menu)127 void CGUIContextMenu::setSubMenu(u32 index, CGUIContextMenu* menu)
128 {
129 if (index >= Items.size())
130 return;
131
132 if (menu)
133 menu->grab();
134 if (Items[index].SubMenu)
135 Items[index].SubMenu->drop();
136
137 Items[index].SubMenu = menu;
138 menu->setVisible(false);
139
140 if (Items[index].SubMenu)
141 {
142 menu->AllowFocus = false;
143 if ( Environment->getFocus() == menu )
144 {
145 Environment->setFocus( this );
146 }
147 }
148
149 recalculateSize();
150 }
151
152
153 //! Adds a separator item to the menu
addSeparator()154 void CGUIContextMenu::addSeparator()
155 {
156 addItem(0, -1, true, false, false, false);
157 }
158
159
160 //! Returns text of the menu item.
getItemText(u32 idx) const161 const wchar_t* CGUIContextMenu::getItemText(u32 idx) const
162 {
163 if (idx >= Items.size())
164 return 0;
165
166 return Items[idx].Text.c_str();
167 }
168
169
170 //! Sets text of the menu item.
setItemText(u32 idx,const wchar_t * text)171 void CGUIContextMenu::setItemText(u32 idx, const wchar_t* text)
172 {
173 if (idx >= Items.size())
174 return;
175
176 Items[idx].Text = text;
177 recalculateSize();
178 }
179
180 //! should the element change the checked status on clicking
setItemAutoChecking(u32 idx,bool autoChecking)181 void CGUIContextMenu::setItemAutoChecking(u32 idx, bool autoChecking)
182 {
183 if ( idx >= Items.size())
184 return;
185
186 Items[idx].AutoChecking = autoChecking;
187 }
188
189 //! does the element change the checked status on clicking
getItemAutoChecking(u32 idx) const190 bool CGUIContextMenu::getItemAutoChecking(u32 idx) const
191 {
192 if (idx >= Items.size())
193 return false;
194
195 return Items[idx].AutoChecking;
196 }
197
198
199 //! Returns if a menu item is enabled
isItemEnabled(u32 idx) const200 bool CGUIContextMenu::isItemEnabled(u32 idx) const
201 {
202 if (idx >= Items.size())
203 {
204 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
205 return false;
206 }
207
208 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
209 return Items[idx].Enabled;
210 }
211
212
213 //! Returns if a menu item is checked
isItemChecked(u32 idx) const214 bool CGUIContextMenu::isItemChecked(u32 idx) const
215 {
216 if (idx >= Items.size())
217 {
218 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
219 return false;
220 }
221
222 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
223 return Items[idx].Checked;
224 }
225
226
227 //! Sets if the menu item should be enabled.
setItemEnabled(u32 idx,bool enabled)228 void CGUIContextMenu::setItemEnabled(u32 idx, bool enabled)
229 {
230 if (idx >= Items.size())
231 return;
232
233 Items[idx].Enabled = enabled;
234 }
235
236
237 //! Sets if the menu item should be checked.
setItemChecked(u32 idx,bool checked)238 void CGUIContextMenu::setItemChecked(u32 idx, bool checked )
239 {
240 if (idx >= Items.size())
241 return;
242
243 Items[idx].Checked = checked;
244 }
245
246
247 //! Removes a menu item
removeItem(u32 idx)248 void CGUIContextMenu::removeItem(u32 idx)
249 {
250 if (idx >= Items.size())
251 return;
252
253 if (Items[idx].SubMenu)
254 {
255 Items[idx].SubMenu->drop();
256 Items[idx].SubMenu = 0;
257 }
258
259 Items.erase(idx);
260 recalculateSize();
261 }
262
263
264 //! Removes all menu items
removeAllItems()265 void CGUIContextMenu::removeAllItems()
266 {
267 for (u32 i=0; i<Items.size(); ++i)
268 if (Items[i].SubMenu)
269 Items[i].SubMenu->drop();
270
271 Items.clear();
272 recalculateSize();
273 }
274
275
276 //! called if an event happened.
OnEvent(const SEvent & event)277 bool CGUIContextMenu::OnEvent(const SEvent& event)
278 {
279 if (isEnabled())
280 {
281
282 switch(event.EventType)
283 {
284 case EET_GUI_EVENT:
285 switch(event.GUIEvent.EventType)
286 {
287 case EGET_ELEMENT_FOCUS_LOST:
288 if (event.GUIEvent.Caller == this && !isMyChild(event.GUIEvent.Element) && AllowFocus)
289 {
290 // set event parent of submenus
291 IGUIElement * p = EventParent ? EventParent : Parent;
292 if ( p ) // can be 0 when element got removed already
293 {
294 setEventParent(p);
295
296 SEvent event;
297 event.EventType = EET_GUI_EVENT;
298 event.GUIEvent.Caller = this;
299 event.GUIEvent.Element = 0;
300 event.GUIEvent.EventType = EGET_ELEMENT_CLOSED;
301 if ( !p->OnEvent(event) )
302 {
303 if ( CloseHandling & ECMC_HIDE )
304 {
305 setVisible(false);
306 }
307 if ( CloseHandling & ECMC_REMOVE )
308 {
309 remove();
310 }
311 }
312 }
313
314 return false;
315 }
316 break;
317 case EGET_ELEMENT_FOCUSED:
318 if (event.GUIEvent.Caller == this && !AllowFocus)
319 {
320 return true;
321 }
322 break;
323 default:
324 break;
325 }
326 break;
327 case EET_MOUSE_INPUT_EVENT:
328 switch(event.MouseInput.Event)
329 {
330 case EMIE_LMOUSE_LEFT_UP:
331 {
332 // menu might be removed if it loses focus in sendClick, so grab a reference
333 grab();
334 const u32 t = sendClick(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y));
335 if ((t==0 || t==1) && Environment->hasFocus(this))
336 Environment->removeFocus(this);
337 drop();
338 }
339 return true;
340 case EMIE_LMOUSE_PRESSED_DOWN:
341 return true;
342 case EMIE_MOUSE_MOVED:
343 if (Environment->hasFocus(this))
344 highlight(core::position2d<s32>(event.MouseInput.X, event.MouseInput.Y), true);
345 return true;
346 default:
347 break;
348 }
349 break;
350 default:
351 break;
352 }
353 }
354
355 return IGUIElement::OnEvent(event);
356 }
357
358
359 //! Sets the visible state of this element.
setVisible(bool visible)360 void CGUIContextMenu::setVisible(bool visible)
361 {
362 HighLighted = -1;
363 ChangeTime = os::Timer::getTime();
364 for (u32 j=0; j<Items.size(); ++j)
365 if (Items[j].SubMenu)
366 Items[j].SubMenu->setVisible(false);
367
368 IGUIElement::setVisible(visible);
369 }
370
371
372 //! sends a click Returns:
373 //! 0 if click went outside of the element,
374 //! 1 if a valid button was clicked,
375 //! 2 if a nonclickable element was clicked
sendClick(const core::position2d<s32> & p)376 u32 CGUIContextMenu::sendClick(const core::position2d<s32>& p)
377 {
378 u32 t = 0;
379
380 // get number of open submenu
381 s32 openmenu = -1;
382 s32 j;
383 for (j=0; j<(s32)Items.size(); ++j)
384 if (Items[j].SubMenu && Items[j].SubMenu->isVisible())
385 {
386 openmenu = j;
387 break;
388 }
389
390 // delegate click operation to submenu
391 if (openmenu != -1)
392 {
393 t = Items[j].SubMenu->sendClick(p);
394 if (t != 0)
395 return t; // clicked something
396 }
397
398 // check click on myself
399 if (isPointInside(p) &&
400 (u32)HighLighted < Items.size())
401 {
402 if (!Items[HighLighted].Enabled ||
403 Items[HighLighted].IsSeparator ||
404 Items[HighLighted].SubMenu)
405 return 2;
406
407 if ( Items[HighLighted].AutoChecking )
408 {
409 Items[HighLighted].Checked = Items[HighLighted].Checked ? false : true;
410 }
411
412 SEvent event;
413 event.EventType = EET_GUI_EVENT;
414 event.GUIEvent.Caller = this;
415 event.GUIEvent.Element = 0;
416 event.GUIEvent.EventType = EGET_MENU_ITEM_SELECTED;
417 if (EventParent)
418 EventParent->OnEvent(event);
419 else if (Parent)
420 Parent->OnEvent(event);
421
422 return 1;
423 }
424
425 return 0;
426 }
427
428
429 //! returns true, if an element was highligted
highlight(const core::position2d<s32> & p,bool canOpenSubMenu)430 bool CGUIContextMenu::highlight(const core::position2d<s32>& p, bool canOpenSubMenu)
431 {
432 if (!isEnabled())
433 {
434 return false;
435 }
436
437 // get number of open submenu
438 s32 openmenu = -1;
439 s32 i;
440 for (i=0; i<(s32)Items.size(); ++i)
441 if (Items[i].Enabled && Items[i].SubMenu && Items[i].SubMenu->isVisible())
442 {
443 openmenu = i;
444 break;
445 }
446
447 // delegate highlight operation to submenu
448 if (openmenu != -1)
449 {
450 if (Items[openmenu].Enabled && Items[openmenu].SubMenu->highlight(p, canOpenSubMenu))
451 {
452 HighLighted = openmenu;
453 ChangeTime = os::Timer::getTime();
454 return true;
455 }
456 }
457
458 // highlight myself
459 for (i=0; i<(s32)Items.size(); ++i)
460 {
461 if (Items[i].Enabled && getHRect(Items[i], AbsoluteRect).isPointInside(p))
462 {
463 HighLighted = i;
464 ChangeTime = os::Timer::getTime();
465
466 // make submenus visible/invisible
467 for (s32 j=0; j<(s32)Items.size(); ++j)
468 if (Items[j].SubMenu)
469 {
470 if ( j == i && canOpenSubMenu && Items[j].Enabled )
471 Items[j].SubMenu->setVisible(true);
472 else if ( j != i )
473 Items[j].SubMenu->setVisible(false);
474 }
475 return true;
476 }
477 }
478
479 HighLighted = openmenu;
480 return false;
481 }
482
483
484 //! returns the item highlight-area
getHRect(const SItem & i,const core::rect<s32> & absolute) const485 core::rect<s32> CGUIContextMenu::getHRect(const SItem& i, const core::rect<s32>& absolute) const
486 {
487 core::rect<s32> r = absolute;
488 r.UpperLeftCorner.Y += i.PosY;
489 r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height;
490 return r;
491 }
492
493
494 //! Gets drawing rect of Item
getRect(const SItem & i,const core::rect<s32> & absolute) const495 core::rect<s32> CGUIContextMenu::getRect(const SItem& i, const core::rect<s32>& absolute) const
496 {
497 core::rect<s32> r = absolute;
498 r.UpperLeftCorner.Y += i.PosY;
499 r.LowerRightCorner.Y = r.UpperLeftCorner.Y + i.Dim.Height;
500 r.UpperLeftCorner.X += 20;
501 return r;
502 }
503
504
505 //! draws the element and its children
draw()506 void CGUIContextMenu::draw()
507 {
508 if (!IsVisible)
509 return;
510
511 IGUISkin* skin = Environment->getSkin();
512
513 if (!skin)
514 return;
515
516 IGUIFont* font = skin->getFont(EGDF_MENU);
517 if (font != LastFont)
518 {
519 if (LastFont)
520 LastFont->drop();
521 LastFont = font;
522 if (LastFont)
523 LastFont->grab();
524
525 recalculateSize();
526 }
527
528 IGUISpriteBank* sprites = skin->getSpriteBank();
529
530 core::rect<s32> rect = AbsoluteRect;
531 core::rect<s32>* clip = 0;
532
533 // draw frame
534 skin->draw3DMenuPane(this, AbsoluteRect, clip);
535
536 // loop through all menu items
537
538 rect = AbsoluteRect;
539 s32 y = AbsoluteRect.UpperLeftCorner.Y;
540
541 for (s32 i=0; i<(s32)Items.size(); ++i)
542 {
543 if (Items[i].IsSeparator)
544 {
545 // draw separator
546 rect = AbsoluteRect;
547 rect.UpperLeftCorner.Y += Items[i].PosY + 3;
548 rect.LowerRightCorner.Y = rect.UpperLeftCorner.Y + 1;
549 rect.UpperLeftCorner.X += 5;
550 rect.LowerRightCorner.X -= 5;
551 skin->draw2DRectangle(this, skin->getColor(EGDC_3D_SHADOW), rect, clip);
552
553 rect.LowerRightCorner.Y += 1;
554 rect.UpperLeftCorner.Y += 1;
555 skin->draw2DRectangle(this, skin->getColor(EGDC_3D_HIGH_LIGHT), rect, clip);
556
557 y += 10;
558 }
559 else
560 {
561 rect = getRect(Items[i], AbsoluteRect);
562
563 // draw highlighted
564
565 if (i == HighLighted && Items[i].Enabled)
566 {
567 core::rect<s32> r = AbsoluteRect;
568 r.LowerRightCorner.Y = rect.LowerRightCorner.Y;
569 r.UpperLeftCorner.Y = rect.UpperLeftCorner.Y;
570 r.LowerRightCorner.X -= 5;
571 r.UpperLeftCorner.X += 5;
572 skin->draw2DRectangle(this, skin->getColor(EGDC_HIGH_LIGHT), r, clip);
573 }
574
575 // draw text
576
577 EGUI_DEFAULT_COLOR c = EGDC_BUTTON_TEXT;
578
579 if (i == HighLighted)
580 c = EGDC_HIGH_LIGHT_TEXT;
581
582 if (!Items[i].Enabled)
583 c = EGDC_GRAY_TEXT;
584
585 if (font)
586 font->draw(Items[i].Text.c_str(), rect,
587 skin->getColor(c), false, true, clip);
588
589 // draw submenu symbol
590 if (Items[i].SubMenu && sprites)
591 {
592 core::rect<s32> r = rect;
593 r.UpperLeftCorner.X = r.LowerRightCorner.X - 15;
594
595 sprites->draw2DSprite(skin->getIcon(EGDI_CURSOR_RIGHT),
596 r.getCenter(), clip, skin->getColor(c),
597 (i == HighLighted) ? ChangeTime : 0,
598 (i == HighLighted) ? os::Timer::getTime() : 0,
599 (i == HighLighted), true);
600 }
601
602 // draw checked symbol
603 if (Items[i].Checked && sprites)
604 {
605 core::rect<s32> r = rect;
606 r.LowerRightCorner.X = r.UpperLeftCorner.X - 15;
607 r.UpperLeftCorner.X = r.LowerRightCorner.X + 15;
608 sprites->draw2DSprite(skin->getIcon(EGDI_CHECK_BOX_CHECKED),
609 r.getCenter(), clip, skin->getColor(c),
610 (i == HighLighted) ? ChangeTime : 0,
611 (i == HighLighted) ? os::Timer::getTime() : 0,
612 (i == HighLighted), true);
613 }
614 }
615 }
616
617 IGUIElement::draw();
618 }
619
620
recalculateSize()621 void CGUIContextMenu::recalculateSize()
622 {
623 IGUIFont* font = Environment->getSkin()->getFont(EGDF_MENU);
624
625 if (!font)
626 return;
627
628 core::rect<s32> rect;
629 rect.UpperLeftCorner = RelativeRect.UpperLeftCorner;
630 u32 width = 100;
631 u32 height = 3;
632
633 u32 i;
634 for (i=0; i<Items.size(); ++i)
635 {
636 if (Items[i].IsSeparator)
637 {
638 Items[i].Dim.Width = 100;
639 Items[i].Dim.Height = 10;
640 }
641 else
642 {
643 Items[i].Dim = font->getDimension(Items[i].Text.c_str());
644 Items[i].Dim.Width += 40;
645
646 if (Items[i].Dim.Width > width)
647 width = Items[i].Dim.Width;
648 }
649
650 Items[i].PosY = height;
651 height += Items[i].Dim.Height;
652 }
653
654 height += 5;
655
656 if (height < 10)
657 height = 10;
658
659 rect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + width;
660 rect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + height;
661
662 setRelativePosition(rect);
663
664 // recalculate submenus
665 for (i=0; i<Items.size(); ++i)
666 {
667 if (Items[i].SubMenu)
668 {
669 // move submenu
670 const s32 w = Items[i].SubMenu->getAbsolutePosition().getWidth();
671 const s32 h = Items[i].SubMenu->getAbsolutePosition().getHeight();
672
673 core::rect<s32> subRect(width-5, Items[i].PosY, width+w-5, Items[i].PosY+h);
674
675 // if it would be drawn beyond the right border, then add it to the left side
676 gui::IGUIElement * root = Environment->getRootGUIElement();
677 if ( root )
678 {
679 core::rect<s32> rectRoot( root->getAbsolutePosition() );
680 if ( getAbsolutePosition().UpperLeftCorner.X+subRect.LowerRightCorner.X > rectRoot.LowerRightCorner.X )
681 {
682 subRect.UpperLeftCorner.X = -w;
683 subRect.LowerRightCorner.X = 0;
684 }
685 }
686
687 Items[i].SubMenu->setRelativePosition(subRect);
688 }
689 }
690 }
691
692
693 //! Returns the selected item in the menu
getSelectedItem() const694 s32 CGUIContextMenu::getSelectedItem() const
695 {
696 return HighLighted;
697 }
698
699
700 //! \return Returns a pointer to the submenu of an item.
getSubMenu(u32 idx) const701 IGUIContextMenu* CGUIContextMenu::getSubMenu(u32 idx) const
702 {
703 if (idx >= Items.size())
704 return 0;
705
706 return Items[idx].SubMenu;
707 }
708
709
710 //! Returns command id of a menu item
getItemCommandId(u32 idx) const711 s32 CGUIContextMenu::getItemCommandId(u32 idx) const
712 {
713 if (idx >= Items.size())
714 return -1;
715
716 return Items[idx].CommandId;
717 }
718
719
720 //! Sets the command id of a menu item
setItemCommandId(u32 idx,s32 id)721 void CGUIContextMenu::setItemCommandId(u32 idx, s32 id)
722 {
723 if (idx >= Items.size())
724 return;
725
726 Items[idx].CommandId = id;
727 }
728
729
730 //! Writes attributes of the element.
serializeAttributes(io::IAttributes * out,io::SAttributeReadWriteOptions * options=0) const731 void CGUIContextMenu::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const
732 {
733 IGUIElement::serializeAttributes(out,options);
734 out->addPosition2d("Position", Pos);
735
736 if (Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU )
737 {
738 const IGUIContextMenu* const ptr = (const IGUIContextMenu*)Parent;
739 // find the position of this item in its parent's list
740 u32 i;
741 // VC6 needs the cast for this
742 for (i=0; (i<ptr->getItemCount()) && (ptr->getSubMenu(i) != (const IGUIContextMenu*)this); ++i)
743 ; // do nothing
744
745 out->addInt("ParentItem", i);
746 }
747
748 out->addInt("CloseHandling", (s32)CloseHandling);
749
750 // write out the item list
751 out->addInt("ItemCount", Items.size());
752
753 core::stringc tmp;
754
755 for (u32 i=0; i < Items.size(); ++i)
756 {
757 tmp = "IsSeparator"; tmp += i;
758 out->addBool(tmp.c_str(), Items[i].IsSeparator);
759
760 if (!Items[i].IsSeparator)
761 {
762 tmp = "Text"; tmp += i;
763 out->addString(tmp.c_str(), Items[i].Text.c_str());
764 tmp = "CommandID"; tmp += i;
765 out->addInt(tmp.c_str(), Items[i].CommandId);
766 tmp = "Enabled"; tmp += i;
767 out->addBool(tmp.c_str(), Items[i].Enabled);
768 tmp = "Checked"; tmp += i;
769 out->addBool(tmp.c_str(), Items[i].Checked);
770 tmp = "AutoChecking"; tmp += i;
771 out->addBool(tmp.c_str(), Items[i].AutoChecking);
772 }
773 }
774 }
775
776
777 //! Reads attributes of the element
deserializeAttributes(io::IAttributes * in,io::SAttributeReadWriteOptions * options=0)778 void CGUIContextMenu::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0)
779 {
780 IGUIElement::deserializeAttributes(in,options);
781
782 Pos = in->getAttributeAsPosition2d("Position");
783
784 // link to this item's parent
785 if (Parent && ( Parent->getType() == EGUIET_CONTEXT_MENU || Parent->getType() == EGUIET_MENU ) )
786 ((CGUIContextMenu*)Parent)->setSubMenu(in->getAttributeAsInt("ParentItem"),this);
787
788 CloseHandling = (ECONTEXT_MENU_CLOSE)in->getAttributeAsInt("CloseHandling");
789
790 removeAllItems();
791
792 // read the item list
793 const s32 count = in->getAttributeAsInt("ItemCount");
794
795 for (s32 i=0; i<count; ++i)
796 {
797 core::stringc tmp;
798 core::stringw txt;
799 s32 commandid=-1;
800 bool enabled=true;
801 bool checked=false;
802 bool autochecking=false;
803
804 tmp = "IsSeparator"; tmp += i;
805 if ( in->existsAttribute(tmp.c_str()) && in->getAttributeAsBool(tmp.c_str()) )
806 addSeparator();
807 else
808 {
809 tmp = "Text"; tmp += i;
810 if ( in->existsAttribute(tmp.c_str()) )
811 txt = in->getAttributeAsStringW(tmp.c_str());
812
813 tmp = "CommandID"; tmp += i;
814 if ( in->existsAttribute(tmp.c_str()) )
815 commandid = in->getAttributeAsInt(tmp.c_str());
816
817 tmp = "Enabled"; tmp += i;
818 if ( in->existsAttribute(tmp.c_str()) )
819 enabled = in->getAttributeAsBool(tmp.c_str());
820
821 tmp = "Checked"; tmp += i;
822 if ( in->existsAttribute(tmp.c_str()) )
823 checked = in->getAttributeAsBool(tmp.c_str());
824
825 tmp = "AutoChecking"; tmp += i;
826 if ( in->existsAttribute(tmp.c_str()) )
827 autochecking = in->getAttributeAsBool(tmp.c_str());
828
829 addItem(core::stringw(txt.c_str()).c_str(), commandid, enabled, false, checked, autochecking);
830 }
831 }
832
833 recalculateSize();
834 }
835
836
837 // because sometimes the element has no parent at click time
setEventParent(IGUIElement * parent)838 void CGUIContextMenu::setEventParent(IGUIElement *parent)
839 {
840 EventParent = parent;
841
842 for (u32 i=0; i<Items.size(); ++i)
843 if (Items[i].SubMenu)
844 Items[i].SubMenu->setEventParent(parent);
845 }
846
847
hasOpenSubMenu() const848 bool CGUIContextMenu::hasOpenSubMenu() const
849 {
850 for (u32 i=0; i<Items.size(); ++i)
851 if (Items[i].SubMenu && Items[i].SubMenu->isVisible())
852 return true;
853
854 return false;
855 }
856
857
closeAllSubMenus()858 void CGUIContextMenu::closeAllSubMenus()
859 {
860 for (u32 i=0; i<Items.size(); ++i)
861 if (Items[i].SubMenu)
862 Items[i].SubMenu->setVisible(false);
863
864 //HighLighted = -1;
865 }
866
867
868 } // end namespace
869 } // end namespace
870
871 #endif // _IRR_COMPILE_WITH_GUI_
872
873