456 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			456 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
| #include "..\e2dnode.h"
 | ||
| 
 | ||
| 
 | ||
| e2d::Text::Text()
 | ||
| 	: _style()
 | ||
| 	, _textLayout(nullptr)
 | ||
| 	, _textFormat(nullptr)
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| e2d::Text::Text(const String& text)
 | ||
| 	: _style()
 | ||
| 	, _textLayout(nullptr)
 | ||
| 	, _textFormat(nullptr)
 | ||
| 	, _text(text)
 | ||
| {
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| e2d::Text::Text(TextStyle textStyle)
 | ||
| 	: _style(textStyle)
 | ||
| 	, _textLayout(nullptr)
 | ||
| 	, _textFormat(nullptr)
 | ||
| {
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| e2d::Text::Text(const String& text, TextStyle textStyle)
 | ||
| 	: _style(textStyle)
 | ||
| 	, _textLayout(nullptr)
 | ||
| 	, _textFormat(nullptr)
 | ||
| 	, _text(text)
 | ||
| {
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| e2d::Text::Text(
 | ||
| 	const String& text, 
 | ||
| 	const String& fontFamily, 
 | ||
| 	double fontSize, 
 | ||
| 	UINT32 color, 
 | ||
| 	UINT32 fontWeight, 
 | ||
| 	bool italic, 
 | ||
| 	TextAlign alignment,
 | ||
| 	bool wrapping,
 | ||
| 	double wrappingWidth,
 | ||
| 	double lineSpacing,
 | ||
| 	bool hasUnderline, 
 | ||
| 	bool hasStrikethrough,
 | ||
| 	bool hasOutline,
 | ||
| 	UINT32 outlineColor,
 | ||
| 	UINT32 outlineWidth
 | ||
| )
 | ||
| 	: _style(
 | ||
| 		fontFamily, 
 | ||
| 		fontSize, 
 | ||
| 		color, 
 | ||
| 		fontWeight, 
 | ||
| 		italic, 
 | ||
| 		alignment,
 | ||
| 		wrapping,
 | ||
| 		wrappingWidth,
 | ||
| 		lineSpacing,
 | ||
| 		hasUnderline, 
 | ||
| 		hasStrikethrough, 
 | ||
| 		hasOutline, 
 | ||
| 		outlineColor,
 | ||
| 		outlineWidth
 | ||
| 	)
 | ||
| 	, _textLayout(nullptr)
 | ||
| 	, _textFormat(nullptr)
 | ||
| 	, _text(text)
 | ||
| {
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| e2d::Text * e2d::Text::create()
 | ||
| {
 | ||
| 	return Create<Text>();
 | ||
| }
 | ||
| 
 | ||
| e2d::Text * e2d::Text::create(const String & text)
 | ||
| {
 | ||
| 	return Create<Text>(text);
 | ||
| }
 | ||
| 
 | ||
| e2d::Text * e2d::Text::create(TextStyle textStyle)
 | ||
| {
 | ||
| 	return Create<Text>(textStyle);
 | ||
| }
 | ||
| 
 | ||
| e2d::Text * e2d::Text::create(const String & text, TextStyle textStyle)
 | ||
| {
 | ||
| 	return Create<Text>(text, textStyle);
 | ||
| }
 | ||
| 
 | ||
| e2d::Text * e2d::Text::create(const String & text, const String & fontFamily, double fontSize, UINT32 color, UINT32 fontWeight, bool italic, TextAlign alignment, bool wrapping, double wrappingWidth, double lineSpacing, bool hasUnderline, bool hasStrikethrough, bool hasOutline, UINT32 outlineColor, UINT32 outlineWidth)
 | ||
| {
 | ||
| 	return Create<Text>(text, fontFamily, fontSize, color, fontWeight, italic, alignment, wrapping, wrappingWidth, lineSpacing, hasUnderline, hasStrikethrough, hasOutline, outlineColor, outlineWidth);
 | ||
| }
 | ||
| 
 | ||
| e2d::Text::~Text()
 | ||
| {
 | ||
| 	SafeReleaseInterface(_textFormat);
 | ||
| 	SafeReleaseInterface(_textLayout);
 | ||
| }
 | ||
| 
 | ||
| e2d::String e2d::Text::getText() const
 | ||
| {
 | ||
| 	return _text;
 | ||
| }
 | ||
| 
 | ||
| e2d::TextStyle e2d::Text::getTextStyle() const
 | ||
| {
 | ||
| 	return _style;
 | ||
| }
 | ||
| 
 | ||
| e2d::String e2d::Text::getFontFamily() const
 | ||
| {
 | ||
| 	return _style.fontFamily;
 | ||
| }
 | ||
| 
 | ||
| double e2d::Text::getFontSize() const
 | ||
| {
 | ||
| 	return _style.fontSize;
 | ||
| }
 | ||
| 
 | ||
| UINT32 e2d::Text::getFontWeight() const
 | ||
| {
 | ||
| 	return _style.fontWeight;
 | ||
| }
 | ||
| 
 | ||
| e2d::Color e2d::Text::getColor() const
 | ||
| {
 | ||
| 	return _style.color;
 | ||
| }
 | ||
| 
 | ||
| e2d::Color e2d::Text::getOutlineColor() const
 | ||
| {
 | ||
| 	return _style.outlineColor;
 | ||
| }
 | ||
| 
 | ||
| double e2d::Text::getOutlineWidth() const
 | ||
| {
 | ||
| 	return _style.outlineWidth;
 | ||
| }
 | ||
| 
 | ||
| e2d::LineJoin e2d::Text::getOutlineJoin() const
 | ||
| {
 | ||
| 	return _style.outlineJoin;
 | ||
| }
 | ||
| 
 | ||
| int e2d::Text::getLineCount() const
 | ||
| {
 | ||
| 	if (_textLayout)
 | ||
| 	{
 | ||
| 		DWRITE_TEXT_METRICS metrics;
 | ||
| 		_textLayout->GetMetrics(&metrics);
 | ||
| 		return static_cast<int>(metrics.lineCount);
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		return 0;
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| bool e2d::Text::isItalic() const
 | ||
| {
 | ||
| 	return _style.italic;
 | ||
| }
 | ||
| 
 | ||
| bool e2d::Text::hasStrikethrough() const
 | ||
| {
 | ||
| 	return _style.hasStrikethrough;
 | ||
| }
 | ||
| 
 | ||
| bool e2d::Text::hasUnderline() const
 | ||
| {
 | ||
| 	return _style.hasUnderline;
 | ||
| }
 | ||
| 
 | ||
| bool e2d::Text::hasOutline() const
 | ||
| {
 | ||
| 	return _style.hasOutline;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setText(const String& text)
 | ||
| {
 | ||
| 	_text = text;
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setStyle(const TextStyle& textStyle)
 | ||
| {
 | ||
| 	_style = textStyle;
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setFontFamily(const String& fontFamily)
 | ||
| {
 | ||
| 	_style.fontFamily = fontFamily;
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setFontSize(double fontSize)
 | ||
| {
 | ||
| 	_style.fontSize = fontSize;
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setFontWeight(UINT32 fontWeight)
 | ||
| {
 | ||
| 	_style.fontWeight = fontWeight;
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setColor(Color color)
 | ||
| {
 | ||
| 	_style.color = color;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setItalic(bool value)
 | ||
| {
 | ||
| 	_style.italic = value;
 | ||
| 	_reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setWrapping(bool wrapping)
 | ||
| {
 | ||
| 	if (_style.wrapping != wrapping)
 | ||
| 	{
 | ||
| 		_style.wrapping = wrapping;
 | ||
| 		_reset();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setWrappingWidth(double wrappingWidth)
 | ||
| {
 | ||
| 	if (_style.wrappingWidth != wrappingWidth)
 | ||
| 	{
 | ||
| 		_style.wrappingWidth = max(wrappingWidth, 0);
 | ||
| 
 | ||
| 		if (_style.wrapping)
 | ||
| 		{
 | ||
| 			_reset();
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setLineSpacing(double lineSpacing)
 | ||
| {
 | ||
| 	if (_style.lineSpacing != lineSpacing)
 | ||
| 	{
 | ||
| 		_style.lineSpacing = lineSpacing;
 | ||
| 		_reset();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setAlignment(TextAlign align)
 | ||
| {
 | ||
| 	if (_style.alignment != align)
 | ||
| 	{
 | ||
| 		_style.alignment = align;
 | ||
| 		_reset();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setUnderline(bool hasUnderline)
 | ||
| {
 | ||
| 	if (_style.hasUnderline != hasUnderline)
 | ||
| 	{
 | ||
| 		_style.hasUnderline = hasUnderline;
 | ||
| 		if (!_textFormat)
 | ||
| 			_createFormat();
 | ||
| 		_createLayout();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setStrikethrough(bool hasStrikethrough)
 | ||
| {
 | ||
| 	if (_style.hasStrikethrough != hasStrikethrough)
 | ||
| 	{
 | ||
| 		_style.hasStrikethrough = hasStrikethrough;
 | ||
| 		if (!_textFormat)
 | ||
| 			_createFormat();
 | ||
| 		_createLayout();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setOutline(bool hasOutline)
 | ||
| {
 | ||
| 	_style.hasOutline = hasOutline;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setOutlineColor(Color outlineColor)
 | ||
| {
 | ||
| 	_style.outlineColor = outlineColor;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setOutlineWidth(double outlineWidth)
 | ||
| {
 | ||
| 	_style.outlineWidth = outlineWidth;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::setOutlineJoin(LineJoin outlineJoin)
 | ||
| {
 | ||
| 	_style.outlineJoin = outlineJoin;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::onRender()
 | ||
| {
 | ||
| 	if (_textLayout)
 | ||
| 	{
 | ||
| 		// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 		D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, _width, _height);
 | ||
| 		// <20><><EFBFBD>û<EFBFBD>ˢ<EFBFBD><CBA2>ɫ<EFBFBD><C9AB><EFBFBD><CDB8><EFBFBD><EFBFBD>
 | ||
| 		Renderer::getSolidColorBrush()->SetOpacity(_displayOpacity);
 | ||
| 		// <20><>ȡ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>Ⱦ<EFBFBD><C8BE>
 | ||
| 		auto pTextRenderer = Renderer::getCustomTextRenderer();
 | ||
| 		pTextRenderer->SetTextStyle(
 | ||
| 			_style.color.toColorF(),
 | ||
| 			_style.hasOutline,
 | ||
| 			_style.outlineColor.toColorF(),
 | ||
| 			float(_style.outlineWidth),
 | ||
| 			D2D1_LINE_JOIN(_style.outlineJoin)
 | ||
| 		);
 | ||
| 		_textLayout->Draw(NULL, pTextRenderer, 0, 0);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::_reset()
 | ||
| {
 | ||
| 	// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD>ʽ<EFBFBD><CABD>
 | ||
| 	_createFormat();
 | ||
| 	// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD>
 | ||
| 	_createLayout();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::_createFormat()
 | ||
| {
 | ||
| 	SafeReleaseInterface(_textFormat);
 | ||
| 
 | ||
| 	HRESULT hr = Renderer::getIDWriteFactory()->CreateTextFormat(
 | ||
| 		_style.fontFamily,
 | ||
| 		NULL,
 | ||
| 		DWRITE_FONT_WEIGHT(_style.fontWeight),
 | ||
| 		_style.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
 | ||
| 		DWRITE_FONT_STRETCH_NORMAL,
 | ||
| 		float(_style.fontSize),
 | ||
| 		L"",
 | ||
| 		&_textFormat
 | ||
| 	);
 | ||
| 
 | ||
| 	ASSERT(SUCCEEDED(hr), "Create IDWriteTextFormat Failed!");
 | ||
| 
 | ||
| 	if (_textFormat)
 | ||
| 	{
 | ||
| 		// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD><D6B6>뷽ʽ
 | ||
| 		_textFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(_style.alignment));
 | ||
| 		// <20><><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD>
 | ||
| 		if (_style.lineSpacing == 0.0)
 | ||
| 		{
 | ||
| 			_textFormat->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
 | ||
| 		}
 | ||
| 		else
 | ||
| 		{
 | ||
| 			_textFormat->SetLineSpacing(
 | ||
| 				DWRITE_LINE_SPACING_METHOD_UNIFORM,
 | ||
| 				float(_style.lineSpacing),
 | ||
| 				float(_style.lineSpacing) * 0.8f
 | ||
| 			);
 | ||
| 		}
 | ||
| 		// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 		if (_style.wrapping)
 | ||
| 		{
 | ||
| 			_textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
 | ||
| 		}
 | ||
| 		else
 | ||
| 		{
 | ||
| 			_textFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::_createLayout()
 | ||
| {
 | ||
| 	SafeReleaseInterface(_textLayout);
 | ||
| 
 | ||
| 	// <20>ı<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 	if (_text.isEmpty())
 | ||
| 	{
 | ||
| 		this->setSize(0, 0);
 | ||
| 		return;
 | ||
| 	}
 | ||
| 
 | ||
| 	if (_textFormat == nullptr)
 | ||
| 	{
 | ||
| 		WARN_IF(true, "Text::_createLayout failed! _textFormat NULL pointer exception.");
 | ||
| 		return;
 | ||
| 	}
 | ||
| 	
 | ||
| 	UINT32 length = UINT32(_text.getLength());
 | ||
| 
 | ||
| 	// <20><><EFBFBD><EFBFBD> TextLayout
 | ||
| 	HRESULT hr;
 | ||
| 	// <20><><EFBFBD>ı<EFBFBD><C4B1>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD>д<EFBFBD><D0B4><EFBFBD>
 | ||
| 	if (_style.wrapping)
 | ||
| 	{
 | ||
| 		hr = Renderer::getIDWriteFactory()->CreateTextLayout(
 | ||
| 			_text,
 | ||
| 			length,
 | ||
| 			_textFormat,
 | ||
| 			float(_style.wrappingWidth),
 | ||
| 			0,
 | ||
| 			&_textLayout
 | ||
| 		);
 | ||
| 		if (_textLayout)
 | ||
| 		{
 | ||
| 			// <20><>ȡ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD>ֵĿ<D6B5><C4BF>Ⱥ߶<CDB8>
 | ||
| 			DWRITE_TEXT_METRICS metrics;
 | ||
| 			_textLayout->GetMetrics(&metrics);
 | ||
| 			// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 			this->setSize(metrics.layoutWidth, metrics.height);
 | ||
| 		}
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		hr = Renderer::getIDWriteFactory()->CreateTextLayout(_text, length, _textFormat, 0, 0, &_textLayout);
 | ||
| 		// Ϊ<><CEAA>ֹ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>⣬<EFBFBD><E2A3AC><EFBFBD>ݸղŴ<D5B2><C5B4><EFBFBD><EFBFBD><EFBFBD> layout <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>´<EFBFBD><C2B4><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 		if (_textLayout)
 | ||
| 		{
 | ||
| 			// <20><>ȡ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD>ֵĿ<D6B5><C4BF>Ⱥ߶<CDB8>
 | ||
| 			DWRITE_TEXT_METRICS metrics;
 | ||
| 			_textLayout->GetMetrics(&metrics);
 | ||
| 			// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 			this->setSize(metrics.width, metrics.height);
 | ||
| 			// <20><><EFBFBD>´<EFBFBD><C2B4><EFBFBD> layout
 | ||
| 			SafeReleaseInterface(_textLayout);
 | ||
| 			hr = Renderer::getIDWriteFactory()->CreateTextLayout(_text, length, _textFormat, _width, 0, &_textLayout);
 | ||
| 		}
 | ||
| 	}
 | ||
| 
 | ||
| 	ASSERT(SUCCEEDED(hr), "Create IDWriteTextFormat Failed!");
 | ||
| 
 | ||
| 	// <20><><EFBFBD><EFBFBD><EFBFBD>»<EFBFBD><C2BB>ߺ<EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>
 | ||
| 	DWRITE_TEXT_RANGE range = { 0, length };
 | ||
| 	if (_style.hasUnderline)
 | ||
| 	{
 | ||
| 		_textLayout->SetUnderline(true, range);
 | ||
| 	}
 | ||
| 	if (_style.hasStrikethrough)
 | ||
| 	{
 | ||
| 		_textLayout->SetStrikethrough(true, range);
 | ||
| 	}
 | ||
| }
 |