1 /*
2  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3  * Distributed under the MIT License
4  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5  */
6 
7 #include "MyGUI_Precompiled.h"
8 #include "MyGUI_MenuControl.h"
9 #include "MyGUI_ResourceSkin.h"
10 #include "MyGUI_MenuItem.h"
11 #include "MyGUI_ImageBox.h"
12 #include "MyGUI_MenuBar.h"
13 #include "MyGUI_WidgetManager.h"
14 #include "MyGUI_LayerManager.h"
15 #include "MyGUI_ControllerManager.h"
16 #include "MyGUI_InputManager.h"
17 #include "MyGUI_Gui.h"
18 #include "MyGUI_RenderManager.h"
19 
20 namespace MyGUI
21 {
22 
23 	const float POPUP_MENU_SPEED_COEF = 3.0f;
24 
MenuControl()25 	MenuControl::MenuControl() :
26 		mHideByAccept(true),
27 		mMenuDropMode(false),
28 		mIsMenuDrop(true),
29 		mHideByLostKey(false),
30 		mResizeToContent(true),
31 		mShutdown(false),
32 		mVerticalAlignment(true),
33 		mDistanceButton(0),
34 		mPopupAccept(false),
35 		mOwner(nullptr),
36 		mAnimateSmooth(false),
37 		mChangeChildSkin(false),
38 		mInternalCreateChild(false)
39 	{
40 	}
41 
initialiseOverride()42 	void MenuControl::initialiseOverride()
43 	{
44 		Base::initialiseOverride();
45 
46 		// инициализируем овнера
47 		Widget* parent = getParent();
48 		if (parent)
49 		{
50 			mOwner = parent->castType<MenuItem>(false);
51 			if (!mOwner)
52 			{
53 				Widget* client = parent;
54 				parent = client->getParent();
55 				if (parent && parent->getClientWidget())
56 				{
57 					mOwner = parent->castType<MenuItem>(false);
58 				}
59 			}
60 		}
61 
62 		// FIXME нам нужен фокус клавы
63 		setNeedKeyFocus(true);
64 
65 		//OBSOLETE
66 		if (isUserString("SkinLine"))
67 		{
68 			mItemNormalSkin = getUserString("SkinLine");
69 			mItemPopupSkin = mItemNormalSkin;
70 		}
71 
72 		if (isUserString("SeparatorSkin"))
73 			mItemSeparatorSkin = getUserString("SeparatorSkin");
74 
75 		if (isUserString("NormalSkin"))
76 			mItemNormalSkin = getUserString("NormalSkin");
77 
78 		if (isUserString("PopupSkin"))
79 			mItemPopupSkin = getUserString("PopupSkin");
80 
81 		if (isUserString("DistanceButton"))
82 			mDistanceButton = utility::parseValue<int>(getUserString("DistanceButton"));
83 
84 		if (isUserString("SubMenuSkin"))
85 			mSubMenuSkin = getUserString("SubMenuSkin");
86 
87 		if (isUserString("SubMenuLayer"))
88 			mSubMenuLayer = getUserString("SubMenuLayer");
89 
90 		// FIXME добавленно, так как шетдаун вызывается и при смене скина
91 		mShutdown = false;
92 	}
93 
shutdownOverride()94 	void MenuControl::shutdownOverride()
95 	{
96 		mShutdown = true;
97 
98 		if (mOwner != nullptr)
99 			mOwner->getMenuCtrlParent()->_notifyDeletePopup(mOwner);
100 
101 		Base::shutdownOverride();
102 	}
103 
onWidgetCreated(Widget * _widget)104 	void MenuControl::onWidgetCreated(Widget* _widget)
105 	{
106 		Base::onWidgetCreated(_widget);
107 
108 		MenuItem* child = _widget->castType<MenuItem>(false);
109 		if (child != nullptr && !mInternalCreateChild)
110 		{
111 			_wrapItem(child, mItemsInfo.size(), "", MenuItemType::Normal, "", Any::Null);
112 		}
113 	}
114 
insertItemAt(size_t _index,const UString & _name,MenuItemType _type,const std::string & _id,Any _data)115 	MenuItem* MenuControl::insertItemAt(size_t _index, const UString& _name, MenuItemType _type, const std::string& _id, Any _data)
116 	{
117 		MYGUI_ASSERT_RANGE_INSERT(_index, mItemsInfo.size(), "MenuControl::insertItemAt");
118 		if (_index == ITEM_NONE) _index = mItemsInfo.size();
119 
120 		mInternalCreateChild = true;
121 		MenuItem* item = _getClientWidget()->createWidget<MenuItem>(getSkinByType(_type), IntCoord(), Align::Default);
122 		mInternalCreateChild = false;
123 		_wrapItem(item, _index, _name, _type, _id, _data);
124 
125 		return item;
126 	}
127 
removeItemAt(size_t _index)128 	void MenuControl::removeItemAt(size_t _index)
129 	{
130 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::removeItemAt");
131 
132 		if (mItemsInfo[_index].submenu)
133 		{
134 			WidgetManager::getInstance().destroyWidget(mItemsInfo[_index].submenu);
135 			mItemsInfo[_index].submenu = nullptr;
136 		}
137 		WidgetManager::getInstance().destroyWidget(mItemsInfo[_index].item);
138 	}
139 
removeAllItems()140 	void MenuControl::removeAllItems()
141 	{
142 		while (!mItemsInfo.empty())
143 		{
144 			if (mItemsInfo.back().submenu)
145 			{
146 				WidgetManager::getInstance().destroyWidget(mItemsInfo.back().submenu);
147 				mItemsInfo.back().submenu = nullptr;
148 			}
149 			WidgetManager::getInstance().destroyWidget(mItemsInfo.back().item);
150 		}
151 	}
152 
getItemNameAt(size_t _index)153 	const UString& MenuControl::getItemNameAt(size_t _index)
154 	{
155 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::getItemNameAt");
156 		return mItemsInfo[_index].name;
157 	}
158 
update()159 	void MenuControl::update()
160 	{
161 		IntSize size;
162 
163 		if (mVerticalAlignment)
164 		{
165 			for (VectorMenuItemInfo::iterator iter = mItemsInfo.begin(); iter != mItemsInfo.end(); ++iter)
166 			{
167 				IntSize contentSize = iter->item->_getContentSize();
168 				iter->item->setCoord(0, size.height, _getClientWidget()->getWidth(), contentSize.height);
169 				size.height += contentSize.height + mDistanceButton;
170 
171 				if (contentSize.width > size.width)
172 					size.width = contentSize.width;
173 			}
174 			if (!mItemsInfo.empty())
175 				size.height -= mDistanceButton;
176 		}
177 		else
178 		{
179 			int maxHeight = 0;
180 			for (VectorMenuItemInfo::iterator iter = mItemsInfo.begin(); iter != mItemsInfo.end(); ++iter)
181 			{
182 				IntSize contentSize = iter->item->_getContentSize();
183 				if (maxHeight < contentSize.height)
184 					maxHeight = contentSize.height;
185 			}
186 
187 			for (VectorMenuItemInfo::iterator iter = mItemsInfo.begin(); iter != mItemsInfo.end(); ++iter)
188 			{
189 				IntSize contentSize = iter->item->_getContentSize();
190 				iter->item->setCoord(size.width, 0, contentSize.width, maxHeight);
191 				size.width += contentSize.width + mDistanceButton;
192 			}
193 
194 			if (!mItemsInfo.empty())
195 				size.width -= mDistanceButton;
196 		}
197 
198 		if (mResizeToContent)
199 			setSize(size + mCoord.size() - _getClientWidget()->getSize());
200 	}
201 
setItemDataAt(size_t _index,Any _data)202 	void MenuControl::setItemDataAt(size_t _index, Any _data)
203 	{
204 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::setItemDataAt");
205 		mItemsInfo[_index].data = _data;
206 	}
207 
getItemChildAt(size_t _index)208 	MenuControl* MenuControl::getItemChildAt(size_t _index)
209 	{
210 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::getItemChildAt");
211 		return mItemsInfo[_index].submenu;
212 	}
213 
removeItemChildAt(size_t _index)214 	void MenuControl::removeItemChildAt(size_t _index)
215 	{
216 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::removeItemChildAt");
217 
218 		if (mItemsInfo[_index].submenu != nullptr)
219 		{
220 			WidgetManager::getInstance().destroyWidget(mItemsInfo[_index].submenu);
221 			mItemsInfo[_index].submenu = nullptr;
222 		}
223 
224 		update();
225 	}
226 
setItemNameAt(size_t _index,const UString & _name)227 	void MenuControl::setItemNameAt(size_t _index, const UString& _name)
228 	{
229 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::setItemNameAt");
230 
231 		mItemsInfo[_index].name = _name;
232 		MenuItem* item = mItemsInfo[_index].item;
233 		item->setCaption(_name);
234 
235 		update();
236 	}
237 
setItemIdAt(size_t _index,const std::string & _id)238 	void MenuControl::setItemIdAt(size_t _index, const std::string& _id)
239 	{
240 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::setItemIdAt");
241 		mItemsInfo[_index].id = _id;
242 	}
243 
getItemIdAt(size_t _index)244 	const std::string& MenuControl::getItemIdAt(size_t _index)
245 	{
246 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::getItemIdAt");
247 		return mItemsInfo[_index].id;
248 	}
249 
_notifyDeleteItem(MenuItem * _item)250 	void MenuControl::_notifyDeleteItem(MenuItem* _item)
251 	{
252 		// дитю меняем скин
253 		if (mChangeChildSkin)
254 			return;
255 
256 		// общий шутдаун виджета
257 		if (mShutdown)
258 			return;
259 
260 		size_t index = getItemIndex(_item);
261 		mItemsInfo.erase(mItemsInfo.begin() + index);
262 		update();
263 	}
264 
_notifyDeletePopup(MenuItem * _item)265 	void MenuControl::_notifyDeletePopup(MenuItem* _item)
266 	{
267 		size_t index = getItemIndex(_item);
268 		mItemsInfo[index].submenu = nullptr;
269 	}
270 
_notifyUpdateName(MenuItem * _item)271 	void MenuControl::_notifyUpdateName(MenuItem* _item)
272 	{
273 		size_t index = getItemIndex(_item);
274 		mItemsInfo[index].name = _item->getCaption();
275 
276 		ISubWidgetText* text = _item->getSubWidgetText();
277 		mItemsInfo[index].width = text ? (text->getTextSize().width + _item->getSize().width - text->getWidth()) : 0;
278 		update();
279 	}
280 
getItemTypeAt(size_t _index)281 	MenuItemType MenuControl::getItemTypeAt(size_t _index)
282 	{
283 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::getItemTypeAt");
284 		return mItemsInfo[_index].type;
285 	}
286 
setItemTypeAt(size_t _index,MenuItemType _type)287 	void MenuControl::setItemTypeAt(size_t _index, MenuItemType _type)
288 	{
289 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::setItemTypeAt");
290 		ItemInfo& info = mItemsInfo[_index];
291 		if (info.type == _type)
292 			return;
293 
294 		// сохраняем данные
295 		info.type = _type;
296 
297 		// при смене скина дите отпишется
298 		mChangeChildSkin = true;
299 		info.item->changeWidgetSkin(getSkinByType(_type));
300 		mChangeChildSkin = false;
301 
302 		info.item->setImageName(getIconIndexByType(_type ));
303 		info.item->setCaption(info.name);
304 
305 		update();
306 	}
307 
notifyMenuCtrlAccept(MenuItem * _item)308 	void MenuControl::notifyMenuCtrlAccept(MenuItem* _item)
309 	{
310 		if (mHideByAccept)
311 		{
312 			setVisibleSmooth(false);
313 		}
314 		else
315 		{
316 			InputManager::getInstance().setKeyFocusWidget(nullptr);
317 		}
318 
319 		MenuItem* parent_item = getMenuItemParent();
320 		if (parent_item)
321 		{
322 			MenuControl* parent_ctrl = parent_item->getMenuCtrlParent();
323 			if (parent_ctrl)
324 			{
325 				parent_ctrl->notifyMenuCtrlAccept(_item);
326 			}
327 		}
328 
329 		eventMenuCtrlAccept(this, _item);
330 	}
331 
setItemChildVisibleAt(size_t _index,bool _visible)332 	void MenuControl::setItemChildVisibleAt(size_t _index, bool _visible)
333 	{
334 		_setItemChildVisibleAt(_index, _visible, true);
335 	}
336 
_setItemChildVisibleAt(size_t _index,bool _visible,bool _smooth)337 	void MenuControl::_setItemChildVisibleAt(size_t _index, bool _visible, bool _smooth)
338 	{
339 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::setItemChildVisibleAt");
340 
341 		if (_visible)
342 		{
343 			if (mItemsInfo[_index].submenu && mItemsInfo[_index].submenu->getItemCount())
344 			{
345 				int offset = mItemsInfo[0].item->getAbsoluteTop() - getAbsoluteTop();
346 
347 				const IntCoord& coord = mItemsInfo[_index].item->getAbsoluteCoord();
348 				IntPoint point(getAbsoluteRect().right, coord.top - offset);
349 
350 				MenuControl* menu = mItemsInfo[_index].submenu;
351 
352 				if (mVerticalAlignment)
353 				{
354 					// too wide
355 					if (point.left + menu->getWidth() > menu->getParentSize().width)
356 					{
357 						// move to the left side if possible
358 						if (point.left - menu->getWidth() - getWidth() > 0)
359 							point.left -= menu->getWidth() + getWidth();
360 						// or put near right parent border (window) if too wide for left side too
361 						else
362 							point.left = menu->getParentSize().width - menu->getWidth();
363 					}
364 					// too high (same logic as for too wide)
365 					if (point.top + menu->getHeight() > menu->getParentSize().height)
366 					{
367 						// move to the top side if possible
368 						if (point.top - menu->getHeight() - getHeight() > 0)
369 							point.top -= menu->getHeight() + getHeight();
370 						// or put near bottom parent border (window) if too high for top side too
371 						else
372 							point.top = menu->getParentSize().height - menu->getHeight();
373 					}
374 				}
375 				else
376 				{
377 					point.set(coord.left, getAbsoluteRect().bottom);
378 				}
379 
380 				menu->setPosition(point);
381 				if (_smooth)
382 					menu->setVisibleSmooth(true);
383 				else
384 					menu->setVisible(true);
385 
386 				MyGUI::LayerManager::getInstance().upLayerItem(menu);
387 			}
388 		}
389 		else
390 		{
391 			if (mItemsInfo[_index].submenu)
392 			{
393 				if (_smooth)
394 					mItemsInfo[_index].submenu->setVisibleSmooth(false);
395 				else
396 					mItemsInfo[_index].submenu->setVisible(false);
397 			}
398 		}
399 	}
400 
notifyRootKeyChangeFocus(Widget * _sender,bool _focus)401 	void MenuControl::notifyRootKeyChangeFocus(Widget* _sender, bool _focus)
402 	{
403 		MenuItem* item = _sender->castType<MenuItem>();
404 		if (item->getItemType() == MenuItemType::Popup)
405 		{
406 			if (_focus)
407 			{
408 				if (!mMenuDropMode || mIsMenuDrop)
409 				{
410 					item->setItemChildVisible(true);
411 					item->setStateSelected(true);
412 				}
413 			}
414 			else
415 			{
416 				item->setItemChildVisible(false);
417 				item->setStateSelected(false);
418 			}
419 		}
420 	}
421 
createItemChildByType(size_t _index,const std::string & _type)422 	Widget* MenuControl::createItemChildByType(size_t _index, const std::string& _type)
423 	{
424 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::createItemChildByType");
425 		removeItemChildAt(_index);
426 		Widget* child = mItemsInfo[_index].item->createWidgetT(WidgetStyle::Popup, _type, mSubMenuSkin, IntCoord(), Align::Default, mSubMenuLayer);
427 		MYGUI_ASSERT(child->isType<MenuControl>(), "child must have MenuControl base type");
428 		return child;
429 	}
430 
notifyMouseButtonClick(Widget * _sender)431 	void MenuControl::notifyMouseButtonClick(Widget* _sender)
432 	{
433 		MenuItem* item = _sender->castType<MenuItem>();
434 		if (mMenuDropMode)
435 		{
436 			if (mIsMenuDrop)
437 			{
438 				if (item->getItemType() == MenuItemType::Popup)
439 				{
440 					item->setStateSelected(false);
441 					item->setItemChildVisible(false);
442 					mIsMenuDrop = false;
443 				}
444 			}
445 			else
446 			{
447 				if (item->getItemType() == MenuItemType::Popup)
448 				{
449 					mIsMenuDrop = true;
450 					item->setStateSelected(true);
451 					item->setItemChildVisible(true);
452 					InputManager::getInstance().setKeyFocusWidget(item);
453 				}
454 			}
455 		}
456 		else
457 		{
458 			if ((item->getItemType() == MenuItemType::Popup && mPopupAccept) ||
459 				item->getItemType() == MenuItemType::Normal)
460 			{
461 				notifyMenuCtrlAccept(item);
462 			}
463 		}
464 	}
465 
onKeyChangeRootFocus(bool _focus)466 	void MenuControl::onKeyChangeRootFocus(bool _focus)
467 	{
468 		if (mMenuDropMode)
469 		{
470 			mIsMenuDrop = false;
471 		}
472 		if (!_focus && mHideByLostKey)
473 		{
474 			setVisibleSmooth(false);
475 			eventMenuCtrlClose(this);
476 		}
477 		Base::onKeyChangeRootFocus(_focus);
478 	}
479 
notifyMouseSetFocus(Widget * _sender,Widget * _new)480 	void MenuControl::notifyMouseSetFocus(Widget* _sender, Widget* _new)
481 	{
482 		InputManager::getInstance().setKeyFocusWidget(_sender);
483 	}
484 
_wrapItemChild(MenuItem * _item,MenuControl * _widget)485 	void MenuControl::_wrapItemChild(MenuItem* _item, MenuControl* _widget)
486 	{
487 		// заменяем
488 		size_t index = getItemIndex(_item);
489 		if (mItemsInfo[index].submenu != nullptr)
490 		{
491 			WidgetManager::getInstance().destroyWidget(mItemsInfo[index].submenu);
492 			mItemsInfo[index].submenu = nullptr;
493 		}
494 		mItemsInfo[index].submenu = _widget;
495 		// скрываем менюшку
496 		mItemsInfo[index].submenu->setVisible(false);
497 
498 		update();
499 	}
500 
_wrapItem(MenuItem * _item,size_t _index,const UString & _name,MenuItemType _type,const std::string & _id,Any _data)501 	void MenuControl::_wrapItem(MenuItem* _item, size_t _index, const UString& _name, MenuItemType _type, const std::string& _id, Any _data)
502 	{
503 		_item->setAlign(mVerticalAlignment ? Align::Top | Align::HStretch : Align::Default);
504 		_item->eventRootKeyChangeFocus += newDelegate(this, &MenuControl::notifyRootKeyChangeFocus);
505 		_item->eventMouseButtonClick += newDelegate(this, &MenuControl::notifyMouseButtonClick);
506 		_item->eventMouseSetFocus += newDelegate(this, &MenuControl::notifyMouseSetFocus);
507 
508 		_item->setImageName(getIconIndexByType(_type ));
509 
510 		MenuControl* submenu = nullptr;
511 
512 		ItemInfo info = ItemInfo(_item, _name, _type, submenu, _id, _data);
513 
514 		mItemsInfo.insert(mItemsInfo.begin() + _index, info);
515 
516 		mChangeChildSkin = true;
517 		_item->changeWidgetSkin(getSkinByType(_type));
518 		mChangeChildSkin = false;
519 
520 		// его сет капшен, обновит размер
521 		_item->setCaption(_name);
522 
523 		update();
524 	}
525 
setVisible(bool _visible)526 	void MenuControl::setVisible(bool _visible)
527 	{
528 		if (mAnimateSmooth)
529 		{
530 			ControllerManager::getInstance().removeItem(this);
531 			setAlpha(ALPHA_MAX);
532 			setEnabledSilent(true);
533 			mAnimateSmooth = false;
534 		}
535 
536 		if (_visible)
537 		{
538 			if (mOwner == nullptr && mHideByLostKey)
539 			{
540 				MyGUI::InputManager::getInstance().setKeyFocusWidget(this);
541 			}
542 		}
543 
544 		Base::setVisible(_visible);
545 	}
546 
setVisibleSmooth(bool _visible)547 	void MenuControl::setVisibleSmooth(bool _visible)
548 	{
549 		mAnimateSmooth = true;
550 		ControllerManager::getInstance().removeItem(this);
551 
552 		if (_visible)
553 		{
554 			setEnabledSilent(true);
555 			if (!getVisible())
556 			{
557 				setAlpha(ALPHA_MIN);
558 				Base::setVisible(true);
559 			}
560 
561 			ControllerFadeAlpha* controller = createControllerFadeAlpha(ALPHA_MAX, POPUP_MENU_SPEED_COEF, true);
562 			controller->eventPostAction += newDelegate(action::actionWidgetShow);
563 			ControllerManager::getInstance().addItem(this, controller);
564 		}
565 		else
566 		{
567 			setEnabledSilent(false);
568 
569 			ControllerFadeAlpha* controller = createControllerFadeAlpha(ALPHA_MIN, POPUP_MENU_SPEED_COEF, false);
570 			controller->eventPostAction += newDelegate(action::actionWidgetHide);
571 			ControllerManager::getInstance().addItem(this, controller);
572 		}
573 	}
574 
createControllerFadeAlpha(float _alpha,float _coef,bool _enable)575 	ControllerFadeAlpha* MenuControl::createControllerFadeAlpha(float _alpha, float _coef, bool _enable)
576 	{
577 		ControllerItem* item = ControllerManager::getInstance().createItem(ControllerFadeAlpha::getClassTypeName());
578 		ControllerFadeAlpha* controller = item->castType<ControllerFadeAlpha>();
579 
580 		controller->setAlpha(_alpha);
581 		controller->setCoef(_coef);
582 		controller->setEnabled(_enable);
583 
584 		return controller;
585 	}
586 
insertItem(MenuItem * _to,const UString & _name,MenuItemType _type,const std::string & _id,Any _data)587 	MenuItem* MenuControl::insertItem(MenuItem* _to, const UString& _name, MenuItemType _type, const std::string& _id, Any _data)
588 	{
589 		return insertItemAt(getItemIndex(_to), _name, _type, _id, _data);
590 	}
591 
addItem(const UString & _name,MenuItemType _type,const std::string & _id,Any _data)592 	MenuItem* MenuControl::addItem(const UString& _name, MenuItemType _type, const std::string& _id, Any _data)
593 	{
594 		return insertItemAt(ITEM_NONE, _name, _type, _id, _data);
595 	}
596 
removeItem(MenuItem * _item)597 	void MenuControl::removeItem(MenuItem* _item)
598 	{
599 		removeItemAt(getItemIndex(_item));
600 	}
601 
getItemAt(size_t _index)602 	MenuItem* MenuControl::getItemAt(size_t _index)
603 	{
604 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "MenuControl::getItemAt");
605 		return mItemsInfo[_index].item;
606 	}
607 
getItemIndex(MenuItem * _item)608 	size_t MenuControl::getItemIndex(MenuItem* _item)
609 	{
610 		for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
611 		{
612 			if (mItemsInfo[pos].item == _item)
613 				return pos;
614 		}
615 		MYGUI_EXCEPT("item (" << _item << ") not found, source 'MenuControl::getItemIndex'");
616 	}
617 
findItemWith(const UString & _name)618 	MenuItem* MenuControl::findItemWith(const UString& _name)
619 	{
620 		for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
621 		{
622 			if (mItemsInfo[pos].name == _name)
623 				return mItemsInfo[pos].item;
624 		}
625 		return nullptr;
626 	}
627 
getItemById(const std::string & _id)628 	MenuItem* MenuControl::getItemById(const std::string& _id)
629 	{
630 		for (size_t index = 0; index < mItemsInfo.size(); index++)
631 		{
632 			if (mItemsInfo[index].id == _id)
633 				return mItemsInfo[index].item;
634 		}
635 		MYGUI_EXCEPT("item id (" << _id << ") not found, source 'MenuControl::getItemById'");
636 	}
637 
getItemIndexById(const std::string & _id)638 	size_t MenuControl::getItemIndexById(const std::string& _id)
639 	{
640 		for (size_t index = 0; index < mItemsInfo.size(); index++)
641 		{
642 			if (mItemsInfo[index].id == _id)
643 				return index;
644 		}
645 		MYGUI_EXCEPT("item id (" << _id << ") not found, source 'MenuControl::getItemById'");
646 	}
647 
findItemById(const std::string & _id,bool _recursive)648 	MenuItem* MenuControl::findItemById(const std::string& _id, bool _recursive)
649 	{
650 		for (size_t index = 0; index < mItemsInfo.size(); index++)
651 		{
652 			if (mItemsInfo[index].id == _id)
653 				return mItemsInfo[index].item;
654 
655 			if (_recursive && mItemsInfo[index].submenu != nullptr)
656 			{
657 				MenuItem* find = mItemsInfo[index].submenu->findItemById(_id, _recursive);
658 				if (find != nullptr)
659 					return find;
660 			}
661 		}
662 		return nullptr;
663 	}
664 
findItemIndexWith(const UString & _name)665 	size_t MenuControl::findItemIndexWith(const UString& _name)
666 	{
667 		for (size_t index = 0; index < mItemsInfo.size(); index++)
668 		{
669 			if (mItemsInfo[index].name == _name)
670 				return index;
671 		}
672 		return ITEM_NONE;
673 	}
674 
findItemIndex(MenuItem * _item)675 	size_t MenuControl::findItemIndex(MenuItem* _item)
676 	{
677 		for (size_t index = 0; index < mItemsInfo.size(); index++)
678 		{
679 			if (mItemsInfo[index].item == _item)
680 				return index;
681 		}
682 		return ITEM_NONE;
683 	}
684 
getItemCount() const685 	size_t MenuControl::getItemCount() const
686 	{
687 		return mItemsInfo.size();
688 	}
689 
setItemData(MenuItem * _item,Any _data)690 	void MenuControl::setItemData(MenuItem* _item, Any _data)
691 	{
692 		setItemDataAt(getItemIndex(_item), _data);
693 	}
694 
clearItemDataAt(size_t _index)695 	void MenuControl::clearItemDataAt(size_t _index)
696 	{
697 		setItemDataAt(_index, Any::Null);
698 	}
699 
clearItemData(MenuItem * _item)700 	void MenuControl::clearItemData(MenuItem* _item)
701 	{
702 		clearItemDataAt(getItemIndex(_item));
703 	}
704 
setItemId(MenuItem * _item,const std::string & _id)705 	void MenuControl::setItemId(MenuItem* _item, const std::string& _id)
706 	{
707 		setItemIdAt(getItemIndex(_item), _id);
708 	}
709 
getItemId(MenuItem * _item)710 	const std::string& MenuControl::getItemId(MenuItem* _item)
711 	{
712 		return getItemIdAt(getItemIndex(_item));
713 	}
714 
setItemName(MenuItem * _item,const UString & _name)715 	void MenuControl::setItemName(MenuItem* _item, const UString& _name)
716 	{
717 		setItemNameAt(getItemIndex(_item), _name);
718 	}
719 
getItemName(MenuItem * _item)720 	const UString& MenuControl::getItemName(MenuItem* _item)
721 	{
722 		return getItemNameAt(getItemIndex(_item));
723 	}
724 
setItemChildVisible(MenuItem * _item,bool _visible)725 	void MenuControl::setItemChildVisible(MenuItem* _item, bool _visible)
726 	{
727 		setItemChildVisibleAt(getItemIndex(_item), _visible);
728 	}
729 
getItemChild(MenuItem * _item)730 	MenuControl* MenuControl::getItemChild(MenuItem* _item)
731 	{
732 		return getItemChildAt(getItemIndex(_item));
733 	}
734 
createItemChildAt(size_t _index)735 	MenuControl* MenuControl::createItemChildAt(size_t _index)
736 	{
737 		return createItemChildTAt<MenuControl>(_index);
738 	}
739 
createItemChild(MenuItem * _item)740 	MenuControl* MenuControl::createItemChild(MenuItem* _item)
741 	{
742 		return createItemChildAt(getItemIndex(_item));
743 	}
744 
removeItemChild(MenuItem * _item)745 	void MenuControl::removeItemChild(MenuItem* _item)
746 	{
747 		removeItemChildAt(getItemIndex(_item));
748 	}
749 
getItemType(MenuItem * _item)750 	MenuItemType MenuControl::getItemType(MenuItem* _item)
751 	{
752 		return getItemTypeAt(getItemIndex(_item));
753 	}
754 
setItemType(MenuItem * _item,MenuItemType _type)755 	void MenuControl::setItemType(MenuItem* _item, MenuItemType _type)
756 	{
757 		setItemTypeAt(getItemIndex(_item), _type);
758 	}
759 
setPopupAccept(bool _value)760 	void MenuControl::setPopupAccept(bool _value)
761 	{
762 		mPopupAccept = _value;
763 	}
764 
getPopupAccept() const765 	bool MenuControl::getPopupAccept() const
766 	{
767 		return mPopupAccept;
768 	}
769 
getMenuItemParent()770 	MenuItem* MenuControl::getMenuItemParent()
771 	{
772 		return mOwner;
773 	}
774 
getSkinByType(MenuItemType _type) const775 	const std::string& MenuControl::getSkinByType(MenuItemType _type) const
776 	{
777 		if (_type == MenuItemType::Popup)
778 			return mItemPopupSkin;
779 		else if (_type == MenuItemType::Separator)
780 			return mItemSeparatorSkin;
781 		return mItemNormalSkin;
782 	}
783 
getIconIndexByType(MenuItemType _type) const784 	std::string MenuControl::getIconIndexByType(MenuItemType _type) const
785 	{
786 		if (_type == MenuItemType::Popup)
787 			return "Popup";
788 		return "None";
789 	}
790 
getItemType(bool _submenu,bool _separator) const791 	MenuItemType MenuControl::getItemType(bool _submenu, bool _separator) const
792 	{
793 		if (_submenu)
794 			return MenuItemType::Popup;
795 		else if (_separator)
796 			return MenuItemType::Separator;
797 		return MenuItemType::Normal;
798 	}
799 
_getItemCount()800 	size_t MenuControl::_getItemCount()
801 	{
802 		return getItemCount();
803 	}
804 
_addItem(const MyGUI::UString & _name)805 	void MenuControl::_addItem(const MyGUI::UString& _name)
806 	{
807 		addItem(_name, MenuItemType::Normal);
808 	}
809 
_removeItemAt(size_t _index)810 	void MenuControl::_removeItemAt(size_t _index)
811 	{
812 		removeItemAt(_index);
813 
814 		_updateSizeForEmpty();
815 	}
816 
_getItemAt(size_t _index)817 	Widget* MenuControl::_getItemAt(size_t _index)
818 	{
819 		return getItemAt(_index);
820 	}
821 
_setItemNameAt(size_t _index,const UString & _name)822 	void MenuControl::_setItemNameAt(size_t _index, const UString& _name)
823 	{
824 		setItemNameAt(_index, _name);
825 	}
826 
_getItemNameAt(size_t _index)827 	const UString& MenuControl::_getItemNameAt(size_t _index)
828 	{
829 		return getItemNameAt(_index);
830 	}
831 
_setItemSelected(IItem * _item)832 	void MenuControl::_setItemSelected(IItem* _item)
833 	{
834 		MenuItem* item = static_cast<MenuItem*>(_item);
835 		for (VectorMenuItemInfo::iterator iter = mItemsInfo.begin(); iter != mItemsInfo.end(); ++iter)
836 		{
837 			if ((*iter).type == MenuItemType::Popup)
838 			{
839 				(*iter).item->setStateSelected(false);
840 
841 				if ((*iter).submenu != nullptr)
842 					(*iter).submenu->setVisible(false);
843 			}
844 		}
845 
846 		if (item->getItemType() == MenuItemType::Popup)
847 		{
848 			item->setStateSelected(true);
849 			size_t index = getItemIndex(item);
850 
851 			_setItemChildVisibleAt(index, true, false);
852 
853 			_updateItems(index);
854 		}
855 	}
856 
_updateItems(size_t _index)857 	void MenuControl::_updateItems(size_t _index)
858 	{
859 		if (mItemsInfo[_index].submenu != nullptr)
860 			mItemsInfo[_index].submenu->_updateSizeForEmpty();
861 	}
862 
_updateSizeForEmpty()863 	void MenuControl::_updateSizeForEmpty()
864 	{
865 		if (mItemsInfo.empty())
866 			setSize(100, 100);
867 	}
868 
setVerticalAlignment(bool _value)869 	void MenuControl::setVerticalAlignment(bool _value)
870 	{
871 		mVerticalAlignment = _value;
872 
873 		update();
874 	}
875 
getVerticalAlignment() const876 	bool MenuControl::getVerticalAlignment() const
877 	{
878 		return mVerticalAlignment;
879 	}
880 
setPropertyOverride(const std::string & _key,const std::string & _value)881 	void MenuControl::setPropertyOverride(const std::string& _key, const std::string& _value)
882 	{
883 		/// @wproperty{MenuControl, VerticalAlignment, bool} Вертикальное выравнивание.
884 		if (_key == "VerticalAlignment")
885 			setVerticalAlignment(utility::parseValue<bool>(_value));
886 
887 		else
888 		{
889 			Base::setPropertyOverride(_key, _value);
890 			return;
891 		}
892 
893 		eventChangeProperty(this, _key, _value);
894 	}
895 
896 } // namespace MyGUI
897