450 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			450 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C++
		
	
	
	
| #include "..\e2dnode.h"
 | ||
| #include "..\e2dmodule.h"
 | ||
| 
 | ||
| //-------------------------------------------------------
 | ||
| // Style
 | ||
| //-------------------------------------------------------
 | ||
| 
 | ||
| e2d::Text::Style::Style()
 | ||
| 	: color(Color::White)
 | ||
| 	, alignment(Align::Left)
 | ||
| 	, wrap(false)
 | ||
| 	, wrap_width(0.f)
 | ||
| 	, line_spacing(0.f)
 | ||
| 	, underline(false)
 | ||
| 	, strikethrough(false)
 | ||
| 	, outline(true)
 | ||
| 	, outline_color(Color(Color::Black, 0.5))
 | ||
| 	, outline_width(1.f)
 | ||
| 	, outline_stroke(Stroke::Round)
 | ||
| {}
 | ||
| 
 | ||
| e2d::Text::Style::Style(
 | ||
| 	Color color,
 | ||
| 	Align alignment,
 | ||
| 	bool wrap,
 | ||
| 	float wrap_width,
 | ||
| 	float line_spacing,
 | ||
| 	bool underline,
 | ||
| 	bool strikethrough,
 | ||
| 	bool outline,
 | ||
| 	Color outline_color,
 | ||
| 	float outline_width,
 | ||
| 	Stroke outline_stroke
 | ||
| )
 | ||
| 	: color(color)
 | ||
| 	, alignment(alignment)
 | ||
| 	, wrap(wrap)
 | ||
| 	, wrap_width(wrap_width)
 | ||
| 	, line_spacing(line_spacing)
 | ||
| 	, underline(underline)
 | ||
| 	, strikethrough(strikethrough)
 | ||
| 	, outline(outline)
 | ||
| 	, outline_color(outline_color)
 | ||
| 	, outline_width(outline_width)
 | ||
| 	, outline_stroke(outline_stroke)
 | ||
| {}
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| //-------------------------------------------------------
 | ||
| // Text
 | ||
| //-------------------------------------------------------
 | ||
| 
 | ||
| e2d::Text::Text()
 | ||
| 	: font_()
 | ||
| 	, style_()
 | ||
| 	, text_layout_(nullptr)
 | ||
| 	, text_format_(nullptr)
 | ||
| {
 | ||
| }
 | ||
| 
 | ||
| e2d::Text::Text(const String & text, const Font & font, const Style & style)
 | ||
| 	: font_(font)
 | ||
| 	, style_(style)
 | ||
| 	, text_layout_(nullptr)
 | ||
| 	, text_format_(nullptr)
 | ||
| 	, text_(text)
 | ||
| {
 | ||
| 	Reset();
 | ||
| }
 | ||
| 
 | ||
| e2d::Text::~Text()
 | ||
| {
 | ||
| 	SafeRelease(text_format_);
 | ||
| 	SafeRelease(text_layout_);
 | ||
| }
 | ||
| 
 | ||
| const e2d::String& e2d::Text::GetText() const
 | ||
| {
 | ||
| 	return text_;
 | ||
| }
 | ||
| 
 | ||
| const e2d::Font& e2d::Text::GetFont() const
 | ||
| {
 | ||
| 	return font_;
 | ||
| }
 | ||
| 
 | ||
| const e2d::Text::Style& e2d::Text::GetStyle() const
 | ||
| {
 | ||
| 	return style_;
 | ||
| }
 | ||
| 
 | ||
| const e2d::String& e2d::Text::GetFontFamily() const
 | ||
| {
 | ||
| 	return font_.family;
 | ||
| }
 | ||
| 
 | ||
| float e2d::Text::GetFontSize() const
 | ||
| {
 | ||
| 	return font_.size;
 | ||
| }
 | ||
| 
 | ||
| UINT e2d::Text::GetFontWeight() const
 | ||
| {
 | ||
| 	return font_.weight;
 | ||
| }
 | ||
| 
 | ||
| const e2d::Color& e2d::Text::GetColor() const
 | ||
| {
 | ||
| 	return style_.color;
 | ||
| }
 | ||
| 
 | ||
| const e2d::Color& e2d::Text::GetOutlineColor() const
 | ||
| {
 | ||
| 	return style_.outline_color;
 | ||
| }
 | ||
| 
 | ||
| float e2d::Text::GetOutlineWidth() const
 | ||
| {
 | ||
| 	return style_.outline_width;
 | ||
| }
 | ||
| 
 | ||
| e2d::Stroke e2d::Text::GetOutlineStroke() const
 | ||
| {
 | ||
| 	return style_.outline_stroke;
 | ||
| }
 | ||
| 
 | ||
| int e2d::Text::GetLineCount() const
 | ||
| {
 | ||
| 	if (text_layout_)
 | ||
| 	{
 | ||
| 		DWRITE_TEXT_METRICS metrics;
 | ||
| 		text_layout_->GetMetrics(&metrics);
 | ||
| 		return static_cast<int>(metrics.lineCount);
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		return 0;
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| bool e2d::Text::IsItalic() const
 | ||
| {
 | ||
| 	return font_.italic;
 | ||
| }
 | ||
| 
 | ||
| bool e2d::Text::strikethrough() const
 | ||
| {
 | ||
| 	return style_.strikethrough;
 | ||
| }
 | ||
| 
 | ||
| bool e2d::Text::underline() const
 | ||
| {
 | ||
| 	return style_.underline;
 | ||
| }
 | ||
| 
 | ||
| bool e2d::Text::outline() const
 | ||
| {
 | ||
| 	return style_.outline;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetText(const String& text)
 | ||
| {
 | ||
| 	text_ = text;
 | ||
| 	Reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetStyle(const Style& style)
 | ||
| {
 | ||
| 	style_ = style;
 | ||
| 	Reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetFont(const Font & font)
 | ||
| {
 | ||
| 	font_ = font;
 | ||
| 	Reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetFontFamily(const String& family)
 | ||
| {
 | ||
| 	font_.family = family;
 | ||
| 	Reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetFontSize(float size)
 | ||
| {
 | ||
| 	font_.size = size;
 | ||
| 	Reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetFontWeight(UINT weight)
 | ||
| {
 | ||
| 	font_.weight = weight;
 | ||
| 	Reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetColor(Color color)
 | ||
| {
 | ||
| 	style_.color = color;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetItalic(bool value)
 | ||
| {
 | ||
| 	font_.italic = value;
 | ||
| 	Reset();
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetWrapEnabled(bool wrap)
 | ||
| {
 | ||
| 	if (style_.wrap != wrap)
 | ||
| 	{
 | ||
| 		style_.wrap = wrap;
 | ||
| 		Reset();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetWrapWidth(float wrap_width)
 | ||
| {
 | ||
| 	if (style_.wrap_width != wrap_width)
 | ||
| 	{
 | ||
| 		style_.wrap_width = std::max(wrap_width, 0.f);
 | ||
| 
 | ||
| 		if (style_.wrap)
 | ||
| 		{
 | ||
| 			Reset();
 | ||
| 		}
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetLineSpacing(float line_spacing)
 | ||
| {
 | ||
| 	if (style_.line_spacing != line_spacing)
 | ||
| 	{
 | ||
| 		style_.line_spacing = line_spacing;
 | ||
| 		Reset();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetAlignment(Align align)
 | ||
| {
 | ||
| 	if (style_.alignment != align)
 | ||
| 	{
 | ||
| 		style_.alignment = align;
 | ||
| 		Reset();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetUnderline(bool underline)
 | ||
| {
 | ||
| 	if (style_.underline != underline)
 | ||
| 	{
 | ||
| 		style_.underline = underline;
 | ||
| 		if (!text_format_)
 | ||
| 			CreateFormat();
 | ||
| 		CreateLayout();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetStrikethrough(bool strikethrough)
 | ||
| {
 | ||
| 	if (style_.strikethrough != strikethrough)
 | ||
| 	{
 | ||
| 		style_.strikethrough = strikethrough;
 | ||
| 		if (!text_format_)
 | ||
| 			CreateFormat();
 | ||
| 		CreateLayout();
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetOutline(bool outline)
 | ||
| {
 | ||
| 	style_.outline = outline;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetOutlineColor(Color outline_color)
 | ||
| {
 | ||
| 	style_.outline_color = outline_color;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetOutlineWidth(float outline_width)
 | ||
| {
 | ||
| 	style_.outline_width = outline_width;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::SetOutlineStroke(Stroke outline_stroke)
 | ||
| {
 | ||
| 	style_.outline_stroke = outline_stroke;
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::Draw() const
 | ||
| {
 | ||
| 	if (text_layout_)
 | ||
| 	{
 | ||
| 		auto renderer = Renderer::GetInstance();
 | ||
| 		// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 		D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, size_.width, size_.height);
 | ||
| 		// <20><><EFBFBD>û<EFBFBD>ˢ<EFBFBD><CBA2>ɫ<EFBFBD><C9AB><EFBFBD><CDB8><EFBFBD><EFBFBD>
 | ||
| 		renderer->GetSolidBrush()->SetOpacity(display_opacity_);
 | ||
| 		// <20><>ȡ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>Ⱦ<EFBFBD><C8BE>
 | ||
| 		auto textRenderer = renderer->GetTextRenderer();
 | ||
| 		textRenderer->SetTextStyle(
 | ||
| 			(D2D1_COLOR_F)style_.color,
 | ||
| 			style_.outline,
 | ||
| 			(D2D1_COLOR_F)style_.outline_color,
 | ||
| 			style_.outline_width,
 | ||
| 			D2D1_LINE_JOIN(style_.outline_stroke)
 | ||
| 		);
 | ||
| 		text_layout_->Draw(nullptr, textRenderer, 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()
 | ||
| {
 | ||
| 	SafeRelease(text_format_);
 | ||
| 
 | ||
| 	ThrowIfFailed(
 | ||
| 		Renderer::GetWriteFactory()->CreateTextFormat(
 | ||
| 			(const wchar_t *)font_.family,
 | ||
| 			nullptr,
 | ||
| 			DWRITE_FONT_WEIGHT(font_.weight),
 | ||
| 			font_.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
 | ||
| 			DWRITE_FONT_STRETCH_NORMAL,
 | ||
| 			font_.size,
 | ||
| 			L"",
 | ||
| 			&text_format_
 | ||
| 		)
 | ||
| 	);
 | ||
| 
 | ||
| 	// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD><D6B6>뷽ʽ
 | ||
| 	text_format_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style_.alignment));
 | ||
| 
 | ||
| 	// <20><><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD>
 | ||
| 	if (style_.line_spacing == 0.f)
 | ||
| 	{
 | ||
| 		text_format_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		text_format_->SetLineSpacing(
 | ||
| 			DWRITE_LINE_SPACING_METHOD_UNIFORM,
 | ||
| 			style_.line_spacing,
 | ||
| 			style_.line_spacing * 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_.wrap)
 | ||
| 	{
 | ||
| 		text_format_->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		text_format_->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| void e2d::Text::CreateLayout()
 | ||
| {
 | ||
| 	SafeRelease(text_layout_);
 | ||
| 
 | ||
| 	// <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 (text_format_ == nullptr)
 | ||
| 	{
 | ||
| 		WARN("Text::CreateLayout failed! text_format_ NULL pointer exception.");
 | ||
| 		return;
 | ||
| 	}
 | ||
| 	
 | ||
| 	UINT32 length = (UINT32)text_.GetLength();
 | ||
| 	auto writeFactory = Renderer::GetWriteFactory();
 | ||
| 
 | ||
| 	// <20><><EFBFBD>ı<EFBFBD><C4B1>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD>д<EFBFBD><D0B4><EFBFBD>
 | ||
| 	if (style_.wrap)
 | ||
| 	{
 | ||
| 		ThrowIfFailed(
 | ||
| 			writeFactory->CreateTextLayout(
 | ||
| 				(const wchar_t *)text_,
 | ||
| 				length,
 | ||
| 				text_format_,
 | ||
| 				style_.wrap_width,
 | ||
| 				0,
 | ||
| 				&text_layout_
 | ||
| 			)
 | ||
| 		);
 | ||
| 		// <20><>ȡ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD>ֵĿ<D6B5><C4BF>Ⱥ߶<CDB8>
 | ||
| 		DWRITE_TEXT_METRICS metrics;
 | ||
| 		text_layout_->GetMetrics(&metrics);
 | ||
| 		// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 		this->SetSize(metrics.layoutWidth, metrics.height);
 | ||
| 	}
 | ||
| 	else
 | ||
| 	{
 | ||
| 		// Ϊ<><CEAA>ֹ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>⣬<EFBFBD><E2A3AC><EFBFBD><EFBFBD><EFBFBD>ȴ<EFBFBD><C8B4><EFBFBD> layout <20>Ի<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>
 | ||
| 		ThrowIfFailed(
 | ||
| 			writeFactory->CreateTextLayout(
 | ||
| 				(const wchar_t *)text_,
 | ||
| 				length,
 | ||
| 				text_format_,
 | ||
| 				0,
 | ||
| 				0,
 | ||
| 				&text_layout_
 | ||
| 			)
 | ||
| 		);
 | ||
| 
 | ||
| 		// <20><>ȡ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD>ֵĿ<D6B5><C4BF>Ⱥ߶<CDB8>
 | ||
| 		DWRITE_TEXT_METRICS metrics;
 | ||
| 		text_layout_->GetMetrics(&metrics);
 | ||
| 		// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
 | ||
| 		this->SetSize(metrics.width, metrics.height);
 | ||
| 
 | ||
| 		// <20><><EFBFBD>´<EFBFBD><C2B4><EFBFBD> layout
 | ||
| 		SafeRelease(text_layout_);
 | ||
| 		ThrowIfFailed(
 | ||
| 			writeFactory->CreateTextLayout(
 | ||
| 				(const wchar_t *)text_,
 | ||
| 				length,
 | ||
| 				text_format_,
 | ||
| 				size_.width,
 | ||
| 				0,
 | ||
| 				&text_layout_
 | ||
| 			)
 | ||
| 		);
 | ||
| 	}
 | ||
| 
 | ||
| 	// <20><><EFBFBD><EFBFBD><EFBFBD>»<EFBFBD><C2BB>ߺ<EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>
 | ||
| 	DWRITE_TEXT_RANGE Range = { 0, length };
 | ||
| 	if (style_.underline)
 | ||
| 	{
 | ||
| 		text_layout_->SetUnderline(true, Range);
 | ||
| 	}
 | ||
| 	if (style_.strikethrough)
 | ||
| 	{
 | ||
| 		text_layout_->SetStrikethrough(true, Range);
 | ||
| 	}
 | ||
| }
 |