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_TabControl.h"
9 #include "MyGUI_ControllerManager.h"
10 #include "MyGUI_WidgetManager.h"
11 #include "MyGUI_Button.h"
12 #include "MyGUI_TabItem.h"
13 #include "MyGUI_ResourceSkin.h"
14 
15 namespace MyGUI
16 {
17 
18 	const float TAB_SPEED_FADE_COEF = 5.0f;
19 
TabControl()20 	TabControl::TabControl() :
21 		mOffsetTab(0),
22 		mButtonShow(true),
23 		mWidthBar(0),
24 		mWidgetBar(nullptr),
25 		mButtonLeft(nullptr),
26 		mButtonRight(nullptr),
27 		mButtonDecor(nullptr),
28 		mEmptyBarWidget(nullptr),
29 		mItemTemplate(nullptr),
30 		mStartIndex(0),
31 		mIndexSelect(ITEM_NONE),
32 		mButtonDefaultWidth(1),
33 		mSmoothShow(true),
34 		mButtonAutoWidth(true),
35 		mShutdown(false),
36 		mHeaderPlace(nullptr),
37 		mControls(nullptr),
38 		mEmpty(nullptr)
39 	{
40 	}
41 
initialiseOverride()42 	void TabControl::initialiseOverride()
43 	{
44 		Base::initialiseOverride();
45 
46 		if (isUserString("ButtonSkin"))
47 			mButtonSkinName = getUserString("ButtonSkin");
48 
49 		// OBSOLETE
50 		if (isUserString("OffsetBar"))
51 			mOffsetTab = utility::parseValue<int>(getUserString("OffsetBar"));
52 
53 		// OBSOLETE
54 		if (isUserString("EmptyBarSkin"))
55 			mEmptySkinName = getUserString("EmptyBarSkin");
56 
57 		// OBSOLETE
58 		assignWidget(mWidgetBar, "Bar");
59 		if (mWidgetBar != nullptr)
60 		{
61 			mWidgetBar->setSize(mWidgetBar->getWidth() - mOffsetTab, mWidgetBar->getHeight());
62 		}
63 
64 		///@wskin_child{TabControl, Button, Left} Кнопка прокрутки заголовков влево.
65 		assignWidget(mButtonLeft, "Left");
66 		if (mButtonLeft != nullptr)
67 		{
68 			mButtonLeft->eventMouseButtonClick += newDelegate(this, &TabControl::notifyPressedButtonEvent);
69 		}
70 
71 		///@wskin_child{TabControl, Button, Right} Кнопка прокрутки заголовков вправо.
72 		assignWidget(mButtonRight, "Right");
73 		if (mButtonRight != nullptr)
74 		{
75 			mButtonRight->eventMouseButtonClick += newDelegate(this, &TabControl::notifyPressedButtonEvent);
76 		}
77 
78 		// OBSOLETE
79 		assignWidget(mButtonDecor, "ButtonDecor");
80 		if (mButtonDecor != nullptr)
81 		{
82 			mButtonDecor->setVisible(false);
83 		}
84 
85 		///@wskin_child{TabControl, Widget, TabItem} Шаблон для страницы, по которому будут создаваться клиентские зоны страниц.
86 		assignWidget(mItemTemplate, "TabItem");
87 		if (mItemTemplate != nullptr)
88 		{
89 			mItemTemplate->setVisible(false);
90 		}
91 
92 #ifndef MYGUI_DONT_USE_OBSOLETE
93 		if (mItemTemplate == nullptr)
94 		{
95 			assignWidget(mItemTemplate, "Sheet");
96 			if (mItemTemplate != nullptr)
97 			{
98 				mItemTemplate->setVisible(false);
99 			}
100 		}
101 #endif // MYGUI_DONT_USE_OBSOLETE
102 
103 		// OBSOLETE
104 		Widget* showPatch = nullptr;
105 		assignWidget(showPatch, "ShowPatch");
106 		if (showPatch != nullptr)
107 		{
108 			mWidgetsPatch.push_back(showPatch);
109 			showPatch->setVisible(false);
110 		}
111 
112 		///@wskin_child{TabControl, Widget, HeaderPlace} Место для заголовоков.
113 		assignWidget(mHeaderPlace, "HeaderPlace");
114 
115 		///@wskin_child{TabControl, Widget, Controls} Виджет на котором должны быть расположены кнопки влево и вправо для заголовоков.
116 		assignWidget(mControls, "Controls");
117 
118 		///@wskin_child{TabControl, Widget, Empty} Виджет который будет показываться в месте где нет заголовков (справа от заголовков).
119 		assignWidget(mEmpty, "Empty");
120 
121 		if (mEmpty == nullptr)
122 		{
123 			// создаем виджет, носитель скина пустоты бара
124 			// OBSOLETE
125 			mEmptyBarWidget = _getWidgetBar()->createWidget<Widget>(mEmptySkinName, IntCoord(), Align::Left | Align::Top);
126 		}
127 
128 		updateBar();
129 
130 		// FIXME добавленно, так как шетдаун вызывается и при смене скина
131 		mShutdown = false;
132 	}
133 
shutdownOverride()134 	void TabControl::shutdownOverride()
135 	{
136 		mWidgetsPatch.clear();
137 		mWidgetBar = nullptr;
138 		mButtonLeft = nullptr;
139 		mButtonRight = nullptr;
140 		mButtonDecor = nullptr;
141 		mItemTemplate = nullptr;
142 		mEmptyBarWidget = nullptr;
143 
144 		mHeaderPlace = nullptr;
145 		mControls = nullptr;
146 		mEmpty = nullptr;
147 
148 		// FIXME перенесенно из деструктора, может косячить при смене скина
149 		mShutdown = true;
150 
151 		Base::shutdownOverride();
152 	}
153 
onWidgetCreated(Widget * _widget)154 	void TabControl::onWidgetCreated(Widget* _widget)
155 	{
156 		Base::onWidgetCreated(_widget);
157 
158 		TabItem* child = _widget->castType<TabItem>(false);
159 		if (child != nullptr)
160 		{
161 			child->setCoord(_getWidgetTemplate()->getAbsoluteLeft() - getAbsoluteLeft(), _getWidgetTemplate()->getAbsoluteTop() - getAbsoluteTop(), _getWidgetTemplate()->getWidth(), _getWidgetTemplate()->getHeight());
162 			child->setAlign(_getWidgetTemplate()->getAlign());
163 
164 			_insertItem(ITEM_NONE, "", child, Any::Null);
165 		}
166 	}
167 
insertItemAt(size_t _index,const UString & _name,Any _data)168 	TabItem* TabControl::insertItemAt(size_t _index, const UString& _name, Any _data)
169 	{
170 		MYGUI_ASSERT_RANGE_INSERT(_index, mItemsInfo.size(), "TabControl::insertItem");
171 
172 		Widget* widget = Base::baseCreateWidget(WidgetStyle::Child, TabItem::getClassTypeName(), "Default", _getWidgetTemplate()->getCoord(), _getWidgetTemplate()->getAlign(), "", "", false);
173 
174 		size_t lastIndex = mItemsInfo.size() - 1;
175 		setItemNameAt(lastIndex, _name);
176 		setItemDataAt(lastIndex, _data);
177 
178 		swapItems(_index == ITEM_NONE ? lastIndex : _index, lastIndex);
179 
180 		return widget->castType<TabItem>();
181 	}
182 
swapItems(size_t _index1,size_t _index2)183 	void TabControl::swapItems(size_t _index1, size_t _index2)
184 	{
185 		MYGUI_ASSERT_RANGE(_index1, mItemsInfo.size(), "TabControl::swapItems");
186 		MYGUI_ASSERT_RANGE(_index2, mItemsInfo.size(), "TabControl::swapItems");
187 
188 		if (_index1 != _index2)
189 		{
190 			std::swap(mItemsInfo[_index1], mItemsInfo[_index2]);
191 			updateBar();
192 		}
193 	}
194 
setPosition(const IntPoint & _point)195 	void TabControl::setPosition(const IntPoint& _point)
196 	{
197 		Base::setPosition(_point);
198 
199 		updateBar();
200 	}
201 
setSize(const IntSize & _size)202 	void TabControl::setSize(const IntSize& _size)
203 	{
204 		Base::setSize(_size);
205 
206 		updateBar();
207 	}
208 
setCoord(const IntCoord & _coord)209 	void TabControl::setCoord(const IntCoord& _coord)
210 	{
211 		Base::setCoord(_coord);
212 
213 		updateBar();
214 	}
215 
notifyPressedButtonEvent(MyGUI::Widget * _sender)216 	void TabControl::notifyPressedButtonEvent(MyGUI::Widget* _sender)
217 	{
218 		if (_sender == mButtonLeft)
219 		{
220 			if (mStartIndex > 0)
221 			{
222 				mStartIndex --;
223 				updateBar();
224 			}
225 		}
226 		else if (_sender == mButtonRight)
227 		{
228 			if ((mStartIndex + 1) < mItemsInfo.size())
229 			{
230 				mStartIndex ++;
231 				// в updateBar() будет подкорректированно если что
232 				updateBar();
233 			}
234 		}
235 	}
236 
notifyPressedBarButtonEvent(MyGUI::Widget * _sender)237 	void TabControl::notifyPressedBarButtonEvent(MyGUI::Widget* _sender)
238 	{
239 		size_t select = *_sender->_getInternalData<size_t>() + mStartIndex;
240 		// щелкнули по той же кнопке
241 		if (select == mIndexSelect)
242 		{
243 			// стараемся показать выделенную кнопку
244 			beginToItemSelected();
245 			return;
246 		}
247 		size_t old = mIndexSelect;
248 		mIndexSelect = select;
249 
250 		size_t count = 0;
251 		for (size_t pos = 0; pos < mItemButton.size(); pos++)
252 		{
253 			Button* button = mItemButton[count]->castType<Button>();
254 			if (button->getVisible())
255 			{
256 				// корректируем нажатость кнопки
257 				button->setStateSelected((pos + mStartIndex) == mIndexSelect);
258 			}
259 			count ++;
260 		}
261 
262 		// стараемся показать выделенную кнопку
263 		beginToItemSelected();
264 
265 		// поднимаем страницу для пикинга
266 		_forcePick(mItemsInfo[mIndexSelect].item);
267 
268 		_showItem(mItemsInfo[mIndexSelect].item, true, mSmoothShow);
269 		_showItem(mItemsInfo[old].item, false, mSmoothShow);
270 
271 		eventTabChangeSelect(this, mIndexSelect);
272 	}
273 
beginToItemAt(size_t _index)274 	void TabControl::beginToItemAt(size_t _index)
275 	{
276 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::beginToItemAt");
277 
278 		// подстраховка
279 		if (_getWidgetBar()->getWidth() < 1)
280 			return;
281 
282 		if (_index == mStartIndex)
283 			return;
284 		else if (_index < mStartIndex)
285 		{
286 			mStartIndex = _index;
287 			updateBar();
288 		}
289 		else
290 		{
291 			// длинна бара от старт индекса до нужной включительно
292 			int width = 0;
293 			for (size_t pos = mStartIndex; pos <= _index; pos++)
294 			{
295 				width += mItemsInfo[pos].width;
296 			}
297 
298 			// уменьшем старт индекс пока не появиться нужная
299 			bool change = false;
300 			while ((mStartIndex < _index) && (width > _getWidgetBar()->getWidth()))
301 			{
302 				width -= mItemsInfo[mStartIndex].width;
303 				mStartIndex ++;
304 				change = true;
305 			}
306 			if (change)
307 				updateBar();
308 		}
309 	}
310 
setButtonDefaultWidth(int _width)311 	void TabControl::setButtonDefaultWidth(int _width)
312 	{
313 		mButtonDefaultWidth = _width;
314 		if (mButtonDefaultWidth < 1)
315 			mButtonDefaultWidth = 1;
316 		setButtonAutoWidth(false);
317 	}
318 
setButtonAutoWidth(bool _auto)319 	void TabControl::setButtonAutoWidth(bool _auto)
320 	{
321 		mButtonAutoWidth = _auto;
322 
323 		for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
324 		{
325 			int width;
326 			if (mButtonAutoWidth)
327 				width = _getTextWidth(mItemsInfo[pos].name);
328 			else
329 				width = mButtonDefaultWidth;
330 
331 			mWidthBar += width - mItemsInfo[pos].width;
332 			mItemsInfo[pos].width = width;
333 		}
334 
335 		updateBar();
336 	}
337 
setButtonWidthAt(size_t _index,int _width)338 	void TabControl::setButtonWidthAt(size_t _index, int _width)
339 	{
340 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::setButtonWidthAt");
341 
342 		if (_width <= 0)
343 		{
344 			if (mButtonAutoWidth)
345 				_width = _getTextWidth(mItemsInfo[_index].name);
346 			else
347 				_width = mButtonDefaultWidth;
348 		}
349 
350 		mWidthBar += _width - mItemsInfo[_index].width;
351 		mItemsInfo[_index].width = _width;
352 
353 		updateBar();
354 	}
355 
setItemNameAt(size_t _index,const UString & _name)356 	void TabControl::setItemNameAt(size_t _index, const UString& _name)
357 	{
358 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::setItemNameAt");
359 		mItemsInfo[_index].name = _name;
360 
361 		int width;
362 		if (mButtonAutoWidth)
363 			width = _getTextWidth(_name);
364 		else
365 			width = mButtonDefaultWidth;
366 
367 		mWidthBar += width - mItemsInfo[_index].width;
368 		mItemsInfo[_index].width = width;
369 
370 		updateBar();
371 	}
372 
setIndexSelected(size_t _index)373 	void TabControl::setIndexSelected(size_t _index)
374 	{
375 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::setIndexSelected");
376 		if (mIndexSelect == _index)
377 			return;
378 		size_t old = mIndexSelect;
379 		mIndexSelect = _index;
380 		updateBar();
381 
382 		// поднимаем страницу для пикинга
383 		if (mSmoothShow)
384 			_forcePick(mItemsInfo[mIndexSelect].item);
385 
386 		_showItem(mItemsInfo[mIndexSelect].item, true, mSmoothShow);
387 		_showItem(mItemsInfo[old].item, false, mSmoothShow);
388 
389 		beginToItemSelected();
390 	}
391 
actionWidgetHide(Widget * _widget,ControllerItem * _controller)392 	void TabControl::actionWidgetHide(Widget* _widget, ControllerItem* _controller)
393 	{
394 		_widget->setVisible(false);
395 		_widget->setEnabled(true);
396 	}
397 
_showItem(TabItem * _item,bool _show,bool _smooth)398 	void TabControl::_showItem(TabItem* _item, bool _show, bool _smooth)
399 	{
400 		if (!_smooth)
401 		{
402 			ControllerManager::getInstance().removeItem(_item);
403 			_item->setAlpha(ALPHA_MAX);
404 
405 			_item->setVisible(_show);
406 
407 			return;
408 		}
409 
410 		if (_show)
411 		{
412 			ControllerFadeAlpha* controller = createControllerFadeAlpha(ALPHA_MAX, TAB_SPEED_FADE_COEF, true);
413 			ControllerManager::getInstance().addItem(_item, controller);
414 		}
415 		else
416 		{
417 			ControllerFadeAlpha* controller = createControllerFadeAlpha(ALPHA_MIN, TAB_SPEED_FADE_COEF, false);
418 			controller->eventPostAction += newDelegate(this, &TabControl::actionWidgetHide);
419 			ControllerManager::getInstance().addItem(_item, controller);
420 		}
421 	}
422 
createButton()423 	Button* TabControl::createButton()
424 	{
425 		Widget* parent = this;
426 		if (mWidgetBar != nullptr)
427 			parent = mWidgetBar;
428 		else if (mHeaderPlace != nullptr)
429 			parent = mHeaderPlace;
430 
431 		return parent->createWidget<Button>(mButtonSkinName, IntCoord(), Align::Left | Align::Top);
432 	}
433 
_createItemButton()434 	void TabControl::_createItemButton()
435 	{
436 		Button* button = createButton();
437 		button->eventMouseButtonClick += newDelegate(this, &TabControl::notifyPressedBarButtonEvent);
438 		button->_setInternalData(mItemButton.size()); // порядковый номер
439 		mItemButton.push_back(button);
440 	}
441 
_getTextWidth(const UString & _text)442 	int TabControl::_getTextWidth(const UString& _text)
443 	{
444 		if (mItemButton.empty())
445 			_createItemButton();
446 
447 		UString save = mItemButton[0]->getCaption();
448 		mItemButton[0]->setCaption(_text);
449 
450 		ISubWidgetText* text = mItemButton[0]->getSubWidgetText();
451 		const IntSize& size = text ? text->getTextSize() : IntSize();
452 		const IntCoord& coord = text ? text->getCoord() : IntCoord();
453 
454 		mItemButton[0]->setCaption(save);
455 
456 		return size.width + mItemButton[0]->getWidth() - coord.width;
457 	}
458 
_notifyDeleteItem(TabItem * _sheet)459 	void TabControl::_notifyDeleteItem(TabItem* _sheet)
460 	{
461 		// общий шутдаун виджета
462 		if (mShutdown)
463 			return;
464 
465 		size_t index = getItemIndex(_sheet);
466 
467 		mWidthBar -= mItemsInfo[index].width;
468 		mItemsInfo.erase(mItemsInfo.begin() + index);
469 
470 		if (mItemsInfo.empty())
471 			mIndexSelect = ITEM_NONE;
472 		else
473 		{
474 			if (index < mIndexSelect)
475 				mIndexSelect --;
476 			else if (index == mIndexSelect)
477 			{
478 				if (mIndexSelect == mItemsInfo.size())
479 					mIndexSelect --;
480 				mItemsInfo[mIndexSelect].item->setVisible(true);
481 				mItemsInfo[mIndexSelect].item->setAlpha(ALPHA_MAX);
482 			}
483 		}
484 
485 		updateBar();
486 	}
487 
_insertItem(size_t _index,const UString & _name,TabItem * _sheet,Any _data)488 	void TabControl::_insertItem(size_t _index, const UString& _name, TabItem* _sheet, Any _data)
489 	{
490 		if (_index == ITEM_NONE)
491 			_index = mItemsInfo.size();
492 
493 		// добавляем инфу о вкладке
494 		int width = (mButtonAutoWidth ? _getTextWidth(_name) : mButtonDefaultWidth);
495 		mWidthBar += width;
496 
497 		mItemsInfo.insert(mItemsInfo.begin() + _index, TabItemInfo(width, _name, _sheet, _data));
498 
499 		// первая вкладка
500 		if (1 == mItemsInfo.size())
501 			mIndexSelect = 0;
502 		else
503 		{
504 			_sheet->setVisible(false);
505 			if (_index <= mIndexSelect)
506 				mIndexSelect ++;
507 		}
508 
509 		updateBar();
510 	}
511 
setItemDataAt(size_t _index,Any _data)512 	void TabControl::setItemDataAt(size_t _index, Any _data)
513 	{
514 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::setItemDataAt");
515 		mItemsInfo[_index].data = _data;
516 	}
517 
getButtonWidthAt(size_t _index)518 	int TabControl::getButtonWidthAt(size_t _index)
519 	{
520 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::getButtonWidthAt");
521 		return mItemsInfo[_index].width;
522 	}
523 
getItemNameAt(size_t _index)524 	const UString& TabControl::getItemNameAt(size_t _index)
525 	{
526 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::getItemNameAt");
527 		return mItemsInfo[_index].name;
528 	}
529 
getItemAt(size_t _index)530 	TabItem* TabControl::getItemAt(size_t _index)
531 	{
532 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::getItemAt");
533 		return mItemsInfo[_index].item;
534 	}
535 
removeItemAt(size_t _index)536 	void TabControl::removeItemAt(size_t _index)
537 	{
538 		MYGUI_ASSERT_RANGE(_index, mItemsInfo.size(), "TabControl::removeItemAt");
539 		this->_destroyChildWidget(mItemsInfo[_index].item);
540 	}
541 
removeAllItems()542 	void TabControl::removeAllItems()
543 	{
544 		while (!mItemsInfo.empty())
545 		{
546 			_destroyChildWidget(mItemsInfo.back().item);
547 		}
548 	}
549 
createControllerFadeAlpha(float _alpha,float _coef,bool _enable)550 	ControllerFadeAlpha* TabControl::createControllerFadeAlpha(float _alpha, float _coef, bool _enable)
551 	{
552 		ControllerItem* item = ControllerManager::getInstance().createItem(ControllerFadeAlpha::getClassTypeName());
553 		ControllerFadeAlpha* controller = item->castType<ControllerFadeAlpha>();
554 
555 		controller->setAlpha(_alpha);
556 		controller->setCoef(_coef);
557 		controller->setEnabled(_enable);
558 
559 		return controller;
560 	}
561 
getItemIndex(TabItem * _item)562 	size_t TabControl::getItemIndex(TabItem* _item)
563 	{
564 		for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
565 		{
566 			if (mItemsInfo[pos].item == _item)
567 				return pos;
568 		}
569 		MYGUI_EXCEPT("item (" << _item << ") not found, source 'TabControl::getItemIndex'");
570 	}
571 
findItemIndex(TabItem * _item)572 	size_t TabControl::findItemIndex(TabItem* _item)
573 	{
574 		for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
575 		{
576 			if (mItemsInfo[pos].item == _item)
577 				return pos;
578 		}
579 		return ITEM_NONE;
580 	}
581 
findItemIndexWith(const UString & _name)582 	size_t TabControl::findItemIndexWith(const UString& _name)
583 	{
584 		for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
585 		{
586 			if (mItemsInfo[pos].name == _name)
587 				return pos;
588 		}
589 		return ITEM_NONE;
590 	}
591 
findItemWith(const UString & _name)592 	TabItem* TabControl::findItemWith(const UString& _name)
593 	{
594 		for (size_t pos = 0; pos < mItemsInfo.size(); pos++)
595 		{
596 			if (mItemsInfo[pos].name == _name)
597 				return mItemsInfo[pos].item;
598 		}
599 		return nullptr;
600 	}
601 
getItemSelected()602 	TabItem* TabControl::getItemSelected()
603 	{
604 		return getIndexSelected() != ITEM_NONE ? getItemAt(getIndexSelected()) : nullptr;
605 	}
606 
_getWidgetTemplate()607 	Widget* TabControl::_getWidgetTemplate()
608 	{
609 		return mItemTemplate == nullptr ? this : mItemTemplate;
610 	}
611 
_getWidgetBar()612 	Widget* TabControl::_getWidgetBar()
613 	{
614 		return mWidgetBar == nullptr ? this : mWidgetBar;
615 	}
616 
setPropertyOverride(const std::string & _key,const std::string & _value)617 	void TabControl::setPropertyOverride(const std::string& _key, const std::string& _value)
618 	{
619 		/// @wproperty{TabControl, ButtonWidth, int} Ширина кнопок в заголовках в пикселях.
620 		if (_key == "ButtonWidth")
621 			setButtonDefaultWidth(utility::parseValue<int>(_value));
622 
623 		/// @wproperty{TabControl, ButtonAutoWidth, bool} Режим автоматического вычисления ширины кнопок в заголовках.
624 		else if (_key == "ButtonAutoWidth")
625 			setButtonAutoWidth(utility::parseValue<bool>(_value));
626 
627 		/// @wproperty{TabControl, SmoothShow, bool} Плавное переключение между закладками.
628 		else if (_key == "SmoothShow")
629 			setSmoothShow(utility::parseValue<bool>(_value));
630 
631 		// не коментировать
632 		else if (_key == "SelectItem")
633 			setIndexSelected(utility::parseValue<size_t>(_value));
634 
635 		else
636 		{
637 			Base::setPropertyOverride(_key, _value);
638 			return;
639 		}
640 
641 		eventChangeProperty(this, _key, _value);
642 	}
643 
getItemCount() const644 	size_t TabControl::getItemCount() const
645 	{
646 		return mItemsInfo.size();
647 	}
648 
insertItem(TabItem * _to,const UString & _name,Any _data)649 	TabItem* TabControl::insertItem(TabItem* _to, const UString& _name, Any _data)
650 	{
651 		return insertItemAt(getItemIndex(_to), _name, _data);
652 	}
653 
addItem(const UString & _name,Any _data)654 	TabItem* TabControl::addItem(const UString& _name, Any _data)
655 	{
656 		return insertItemAt(ITEM_NONE, _name, _data);
657 	}
658 
removeItem(TabItem * _item)659 	void TabControl::removeItem(TabItem* _item)
660 	{
661 		removeItemAt(getItemIndex(_item));
662 	}
663 
getIndexSelected() const664 	size_t TabControl::getIndexSelected() const
665 	{
666 		return mIndexSelect;
667 	}
668 
setItemSelected(TabItem * _item)669 	void TabControl::setItemSelected(TabItem* _item)
670 	{
671 		setIndexSelected(getItemIndex(_item));
672 	}
673 
setItemData(TabItem * _item,Any _data)674 	void TabControl::setItemData(TabItem* _item, Any _data)
675 	{
676 		setItemDataAt(getItemIndex(_item), _data);
677 	}
678 
clearItemDataAt(size_t _index)679 	void TabControl::clearItemDataAt(size_t _index)
680 	{
681 		setItemDataAt(_index, Any::Null);
682 	}
683 
clearItemData(TabItem * _item)684 	void TabControl::clearItemData(TabItem* _item)
685 	{
686 		clearItemDataAt(getItemIndex(_item));
687 	}
688 
setItemName(TabItem * _item,const UString & _name)689 	void TabControl::setItemName(TabItem* _item, const UString& _name)
690 	{
691 		setItemNameAt(getItemIndex(_item), _name);
692 	}
693 
getItemName(TabItem * _item)694 	const UString& TabControl::getItemName(TabItem* _item)
695 	{
696 		return getItemNameAt(getItemIndex(_item));
697 	}
698 
beginToItem(TabItem * _item)699 	void TabControl::beginToItem(TabItem* _item)
700 	{
701 		beginToItemAt(getItemIndex(_item));
702 	}
703 
beginToItemFirst()704 	void TabControl::beginToItemFirst()
705 	{
706 		if (getItemCount())
707 			beginToItemAt(0);
708 	}
709 
beginToItemLast()710 	void TabControl::beginToItemLast()
711 	{
712 		if (getItemCount())
713 			beginToItemAt(getItemCount() - 1);
714 	}
715 
beginToItemSelected()716 	void TabControl::beginToItemSelected()
717 	{
718 		if (getIndexSelected() != ITEM_NONE)
719 			beginToItemAt(getIndexSelected());
720 	}
721 
setButtonWidth(TabItem * _item,int _width)722 	void TabControl::setButtonWidth(TabItem* _item, int _width)
723 	{
724 		setButtonWidthAt(getItemIndex(_item), _width);
725 	}
726 
getButtonWidth(TabItem * _item)727 	int TabControl::getButtonWidth(TabItem* _item)
728 	{
729 		return getButtonWidthAt(getItemIndex(_item));
730 	}
731 
getButtonDefaultWidth() const732 	int TabControl::getButtonDefaultWidth() const
733 	{
734 		return mButtonDefaultWidth;
735 	}
736 
getButtonAutoWidth() const737 	bool TabControl::getButtonAutoWidth() const
738 	{
739 		return mButtonAutoWidth;
740 	}
741 
setSmoothShow(bool _value)742 	void TabControl::setSmoothShow(bool _value)
743 	{
744 		mSmoothShow = _value;
745 	}
746 
getSmoothShow() const747 	bool TabControl::getSmoothShow() const
748 	{
749 		return mSmoothShow;
750 	}
751 
_getItemCount()752 	size_t TabControl::_getItemCount()
753 	{
754 		return getItemCount();
755 	}
756 
_addItem(const MyGUI::UString & _name)757 	void TabControl::_addItem(const MyGUI::UString& _name)
758 	{
759 		addItem(_name);
760 	}
761 
_removeItemAt(size_t _index)762 	void TabControl::_removeItemAt(size_t _index)
763 	{
764 		removeItemAt(_index);
765 	}
766 
_getItemAt(size_t _index)767 	Widget* TabControl::_getItemAt(size_t _index)
768 	{
769 		return getItemAt(_index);
770 	}
771 
_setItemNameAt(size_t _index,const UString & _name)772 	void TabControl::_setItemNameAt(size_t _index, const UString& _name)
773 	{
774 		setItemNameAt(_index, _name);
775 	}
776 
_getItemNameAt(size_t _index)777 	const UString& TabControl::_getItemNameAt(size_t _index)
778 	{
779 		return getItemNameAt(_index);
780 	}
781 
updateBar()782 	void TabControl::updateBar()
783 	{
784 		if (mHeaderPlace != nullptr)
785 			updateBarNew();
786 		else
787 			updateBarOld();
788 	}
789 
updateBarOld()790 	void TabControl::updateBarOld()
791 	{
792 		// подстраховка
793 		if (_getWidgetBar()->getWidth() < 1)
794 			return;
795 
796 		if ((_getWidgetBar()->getWidth() < mWidthBar) && (1 < mItemsInfo.size()))
797 		{
798 			if (!mButtonShow)
799 			{
800 				mButtonShow = true;
801 
802 				if (nullptr != mButtonLeft)
803 					mButtonLeft->setVisible(true);
804 				if (nullptr != mButtonRight)
805 					mButtonRight->setVisible(true);
806 				if (nullptr != mButtonDecor)
807 					mButtonDecor->setVisible(true);
808 				for (VectorWidgetPtr::iterator iter = mWidgetsPatch.begin(); iter != mWidgetsPatch.end(); ++iter)
809 					(*iter)->setVisible(true);
810 				if (mWidgetBar != nullptr)
811 					mWidgetBar->setSize(mWidgetBar->getWidth() - mOffsetTab, mWidgetBar->getHeight());
812 			}
813 		}
814 		else
815 		{
816 			if (mButtonShow)
817 			{
818 				mButtonShow = false;
819 				if (nullptr != mButtonLeft)
820 					mButtonLeft->setVisible(false);
821 				if (nullptr != mButtonRight)
822 					mButtonRight->setVisible(false);
823 				if (nullptr != mButtonDecor)
824 					mButtonDecor->setVisible(false);
825 				for (VectorWidgetPtr::iterator iter = mWidgetsPatch.begin(); iter != mWidgetsPatch.end(); ++iter)
826 					(*iter)->setVisible(false);
827 				if (mWidgetBar != nullptr)
828 					mWidgetBar->setSize(mWidgetBar->getWidth() + mOffsetTab, mWidgetBar->getHeight());
829 			}
830 		}
831 
832 		// проверяем правильность стартового индекса
833 		if (mStartIndex > 0)
834 		{
835 			// считаем длинну видимых кнопок
836 			int width = 0;
837 			for (size_t pos = mStartIndex; pos < mItemsInfo.size(); pos++)
838 				width += mItemsInfo[pos].width;
839 
840 			// уменьшаем индекс до тех пор пока кнопка до индекста полностью не влезет в бар
841 			while ((mStartIndex > 0) && ((width + mItemsInfo[mStartIndex - 1].width) <= _getWidgetBar()->getWidth()))
842 			{
843 				mStartIndex--;
844 				width += mItemsInfo[mStartIndex].width;
845 			}
846 		}
847 
848 		// проверяем и обновляем бар
849 		int width = 0;
850 		size_t count = 0;
851 		size_t pos = mStartIndex;
852 		for (; pos < mItemsInfo.size(); pos++)
853 		{
854 			// текущая кнопка не влазиет
855 			if (width > _getWidgetBar()->getWidth())
856 				break;
857 
858 			// следующая не влазиет
859 			TabItemInfo& info = mItemsInfo[pos];
860 			if ((width + info.width) > _getWidgetBar()->getWidth())
861 			{
862 				break;
863 			}
864 
865 			// проверяем физическое наличие кнопки
866 			if (count >= mItemButton.size())
867 				_createItemButton();
868 
869 			// если кнопка не соответствует, то изменяем ее
870 			Button* button = mItemButton[count]->castType<Button>();
871 			button->setVisible(true);
872 
873 			// корректируем нажатость кнопки
874 			button->setStateSelected(pos == mIndexSelect);
875 
876 			if (button->getCaption() != info.name)
877 				button->setCaption(info.name);
878 			// положение кнопки
879 			IntCoord coord(width, 0, info.width, _getWidgetBar()->getHeight());
880 			if (coord != button->getCoord())
881 				button->setCoord(coord);
882 
883 			width += info.width;
884 			count ++;
885 		}
886 
887 		// скрываем кнопки что были созданны, но не видны
888 		while (count < mItemButton.size())
889 		{
890 			mItemButton[count]->setVisible(false);
891 			count ++;
892 		}
893 
894 		bool right = true;
895 		if (pos == mItemsInfo.size())
896 			right = false;
897 
898 		// в редакторе падает почему то, хотя этот скин создается всегда
899 		if (mEmptyBarWidget != nullptr)
900 		{
901 			// корректируем виджет для пустоты
902 			if (width < _getWidgetBar()->getWidth())
903 			{
904 				mEmptyBarWidget->setVisible(true);
905 				mEmptyBarWidget->setCoord(width, 0, _getWidgetBar()->getWidth() - width, _getWidgetBar()->getHeight());
906 			}
907 			else
908 			{
909 				mEmptyBarWidget->setVisible(false);
910 			}
911 		}
912 
913 		// корректируем доступность стрелок
914 		if (mStartIndex == 0)
915 		{
916 			if (nullptr != mButtonLeft)
917 				mButtonLeft->setEnabled(false);
918 		}
919 		else
920 		{
921 			if (nullptr != mButtonLeft)
922 				mButtonLeft->setEnabled(true);
923 		}
924 
925 		if (right)
926 		{
927 			if (nullptr != mButtonRight)
928 				mButtonRight->setEnabled(true);
929 		}
930 		else
931 		{
932 			if (nullptr != mButtonRight)
933 				mButtonRight->setEnabled(false);
934 		}
935 	}
936 
updateBarNew()937 	void TabControl::updateBarNew()
938 	{
939 		if (mHeaderPlace == nullptr)
940 			return;
941 
942 		// подстраховка
943 		if (mHeaderPlace->getWidth() < 1)
944 			return;
945 
946 		int widthControls = 0;
947 		if (mControls != nullptr)
948 			widthControls = mControls->getWidth();
949 
950 		if ((mHeaderPlace->getWidth() < mWidthBar) && (1 < mItemsInfo.size()) && (mHeaderPlace->getWidth() >= widthControls))
951 		{
952 			if (!mButtonShow)
953 			{
954 				mButtonShow = true;
955 
956 				if (nullptr != mControls)
957 					mControls->setVisible(true);
958 			}
959 
960 			if (mControls != nullptr)
961 				mControls->setCoord(mHeaderPlace->getWidth() - mControls->getWidth(), 0, mControls->getWidth(), mHeaderPlace->getHeight());
962 		}
963 		else
964 		{
965 			if (mButtonShow)
966 			{
967 				mButtonShow = false;
968 
969 				if (nullptr != mControls)
970 					mControls->setVisible(false);
971 			}
972 
973 			widthControls = 0;
974 		}
975 
976 		// проверяем правильность стартового индекса
977 		if (mStartIndex > 0)
978 		{
979 			// считаем длинну видимых кнопок
980 			int width = 0;
981 			for (size_t pos = mStartIndex; pos < mItemsInfo.size(); pos++)
982 				width += mItemsInfo[pos].width;
983 
984 			// уменьшаем индекс до тех пор пока кнопка до индекста полностью не влезет в бар
985 			while ((mStartIndex > 0) && ((width + mItemsInfo[mStartIndex - 1].width) <= (mHeaderPlace->getWidth() - widthControls)))
986 			{
987 				mStartIndex--;
988 				width += mItemsInfo[mStartIndex].width;
989 			}
990 		}
991 
992 		// проверяем и обновляем бар
993 		int width = 0;
994 		size_t count = 0;
995 		size_t pos = mStartIndex;
996 		for (; pos < mItemsInfo.size(); pos++)
997 		{
998 			// текущая кнопка не влазиет
999 			if (width > (mHeaderPlace->getWidth() - widthControls))
1000 				break;
1001 
1002 			// следующая не влазиет
1003 			TabItemInfo& info = mItemsInfo[pos];
1004 			if ((width + info.width) > (mHeaderPlace->getWidth() - widthControls))
1005 			{
1006 				break;
1007 			}
1008 
1009 			// проверяем физическое наличие кнопки
1010 			if (count >= mItemButton.size())
1011 				_createItemButton();
1012 
1013 			// если кнопка не соответствует, то изменяем ее
1014 			Button* button = mItemButton[count];
1015 			button->setVisible(true);
1016 
1017 			// корректируем нажатость кнопки
1018 			button->setStateSelected(pos == mIndexSelect);
1019 
1020 			if (button->getCaption() != info.name)
1021 				button->setCaption(info.name);
1022 			// положение кнопки
1023 			IntCoord coord(width, 0, info.width, mHeaderPlace->getHeight());
1024 			if (coord != button->getCoord())
1025 				button->setCoord(coord);
1026 
1027 			width += info.width;
1028 			count ++;
1029 		}
1030 
1031 		// скрываем кнопки что были созданны, но не видны
1032 		while (count < mItemButton.size())
1033 		{
1034 			mItemButton[count]->setVisible(false);
1035 			count ++;
1036 		}
1037 
1038 		bool right = true;
1039 		if (pos == mItemsInfo.size())
1040 			right = false;
1041 
1042 		if (mEmpty != nullptr)
1043 		{
1044 			// корректируем виджет для пустоты
1045 			mEmpty->setCoord(width, 0, mHeaderPlace->getWidth() - width - widthControls, mHeaderPlace->getHeight());
1046 		}
1047 
1048 		// корректируем доступность стрелок
1049 		if (mStartIndex == 0)
1050 		{
1051 			if (nullptr != mButtonLeft)
1052 				mButtonLeft->setEnabled(false);
1053 		}
1054 		else
1055 		{
1056 			if (nullptr != mButtonLeft)
1057 				mButtonLeft->setEnabled(true);
1058 		}
1059 
1060 		if (right)
1061 		{
1062 			if (nullptr != mButtonRight)
1063 				mButtonRight->setEnabled(true);
1064 		}
1065 		else
1066 		{
1067 			if (nullptr != mButtonRight)
1068 				mButtonRight->setEnabled(false);
1069 		}
1070 	}
1071 
1072 } // namespace MyGUI
1073