Magic_Game/core/base/Text.cpp

471 lines
8.8 KiB
C++
Raw Normal View History

2018-10-03 22:02:46 +08:00
// Copyright (c) 2016-2018 Easy2D - Nomango
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#include "Text.h"
#include "render.h"
#include "base.h"
2018-11-08 00:21:59 +08:00
namespace easy2d
{
//-------------------------------------------------------
// Style
//-------------------------------------------------------
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)
{}
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
//-------------------------------------------------------
Text::Text()
: font_()
, style_()
, text_layout_(nullptr)
, text_format_(nullptr)
{
}
Text::Text(const String & text, const Font & font, const Style & style)
2018-11-08 00:21:59 +08:00
: font_(font)
, style_(style)
, text_layout_(nullptr)
, text_format_(nullptr)
, text_(text)
{
Reset();
}
2018-11-08 00:21:59 +08:00
Text::~Text()
{
SafeRelease(text_format_);
SafeRelease(text_layout_);
}
const String& Text::GetText() const
2018-11-08 00:21:59 +08:00
{
return text_;
}
2018-11-08 00:21:59 +08:00
const Font& Text::GetFont() const
{
return font_;
}
2018-11-08 00:21:59 +08:00
const Text::Style& Text::GetStyle() const
2018-04-09 18:41:56 +08:00
{
2018-11-08 00:21:59 +08:00
return style_;
2018-04-09 18:41:56 +08:00
}
2018-11-08 00:21:59 +08:00
const String& Text::GetFontFamily() const
2018-04-09 18:41:56 +08:00
{
2018-11-08 00:21:59 +08:00
return font_.family;
2018-04-09 18:41:56 +08:00
}
2018-11-08 00:21:59 +08:00
float Text::GetFontSize() const
{
return font_.size;
}
2018-11-08 00:21:59 +08:00
UINT Text::GetFontWeight() const
{
return font_.weight;
}
2018-04-22 14:08:29 +08:00
2018-11-08 00:21:59 +08:00
const Color& Text::GetColor() const
{
return style_.color;
}
2018-04-22 14:08:29 +08:00
2018-11-08 00:21:59 +08:00
const Color& Text::GetOutlineColor() const
{
return style_.outline_color;
}
2018-11-08 00:21:59 +08:00
float Text::GetOutlineWidth() const
{
return style_.outline_width;
}
2018-11-08 00:21:59 +08:00
Stroke Text::GetOutlineStroke() const
{
return style_.outline_stroke;
}
2018-11-08 00:21:59 +08:00
int Text::GetLineCount() const
{
if (text_layout_)
{
DWRITE_TEXT_METRICS metrics;
text_layout_->GetMetrics(&metrics);
return static_cast<int>(metrics.lineCount);
}
else
{
return 0;
}
}
2018-11-08 00:21:59 +08:00
bool Text::IsItalic() const
{
return font_.italic;
}
2018-11-08 00:21:59 +08:00
bool Text::strikethrough() const
{
return style_.strikethrough;
}
2018-11-08 00:21:59 +08:00
bool Text::underline() const
{
return style_.underline;
}
2018-11-08 00:21:59 +08:00
bool Text::outline() const
{
return style_.outline;
}
void Text::SetText(const String& text)
2018-11-08 00:21:59 +08:00
{
text_ = text;
Reset();
}
2018-11-08 00:21:59 +08:00
void Text::SetStyle(const Style& style)
{
2018-11-08 00:21:59 +08:00
style_ = style;
2018-09-04 22:42:34 +08:00
Reset();
}
2018-11-08 00:21:59 +08:00
void Text::SetFont(const Font & font)
{
2018-11-08 00:21:59 +08:00
font_ = font;
Reset();
}
void Text::SetFontFamily(const String& family)
2018-11-08 00:21:59 +08:00
{
font_.family = family;
Reset();
}
2018-11-08 00:21:59 +08:00
void Text::SetFontSize(float size)
{
2018-11-08 00:21:59 +08:00
font_.size = size;
2018-09-04 22:42:34 +08:00
Reset();
}
2018-11-08 00:21:59 +08:00
void Text::SetFontWeight(UINT weight)
{
2018-11-08 00:21:59 +08:00
font_.weight = weight;
2018-09-04 22:42:34 +08:00
Reset();
}
2018-11-08 00:21:59 +08:00
void Text::SetColor(Color color)
{
2018-11-08 00:21:59 +08:00
style_.color = color;
}
2018-11-08 00:21:59 +08:00
void Text::SetItalic(bool value)
{
2018-11-08 00:21:59 +08:00
font_.italic = value;
Reset();
}
2018-11-08 00:21:59 +08:00
void Text::SetWrapEnabled(bool wrap)
{
if (style_.wrap != wrap)
{
style_.wrap = wrap;
Reset();
}
}
2018-11-08 00:21:59 +08:00
void Text::SetWrapWidth(float wrap_width)
{
if (style_.wrap_width != wrap_width)
{
style_.wrap_width = std::max(wrap_width, 0.f);
2018-11-08 00:21:59 +08:00
if (style_.wrap)
{
Reset();
}
}
}
2018-11-08 00:21:59 +08:00
void Text::SetLineSpacing(float line_spacing)
{
if (style_.line_spacing != line_spacing)
{
style_.line_spacing = line_spacing;
Reset();
}
}
2018-11-08 00:21:59 +08:00
void Text::SetAlignment(Align align)
{
if (style_.alignment != align)
{
style_.alignment = align;
Reset();
}
}
2018-11-08 00:21:59 +08:00
void Text::SetUnderline(bool underline)
{
if (style_.underline != underline)
{
style_.underline = underline;
if (!text_format_)
CreateFormat();
CreateLayout();
}
}
2018-11-08 00:21:59 +08:00
void Text::SetStrikethrough(bool strikethrough)
{
if (style_.strikethrough != strikethrough)
{
style_.strikethrough = strikethrough;
if (!text_format_)
CreateFormat();
CreateLayout();
}
2018-08-28 00:06:10 +08:00
}
2018-11-08 00:21:59 +08:00
void Text::SetOutline(bool outline)
2018-08-28 00:06:10 +08:00
{
2018-11-08 00:21:59 +08:00
style_.outline = outline;
2018-08-28 00:06:10 +08:00
}
2018-11-08 00:21:59 +08:00
void Text::SetOutlineColor(Color outline_color)
2018-08-28 00:06:10 +08:00
{
2018-11-08 00:21:59 +08:00
style_.outline_color = outline_color;
}
2018-11-08 00:21:59 +08:00
void Text::SetOutlineWidth(float outline_width)
{
style_.outline_width = outline_width;
}
2018-11-08 00:21:59 +08:00
void Text::SetOutlineStroke(Stroke outline_stroke)
{
2018-11-08 00:21:59 +08:00
style_.outline_stroke = outline_stroke;
}
2018-11-08 00:21:59 +08:00
void Text::OnDraw() const
{
2018-11-08 00:21:59 +08:00
if (text_layout_)
{
// <20><><EFBFBD><EFBFBD><EFBFBD>ı<EFBFBD><C4B1><EFBFBD><EFBFBD><EFBFBD>
D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height);
// <20><><EFBFBD>û<EFBFBD>ˢ<EFBFBD><CBA2>ɫ<EFBFBD><C9AB>͸<EFBFBD><CDB8><EFBFBD><EFBFBD>
render::D2D.SolidColorBrush->SetOpacity(GetDisplayOpacity());
2018-11-08 00:21:59 +08:00
// <20><>ȡ<EFBFBD>ı<EFBFBD><C4B1><EFBFBD>Ⱦ<EFBFBD><C8BE>
render::D2D.TextRenderer->SetTextStyle(
2018-11-08 00:21:59 +08:00
style_.color,
style_.outline,
style_.outline_color,
style_.outline_width,
static_cast<D2D1_LINE_JOIN>(style_.outline_stroke)
2018-11-08 00:21:59 +08:00
);
text_layout_->Draw(nullptr, render::D2D.TextRenderer, 0, 0);
2018-11-08 00:21:59 +08:00
}
}
2018-11-08 00:21:59 +08:00
void Text::Reset()
{
2018-11-08 00:21:59 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD>ʽ<EFBFBD><CABD>
CreateFormat();
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֲ<EFBFBD><D6B2><EFBFBD>
CreateLayout();
}
2018-11-08 00:21:59 +08:00
void Text::CreateFormat()
{
2018-11-08 00:21:59 +08:00
SafeRelease(text_format_);
2018-08-28 00:06:10 +08:00
ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextFormat(
2018-11-08 00:21:59 +08:00
font_.family.c_str(),
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_
2018-08-28 00:06:10 +08:00
)
);
2018-11-08 00:21:59 +08:00
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֶ<EFBFBD><D6B6>ʽ
text_format_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style_.alignment));
2018-08-28 00:06:10 +08:00
2018-11-08 00:21:59 +08:00
// <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
);
}
2018-11-08 00:21:59 +08:00
// <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);
}
}
2018-11-08 00:21:59 +08:00
void Text::CreateLayout()
{
2018-11-08 00:21:59 +08:00
SafeRelease(text_layout_);
// <20>ı<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (text_.empty())
{
this->SetSize(0, 0);
return;
}
if (text_format_ == nullptr)
{
E2D_WARNING("Text::CreateLayout failed! text_format_ NULL pointer exception.");
return;
}
UINT32 length = static_cast<UINT32>(text_.size());
// <20><><EFBFBD>ı<EFBFBD><C4B1>Զ<EFBFBD><D4B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD>д<EFBFBD><D0B4><EFBFBD>
if (style_.wrap)
{
ThrowIfFailed(
render::D2D.DWriteFactory->CreateTextLayout(
2018-11-08 00:21:59 +08:00
text_.c_str(),
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(
render::D2D.DWriteFactory->CreateTextLayout(
2018-11-08 00:21:59 +08:00
text_.c_str(),
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(
render::D2D.DWriteFactory->CreateTextLayout(
2018-11-08 00:21:59 +08:00
text_.c_str(),
length,
text_format_,
GetTransform().size.width,
0,
&text_layout_
)
);
}
// <20><><EFBFBD><EFBFBD><EFBFBD>»<EFBFBD><C2BB>ߺ<EFBFBD>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>
DWRITE_TEXT_RANGE range = { 0, length };
2018-11-08 00:21:59 +08:00
if (style_.underline)
{
text_layout_->SetUnderline(true, range);
2018-11-08 00:21:59 +08:00
}
if (style_.strikethrough)
{
text_layout_->SetStrikethrough(true, range);
2018-11-08 00:21:59 +08:00
}
}
}