1 /*!
2 	@file
3 	@author		Albert Semenov
4 	@date		03/2011
5 */
6 
7 #include "MyGUI_Precompiled.h"
8 #include <MyGUI_ResourceImageSet.h>
9 #include <MyGUI_ImageBox.h>
10 #include <MyGUI_TextBox.h>
11 #include <MyGUI_WidgetManager.h>
12 #include <MyGUI_FontManager.h>
13 #include <MyGUI_IFont.h>
14 #include "HyperTextBox.h"
15 
16 namespace MyGUI
17 {
18 
HyperTextBox()19 	HyperTextBox::HyperTextBox() :
20 		mBold(false),
21 		mItalic(false),
22 		mStrike(false),
23 		mUnder(false),
24 		mImage(false),
25 		mHeader1(false),
26 		mHeader2(false),
27 		mHeader3(false),
28 		mColour(false),
29 		mUrl(false),
30 		mStackPanel(nullptr),
31 		mScrollViewPanel(nullptr),
32 		mTextSkin("TextBox"),
33 		mImageSkin("ImageBox"),
34 		mParagraphSkin("Default"),
35 		mLineSkin("WhiteSkin"),
36 		mLinkPoiner("link"),
37 		mHeader1Font("Default"),
38 		mHeader2Font("Default"),
39 		mHeader3Font("Default"),
40 		mDefaultFont("Default"),
41 		mBoldFont("Default"),
42 		mItalicFont("Default"),
43 		mBoldItalicFont("Default"),
44 		mCurrentWrapPanel(nullptr),
45 		mBreakHeight(0)
46 	{
47 	}
48 
initialiseOverride()49 	void HyperTextBox::initialiseOverride()
50 	{
51 		Base::initialiseOverride();
52 
53 		assignWidget(mScrollViewPanel, "ScrollViewPanel");
54 		assignWidget(mStackPanel, "StackPanel");
55 
56 		if (isUserString("TextSkin"))
57 			mTextSkin = getUserString("TextSkin");
58 		if (isUserString("ImageSkin"))
59 			mImageSkin = getUserString("ImageSkin");
60 		if (isUserString("ParagraphSkin"))
61 			mParagraphSkin = getUserString("ParagraphSkin");
62 		if (isUserString("LineSkin"))
63 			mLineSkin = getUserString("LineSkin");
64 		if (isUserString("LinkPointer"))
65 			mLinkPoiner = getUserString("LinkPointer");
66 
67 		updateBreakHeight();
68 	}
69 
shutdownOverride()70 	void HyperTextBox::shutdownOverride()
71 	{
72 		Base::shutdownOverride();
73 	}
74 
addItem(const std::string & _value)75 	void HyperTextBox::addItem(const std::string& _value)
76 	{
77 		parseParagraph(mStackPanel, _value);
78 		mCurrentWrapPanel = nullptr;
79 	}
80 
parseParagraph(Widget * _parent,const std::string & _value)81 	void HyperTextBox::parseParagraph(Widget* _parent, const std::string& _value)
82 	{
83 		std::string::const_iterator textItem = _value.end();
84 		for (std::string::const_iterator item = _value.begin(); item != _value.end(); ++ item)
85 		{
86 			if ((*item) == '<')
87 			{
88 				// отрезаем текст
89 				if (textItem < item)
90 				{
91 					if (mCurrentWrapPanel != nullptr)
92 						parseText(mCurrentWrapPanel,	_value.substr(textItem - _value.begin(), item - textItem));
93 				}
94 
95 				// ищем конец тега
96 				for (std::string::const_iterator tagItem = item; tagItem != _value.end(); ++ tagItem)
97 				{
98 					if ((*tagItem) == '>')
99 					{
100 						parseTag(_value.substr(item - _value.begin(), tagItem - item + 1));
101 
102 						item = tagItem;
103 						textItem = tagItem + 1;
104 						break;
105 					}
106 				}
107 			}
108 		}
109 	}
110 
parseText(Widget * _parent,const std::string & _value)111 	void HyperTextBox::parseText(Widget* _parent, const std::string& _value)
112 	{
113 		const int defaultSize = 16;
114 
115 		if (mImage)
116 		{
117 			if (mImageSize.width == 0 || mImageSize.height == 0)
118 			{
119 				IResource* resource = ResourceManager::getInstance().getByName(_value, false);
120 				if (resource != nullptr)
121 				{
122 					ResourceImageSet* imageSet = resource->castType<ResourceImageSet>(false);
123 					if (imageSet != nullptr)
124 					{
125 						ImageIndexInfo info = imageSet->getIndexInfo(0, 0);
126 						mImageSize = info.size;
127 					}
128 				}
129 			}
130 
131 			ImageBox* image = _parent->createWidget<ImageBox>(mImageSkin, IntCoord(0, 0, mImageSize.width, mImageSize.height), Align::Default);
132 			image->setItemResource(_value);
133 			// картинка как урл
134 			if (mUrl)
135 			{
136 				image->setPointer(mLinkPoiner);
137 				image->eventMouseButtonClick += newDelegate(this, &HyperTextBox::OnTextClick);
138 				image->setUserString("URL", mUrlValue);
139 			}
140 		}
141 		else if (mUrl)
142 		{
143 			TextBox* text = _parent->createWidget<TextBox>(mTextSkin, IntCoord(0, 0, defaultSize, defaultSize), Align::Default);
144 			text->setCaption(_value);
145 			text->setPointer(mLinkPoiner);
146 			if (mBold)
147 			{
148 				if (mItalic)
149 					text->setFontName(mBoldItalicFont);
150 				else
151 					text->setFontName(mBoldFont);
152 			}
153 			else if (mItalic)
154 			{
155 				text->setFontName(mItalicFont);
156 			}
157 
158 			Widget* line = text->createWidget<Widget>(mLineSkin, IntCoord(0, defaultSize - 1, defaultSize, 1), Align::HStretch | Align::Bottom);
159 			line->setColour(Colour::Black);
160 			line->setVisible(false);
161 			line->setNeedMouseFocus(false);
162 
163 			text->eventMouseLostFocus += newDelegate(this, &HyperTextBox::OnTextLostFocus);
164 			text->eventMouseSetFocus += newDelegate(this, &HyperTextBox::OnTextSetFocus);
165 			text->eventMouseButtonClick += newDelegate(this, &HyperTextBox::OnTextClick);
166 			text->setUserString("URL", mUrlValue);
167 		}
168 		else
169 		{
170 			VectorString result = utility::split(_value);
171 			for (VectorString::const_iterator item = result.begin(); item != result.end(); ++ item)
172 			{
173 				TextBox* text = _parent->createWidget<TextBox>(mTextSkin, IntCoord(0, 0, defaultSize, defaultSize), Align::Default);
174 				text->setCaption(*item);
175 				if (mBold)
176 				{
177 					if (mItalic)
178 						text->setFontName(mBoldItalicFont);
179 					else
180 						text->setFontName(mBoldFont);
181 				}
182 				else if (mItalic)
183 				{
184 					text->setFontName(mItalicFont);
185 				}
186 				else if (mHeader1)
187 				{
188 					text->setFontName(mHeader1Font);
189 				}
190 				else if (mHeader2)
191 				{
192 					text->setFontName(mHeader2Font);
193 				}
194 				else if (mHeader3)
195 				{
196 					text->setFontName(mHeader3Font);
197 				}
198 
199 				if (mColour)
200 				{
201 					text->setTextColour(mColourValue);
202 				}
203 
204 				if (mStrike)
205 				{
206 					Widget* line = text->createWidget<Widget>(mLineSkin, IntCoord(0, 0, defaultSize, 1), Align::HStretch | Align::VCenter);
207 					line->setColour(Colour::Black);
208 					line->setNeedMouseFocus(false);
209 					if (mColour)
210 						line->setColour(mColourValue);
211 				}
212 
213 				if (mUnder)
214 				{
215 					Widget* line = text->createWidget<Widget>(mLineSkin, IntCoord(0, defaultSize - 1, defaultSize, 1), Align::HStretch | Align::Bottom);
216 					line->setColour(Colour::Black);
217 					line->setNeedMouseFocus(false);
218 					if (mColour)
219 						line->setColour(mColourValue);
220 				}
221 			}
222 		}
223 	}
224 
parseTag(const std::string & _value)225 	void HyperTextBox::parseTag(const std::string& _value)
226 	{
227 		const std::string imageStartTagName = "<img";
228 		const std::string imageEndTagName = ">";
229 
230 		const std::string paragraphStartTagName = "<p";
231 		const std::string paragraphEndTagName = ">";
232 
233 		const std::string colourStartTagName = "<color";
234 		const std::string colourEndTagName = ">";
235 
236 		const std::string urlStartTagName = "<url";
237 		const std::string urlEndTagName = ">";
238 
239 		if (_value == "<h1>")
240 		{
241 			mHeader1 = true;
242 		}
243 		else if (_value == "</h1>")
244 		{
245 			mHeader1 = false;
246 		}
247 		else if (_value == "<h2>")
248 		{
249 			mHeader2 = true;
250 		}
251 		else if (_value == "</h2>")
252 		{
253 			mHeader2 = false;
254 		}
255 		else if (_value == "<h3>")
256 		{
257 			mHeader3 = true;
258 		}
259 		else if (_value == "</h3>")
260 		{
261 			mHeader3 = false;
262 		}
263 		else if (_value == "<b>")
264 		{
265 			mBold = true;
266 		}
267 		else if (_value == "</b>")
268 		{
269 			mBold = false;
270 		}
271 		else if (_value == "<i>")
272 		{
273 			mItalic = true;
274 		}
275 		else if (_value == "</i>")
276 		{
277 			mItalic = false;
278 		}
279 		else if (_value == "<s>")
280 		{
281 			mStrike = true;
282 		}
283 		else if (_value == "</s>")
284 		{
285 			mStrike = false;
286 		}
287 		else if (_value == "<u>")
288 		{
289 			mUnder = true;
290 		}
291 		else if (_value == "</u>")
292 		{
293 			mUnder = false;
294 		}
295 		else if (utility::startWith(_value, colourStartTagName))
296 		{
297 			mColour = true;
298 			mColourValue = Colour::Black;
299 
300 			const std::string colourTagName = "value=";
301 
302 			std::string valueColour = _value.substr(colourStartTagName.size(), _value.size() - (colourStartTagName.size() + colourEndTagName.size()));
303 			VectorString result = utility::split(valueColour);
304 			for (VectorString::const_iterator item = result.begin(); item != result.end(); ++ item)
305 			{
306 				if (utility::startWith(*item, colourTagName))
307 				{
308 					if ((colourTagName.size() + 2) < ((*item).size()))
309 					{
310 						std::string value = (*item).substr(colourTagName.size() + 1, (*item).size() - (colourTagName.size() + 2));
311 						mColourValue = Colour::parse(value);
312 					}
313 				}
314 			}
315 		}
316 		else if (_value == "</color>")
317 		{
318 			mColour = false;
319 		}
320 		else if (utility::startWith(_value, urlStartTagName))
321 		{
322 			mUrl = true;
323 			mUrlValue.clear();
324 
325 			const std::string urlTagName = "value=";
326 
327 			std::string valueUrl = _value.substr(urlStartTagName.size(), _value.size() - (urlStartTagName.size() + urlEndTagName.size()));
328 			VectorString result = utility::split(valueUrl);
329 			for (VectorString::const_iterator item = result.begin(); item != result.end(); ++ item)
330 			{
331 				if (utility::startWith(*item, urlTagName))
332 				{
333 					if ((urlTagName.size() + 2) < ((*item).size()))
334 					{
335 						mUrlValue = (*item).substr(urlTagName.size() + 1, (*item).size() - (urlTagName.size() + 2));
336 					}
337 				}
338 			}
339 		}
340 		else if (_value == "</url>")
341 		{
342 			mUrl = false;
343 		}
344 		else if (utility::startWith(_value, paragraphStartTagName))
345 		{
346 			mCurrentWrapPanel = mStackPanel->createWidget<WrapPanel>(mParagraphSkin, IntCoord(), Align::Default);
347 			mCurrentWrapPanel->setContentAlign(Align::Left | Align::Bottom);
348 			mCurrentWrapPanel->setSpacer(mSpacer);
349 
350 			Align alignResult = Align::Default;
351 			bool needAlign = false;
352 
353 			Align floatResult = Align::Default;
354 			bool needFloat = false;
355 
356 			const std::string alightTagName = "align=";
357 			const std::string floatTagName = "float=";
358 
359 			std::string valueParagraph = _value.substr(paragraphStartTagName.size(), _value.size() - (paragraphStartTagName.size() + paragraphEndTagName.size()));
360 			VectorString result = utility::split(valueParagraph);
361 			for (VectorString::const_iterator item = result.begin(); item != result.end(); ++ item)
362 			{
363 				if (utility::startWith(*item, alightTagName))
364 				{
365 					if ((alightTagName.size() + 2) < ((*item).size()))
366 					{
367 						needAlign = true;
368 						std::string value = (*item).substr(alightTagName.size() + 1, (*item).size() - (alightTagName.size() + 2));
369 						if (value == "left")
370 							alignResult = Align::Default;
371 						else if (value == "center")
372 							alignResult = Align::HCenter | Align::Top;
373 						else if (value == "right")
374 							alignResult = Align::Right | Align::Top;
375 						else
376 							alignResult = Align::Default;
377 					}
378 				}
379 				else if (utility::startWith(*item, floatTagName))
380 				{
381 					if ((floatTagName.size() + 2) < ((*item).size()))
382 					{
383 						needFloat = true;
384 						std::string value = (*item).substr(floatTagName.size() + 1, (*item).size() - (floatTagName.size() + 2));
385 						if (value == "left")
386 							floatResult = Align::Default;
387 						else if (value == "center")
388 							floatResult = Align::HCenter | Align::Top;
389 						else if (value == "right")
390 							floatResult = Align::Right | Align::Top;
391 						else
392 							floatResult = Align::Default;
393 					}
394 				}
395 			}
396 
397 			if (needAlign)
398 			{
399 				mCurrentWrapPanel->setContentAlign(alignResult);
400 			}
401 			if (needFloat)
402 			{
403 				mCurrentWrapPanel->setContentFloat(true);
404 				mCurrentWrapPanel->setSnapFloat(floatResult);
405 			}
406 		}
407 		else if (_value == "</p>")
408 		{
409 			mCurrentWrapPanel = nullptr;
410 		}
411 		else if (utility::startWith(_value, imageStartTagName))
412 		{
413 			mImageSize.clear();
414 			mImage = true;
415 
416 			const std::string widthTagName = "width=";
417 			const std::string heightTagName = "height=";
418 
419 			std::string valueImage = _value.substr(imageStartTagName.size(), _value.size() - (imageStartTagName.size() + imageEndTagName.size()));
420 			VectorString result = utility::split(valueImage);
421 			for (VectorString::const_iterator item = result.begin(); item != result.end(); ++ item)
422 			{
423 				if (utility::startWith(*item, widthTagName))
424 				{
425 					if ((widthTagName.size() + 2) < ((*item).size()))
426 					{
427 						std::string value = (*item).substr(widthTagName.size() + 1, (*item).size() - (widthTagName.size() + 2));
428 						mImageSize.width = utility::parseValue<int>(value);
429 					}
430 				}
431 				else if (utility::startWith(*item, heightTagName))
432 				{
433 					if ((heightTagName.size() + 2) < ((*item).size()))
434 					{
435 						std::string value = (*item).substr(heightTagName.size() + 1, (*item).size() - (heightTagName.size() + 2));
436 						mImageSize.height = utility::parseValue<int>(value);
437 					}
438 				}
439 			}
440 		}
441 		else if (_value == "</img>")
442 		{
443 			mImage = false;
444 		}
445 		else if (_value == "<br/>")
446 		{
447 			if (mCurrentWrapPanel == nullptr)
448 			{
449 				WrapPanel* panel = mStackPanel->createWidget<WrapPanel>(mParagraphSkin, IntCoord(), Align::Default);
450 				panel->setContentAlign(Align::Left | Align::Bottom);
451 				panel->setSpacer(mSpacer);
452 				panel->createWidget<Widget>("Default", IntCoord(0, 0, 0, mBreakHeight), Align::Default);
453 			}
454 		}
455 		else if (_value == "<t/>")
456 		{
457 			if (mCurrentWrapPanel != nullptr)
458 			{
459 				const int countInTab = 4;
460 				mCurrentWrapPanel->createWidget<Widget>("Default", IntCoord(0, 0, countInTab * mSpacer.width, 0), Align::Default);
461 			}
462 		}
463 	}
464 
OnTextLostFocus(Widget * _sender,Widget * _new)465 	void HyperTextBox::OnTextLostFocus(Widget* _sender, Widget* _new)
466 	{
467 		size_t count = _sender->getChildCount();
468 		if (count > 0)
469 			_sender->getChildAt(0)->setVisible(false);
470 	}
471 
OnTextSetFocus(Widget * _sender,Widget * _old)472 	void HyperTextBox::OnTextSetFocus(Widget* _sender, Widget* _old)
473 	{
474 		size_t count = _sender->getChildCount();
475 		if (count > 0)
476 			_sender->getChildAt(0)->setVisible(true);
477 	}
478 
OnTextClick(Widget * _sender)479 	void HyperTextBox::OnTextClick(Widget* _sender)
480 	{
481 		std::string url = _sender->getUserString("URL");
482 		eventUrlClick(this, url);
483 	}
484 
updateContent()485 	void HyperTextBox::updateContent()
486 	{
487 		mStackPanel->setSpacer(IntSize(0, mSpacer.height));
488 		mScrollViewPanel->updateContent();
489 	}
490 
getSpacer() const491 	const IntSize& HyperTextBox::getSpacer() const
492 	{
493 		return mSpacer;
494 	}
495 
setSpacer(const IntSize & _value)496 	void HyperTextBox::setSpacer(const IntSize& _value)
497 	{
498 		mSpacer = _value;
499 	}
500 
getHeader1Font() const501 	const std::string& HyperTextBox::getHeader1Font() const
502 	{
503 		return mHeader1Font;
504 	}
505 
setHeader1Font(const std::string & _value)506 	void HyperTextBox::setHeader1Font(const std::string& _value)
507 	{
508 		mHeader1Font = _value;
509 	}
510 
getHeader2Font() const511 	const std::string& HyperTextBox::getHeader2Font() const
512 	{
513 		return mHeader2Font;
514 	}
515 
setHeader2Font(const std::string & _value)516 	void HyperTextBox::setHeader2Font(const std::string& _value)
517 	{
518 		mHeader2Font = _value;
519 	}
520 
getHeader3Font() const521 	const std::string& HyperTextBox::getHeader3Font() const
522 	{
523 		return mHeader3Font;
524 	}
525 
setHeader3Font(const std::string & _value)526 	void HyperTextBox::setHeader3Font(const std::string& _value)
527 	{
528 		mHeader3Font = _value;
529 	}
530 
getDefaultFont() const531 	const std::string& HyperTextBox::getDefaultFont() const
532 	{
533 		return mDefaultFont;
534 	}
535 
setDefaultFont(const std::string & _value)536 	void HyperTextBox::setDefaultFont(const std::string& _value)
537 	{
538 		mDefaultFont = _value;
539 		updateBreakHeight();
540 	}
541 
getBoldFont() const542 	const std::string& HyperTextBox::getBoldFont() const
543 	{
544 		return mBoldFont;
545 	}
546 
setBoldFont(const std::string & _value)547 	void HyperTextBox::setBoldFont(const std::string& _value)
548 	{
549 		mBoldFont = _value;
550 	}
551 
getItalicFont() const552 	const std::string& HyperTextBox::getItalicFont() const
553 	{
554 		return mItalicFont;
555 	}
556 
setItalicFont(const std::string & _value)557 	void HyperTextBox::setItalicFont(const std::string& _value)
558 	{
559 		mItalicFont = _value;
560 	}
561 
getBoldItalicFont() const562 	const std::string& HyperTextBox::getBoldItalicFont() const
563 	{
564 		return mBoldItalicFont;
565 	}
566 
setBoldItalicFont(const std::string & _value)567 	void HyperTextBox::setBoldItalicFont(const std::string& _value)
568 	{
569 		mBoldItalicFont =_value;
570 	}
571 
setPropertyOverride(const std::string & _key,const std::string & _value)572 	void HyperTextBox::setPropertyOverride(const std::string& _key, const std::string& _value)
573 	{
574 		if (_key == "Spacer")
575 			setSpacer(utility::parseValue<IntSize>(_value));
576 		else if (_key == "DefaultFont")
577 			setDefaultFont(_value);
578 		else if (_key == "BoldFont")
579 			setBoldFont(_value);
580 		else if (_key == "ItalicFont")
581 			setItalicFont(_value);
582 		else if (_key == "BoldItalicFont")
583 			setBoldItalicFont(_value);
584 		else if (_key == "Header1Font")
585 			setHeader1Font(_value);
586 		else if (_key == "Header2Font")
587 			setHeader2Font(_value);
588 		else if (_key == "Header3Font")
589 			setHeader3Font(_value);
590 		else
591 		{
592 			Base::setPropertyOverride(_key, _value);
593 			return;
594 		}
595 		eventChangeProperty(this, _key, _value);
596 	}
597 
setCaption(const UString & _value)598 	void HyperTextBox::setCaption(const UString& _value)
599 	{
600 		removeAllItems();
601 
602 		addItem(_value);
603 
604 		updateContent();
605 	}
606 
removeAllItems()607 	void HyperTextBox::removeAllItems()
608 	{
609 		while (mStackPanel->getChildCount() != 0)
610 			WidgetManager::getInstancePtr()->destroyWidget(mStackPanel->getChildAt(0));
611 	}
612 
getItemsCount() const613 	size_t HyperTextBox::getItemsCount() const
614 	{
615 		return mStackPanel->getChildCount();
616 	}
617 
removeItemAt(size_t _index)618 	void HyperTextBox::removeItemAt(size_t _index)
619 	{
620 		MYGUI_ASSERT_RANGE(_index, mStackPanel->getChildCount(), "HyperTextBox::removeItemAt");
621 		WidgetManager::getInstancePtr()->destroyWidget(mStackPanel->getChildAt(_index));
622 	}
623 
updateBreakHeight()624 	void HyperTextBox::updateBreakHeight()
625 	{
626 		mBreakHeight = 0;
627 
628 		IFont* font = FontManager::getInstancePtr()->getByName(getDefaultFont());
629 		if (font != nullptr)
630 			mBreakHeight = font->getDefaultHeight();
631 	}
632 
633 } // namespace MyGUI
634