Text changes

Font changes into struct. class Text has some new features.
This commit is contained in:
Nomango 2018-03-30 23:37:42 +08:00
parent 9bef38091f
commit 93a08d6b7e
4 changed files with 371 additions and 323 deletions

View File

@ -1,108 +1,21 @@
#include "..\enodes.h"
e2d::Font::Font()
: m_pTextFormat(nullptr)
, m_Color(Color::WHITE)
, m_fFontSize(22)
, m_FontWeight(FontWeight::REGULAR)
, m_bItalic(false)
, m_bRecreateNeeded(true)
{
}
e2d::Font::Font()
: fontFamily("")
, size(22)
, color(Color::WHITE)
, weight(FontWeight::NORMAL)
, italic(false)
, underline(false)
, strikethrough(false)
{}
e2d::Font::Font(String fontFamily, double fontSize /* = 22 */, UINT32 color /* = EColor::WHITE */, UINT32 fontWeight, bool italic /* = false */)
: m_pTextFormat(nullptr)
, m_Color(Color::WHITE)
, m_fFontSize(22)
, m_FontWeight(FontWeight::REGULAR)
, m_bItalic(false)
, m_bRecreateNeeded(true)
{
this->setFamily(fontFamily);
this->setSize(fontSize);
this->setColor(color);
this->setWeight(fontWeight);
this->setItalic(italic);
}
e2d::Font::~Font()
{
SafeReleaseInterface(&m_pTextFormat);
}
double e2d::Font::getFontSize() const
{
return m_fFontSize;
}
UINT32 e2d::Font::getFontWeight() const
{
return m_FontWeight;
}
UINT32 e2d::Font::getColor() const
{
return m_Color;
}
bool e2d::Font::isItalic() const
{
return m_bItalic;
}
void e2d::Font::setFamily(String fontFamily)
{
m_sFontFamily = fontFamily;
m_bRecreateNeeded = true;
}
void e2d::Font::setSize(double fontSize)
{
m_fFontSize = static_cast<float>(fontSize);
m_bRecreateNeeded = true;
}
void e2d::Font::setWeight(UINT32 fontWeight)
{
m_FontWeight = fontWeight;
m_bRecreateNeeded = true;
}
void e2d::Font::setColor(UINT32 color)
{
m_Color = color;
}
void e2d::Font::setItalic(bool value)
{
m_bItalic = value;
m_bRecreateNeeded = true;
}
void e2d::Font::_initTextFormat()
{
SafeReleaseInterface(&m_pTextFormat);
HRESULT hr = Renderer::getIDWriteFactory()->CreateTextFormat(
m_sFontFamily,
NULL,
DWRITE_FONT_WEIGHT(m_FontWeight),
m_bItalic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
m_fFontSize,
L"zh-cn",
&m_pTextFormat
);
ASSERT(SUCCEEDED(hr), "Create IDWriteTextFormat Failed!");
}
IDWriteTextFormat * e2d::Font::getDWriteTextFormat()
{
if (m_bRecreateNeeded)
{
_initTextFormat();
m_bRecreateNeeded = false;
}
return m_pTextFormat;
}
e2d::Font::Font(String fontFamily, double fontSize, UINT32 color, UINT32 fontWeight, bool italic, bool hasUnderline, bool hasStrikethrough)
: fontFamily(fontFamily)
, size(fontSize)
, color(color)
, weight(fontWeight)
, italic(italic)
, underline(hasUnderline)
, strikethrough(hasStrikethrough)
{}

View File

@ -1,66 +1,72 @@
#include "..\enodes.h"
e2d::Text::Text()
: m_bWrappingEnable(false)
, m_pFont(nullptr)
, m_fWrappingWidth(0)
, m_bHasUnderline(false)
, m_bHasStrikethrough(false)
, m_Font()
, m_nAlign(TextAlign::LEFT)
, m_fLineSpacing(0.0f)
, m_fWrappingWidth(0.0f)
, m_pDWriteTextLayout(nullptr)
, m_pDWriteTextFormat(nullptr)
{
this->setFont(new Font());
}
e2d::Text::Text(String text)
: m_bWrappingEnable(false)
, m_pFont(nullptr)
, m_fWrappingWidth(0)
, m_bHasUnderline(false)
, m_bHasStrikethrough(false)
, m_Font()
, m_nAlign(TextAlign::LEFT)
, m_fLineSpacing(0.0f)
, m_fWrappingWidth(0.0f)
, m_pDWriteTextLayout(nullptr)
, m_pDWriteTextFormat(nullptr)
, m_sText(text)
{
this->setText(text);
this->setFont(new Font());
_reset();
}
e2d::Text::Text(Font * font)
e2d::Text::Text(Font font)
: m_bWrappingEnable(false)
, m_pFont(nullptr)
, m_fWrappingWidth(0)
, m_bHasUnderline(false)
, m_bHasStrikethrough(false)
, m_Font(font)
, m_nAlign(TextAlign::LEFT)
, m_fLineSpacing(0.0f)
, m_fWrappingWidth(0.0f)
, m_pDWriteTextLayout(nullptr)
, m_pDWriteTextFormat(nullptr)
{
this->setFont(font);
_reset();
}
e2d::Text::Text(String text, Font * font)
e2d::Text::Text(String text, Font font)
: m_bWrappingEnable(false)
, m_pFont(nullptr)
, m_fWrappingWidth(0)
, m_bHasUnderline(false)
, m_bHasStrikethrough(false)
, m_Font(font)
, m_nAlign(TextAlign::LEFT)
, m_fLineSpacing(0.0f)
, m_fWrappingWidth(0.0f)
, m_pDWriteTextLayout(nullptr)
, m_pDWriteTextFormat(nullptr)
, m_sText(text)
{
this->setText(text);
this->setFont(font);
_reset();
}
e2d::Text::Text(String text, String fontFamily, double fontSize, UINT32 color, UINT32 fontWeight, bool italic)
e2d::Text::Text(String text, String fontFamily, double fontSize, UINT32 color, UINT32 fontWeight, bool italic, bool hasUnderline, bool hasStrikethrough)
: m_bWrappingEnable(false)
, m_pFont(nullptr)
, m_fWrappingWidth(0)
, m_bHasUnderline(false)
, m_bHasStrikethrough(false)
, m_Font(Font(fontFamily, fontSize, color, fontWeight, italic, hasUnderline, hasStrikethrough))
, m_nAlign(TextAlign::LEFT)
, m_fLineSpacing(0.0f)
, m_fWrappingWidth(0.0f)
, m_pDWriteTextLayout(nullptr)
, m_pDWriteTextFormat(nullptr)
, m_sText(text)
{
this->setText(text);
this->setFont(new Font(fontFamily, fontSize, color, fontWeight, italic));
_reset();
}
e2d::Text::~Text()
{
SafeRelease(&m_pFont);
SafeReleaseInterface(&m_pDWriteTextFormat);
SafeReleaseInterface(&m_pDWriteTextLayout);
}
e2d::String e2d::Text::getText() const
@ -68,90 +74,141 @@ e2d::String e2d::Text::getText() const
return m_sText;
}
e2d::Font * e2d::Text::getFont() const
e2d::Font e2d::Text::getFont() const
{
return m_pFont;
return m_Font;
}
e2d::String e2d::Text::getFontFamily() const
{
return m_Font.fontFamily;
}
double e2d::Text::getFontSize() const
{
return m_Font.size;
}
UINT32 e2d::Text::getFontWeight() const
{
return m_Font.weight;
}
UINT32 e2d::Text::getColor() const
{
return m_Font.color;
}
bool e2d::Text::isItalic() const
{
return m_Font.italic;
}
void e2d::Text::setText(String text)
{
m_sText = text;
_initTextLayout();
_reset();
}
void e2d::Text::setFont(Font * font)
void e2d::Text::setFont(Font font)
{
if (font)
{
SafeRelease(&m_pFont);
m_pFont = font;
font->retain();
m_Font = font;
_reset();
}
_initTextLayout();
void e2d::Text::setFontFamily(String fontFamily)
{
m_Font.fontFamily = fontFamily;
_reset();
}
void e2d::Text::setFontSize(double fontSize)
{
m_Font.size = static_cast<float>(fontSize);
_reset();
}
void e2d::Text::setFontWeight(UINT32 fontWeight)
{
m_Font.weight = fontWeight;
_reset();
}
void e2d::Text::setColor(UINT32 color)
{
m_Font.color = color;
}
void e2d::Text::setItalic(bool value)
{
m_Font.italic = value;
_reset();
}
void e2d::Text::setWrappingEnable(bool bWrappingEnable)
{
if (m_bWrappingEnable != bWrappingEnable)
{
m_bWrappingEnable = bWrappingEnable;
_reset();
}
}
void e2d::Text::setWrappingWidth(double wordWrapWidth)
void e2d::Text::setWrappingWidth(double fWrappingWidth)
{
m_fWrappingWidth = max(static_cast<float>(wordWrapWidth), 0);
m_bWrappingEnable = (abs(m_fWrappingWidth) >= 1e-7);
_initTextLayout();
if (m_fWrappingWidth != fWrappingWidth)
{
m_fWrappingWidth = max(static_cast<float>(fWrappingWidth), 0);
_reset();
}
}
void e2d::Text::setLineSpacing(double fLineSpacing)
{
if (m_pFont)
if (m_fLineSpacing != fLineSpacing)
{
if (fLineSpacing == 0.0f)
{
m_pFont->getDWriteTextFormat()->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
}
else
{
m_pFont->getDWriteTextFormat()->SetLineSpacing(
DWRITE_LINE_SPACING_METHOD_UNIFORM,
static_cast<float>(fLineSpacing),
static_cast<float>(fLineSpacing) * 0.8f
);
}
_initTextLayout();
m_fLineSpacing = static_cast<float>(fLineSpacing);
_reset();
}
}
void e2d::Text::setAlignment(UINT32 nAlign)
{
if (m_pFont)
if (m_nAlign != nAlign)
{
m_pFont->getDWriteTextFormat()->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(nAlign));
_initTextLayout();
m_nAlign = nAlign;
_reset();
}
}
void e2d::Text::setUnderline(bool hasUnderline)
{
if (m_bHasUnderline != hasUnderline)
if (m_Font.underline != hasUnderline)
{
m_bHasUnderline = hasUnderline;
_initTextLayout();
m_Font.underline = hasUnderline;
if (!m_pDWriteTextFormat)
_createFormat();
_createLayout();
}
}
void e2d::Text::setStrikethrough(bool hasStrikethrough)
{
if (m_bHasStrikethrough != hasStrikethrough)
if (m_Font.strikethrough != hasStrikethrough)
{
m_bHasStrikethrough = hasStrikethrough;
_initTextLayout();
m_Font.strikethrough = hasStrikethrough;
if (!m_pDWriteTextFormat)
_createFormat();
_createLayout();
}
}
void e2d::Text::onRender()
{
// 创建文本区域
D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, m_bWrappingEnable ? m_fWrappingWidth : m_fWidth, m_fHeight);
D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, m_fWidth, m_fHeight);
// 设置画刷颜色和透明度
Renderer::getSolidColorBrush()->SetColor(D2D1::ColorF(m_pFont->m_Color, m_fDisplayOpacity));
Renderer::getSolidColorBrush()->SetColor(D2D1::ColorF(m_Font.color, m_fDisplayOpacity));
// 渲染文字内容
if (m_pDWriteTextLayout)
{
@ -163,54 +220,127 @@ void e2d::Text::onRender()
}
}
void e2d::Text::_initTextLayout()
void e2d::Text::_reset()
{
// 未设置字体或空字符串时,文本宽高为 0
if (!m_pFont || m_sText.isEmpty())
// 创建文字格式化
_createFormat();
// 创建文字布局
_createLayout();
}
void e2d::Text::_createFormat()
{
SafeReleaseInterface(&m_pDWriteTextFormat);
HRESULT hr = Renderer::getIDWriteFactory()->CreateTextFormat(
m_Font.fontFamily,
NULL,
DWRITE_FONT_WEIGHT(m_Font.weight),
m_Font.italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
static_cast<float>(m_Font.size),
L"zh-cn",
&m_pDWriteTextFormat
);
ASSERT(SUCCEEDED(hr), "Create IDWriteTextFormat Failed!");
if (m_pDWriteTextFormat)
{
// 设置文字对齐方式
m_pDWriteTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(m_nAlign));
// 设置行间距
if (m_fLineSpacing == 0.0f)
{
m_pDWriteTextFormat->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0);
}
else
{
m_pDWriteTextFormat->SetLineSpacing(
DWRITE_LINE_SPACING_METHOD_UNIFORM,
m_fLineSpacing,
m_fLineSpacing * 0.8f
);
}
// 打开文本自动换行时,设置换行属性
if (m_bWrappingEnable)
{
m_pDWriteTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
}
else
{
m_pDWriteTextFormat->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
}
}
}
void e2d::Text::_createLayout()
{
SafeReleaseInterface(&m_pDWriteTextLayout);
// 文本为空字符串时,重置属性
if (m_sText.isEmpty())
{
this->setSize(0, 0);
return;
}
// 未打开文本自动换行时,设置 TextFormat 属性为不换行
if (!m_bWrappingEnable)
if (m_pDWriteTextFormat == nullptr)
{
m_pFont->getDWriteTextFormat()->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
WARN_IF(true, "Text::_createLayout failed! m_pDWriteTextFormat NULL pointer exception.");
return;
}
UINT32 length = static_cast<UINT32>(m_sText.getLength());
// 创建 TextLayout
HRESULT hr;
// 对文本自动换行情况下进行处理
if (m_bWrappingEnable)
{
hr = Renderer::getIDWriteFactory()->CreateTextLayout(
m_sText,
length,
m_pDWriteTextFormat,
m_fWrappingWidth,
0,
&m_pDWriteTextLayout
);
if (m_pDWriteTextLayout)
{
// 获取文本布局的宽度和高度
DWRITE_TEXT_METRICS metrics;
m_pDWriteTextLayout->GetMetrics(&metrics);
// 重设文本宽高
this->setSize(metrics.layoutWidth, metrics.height);
}
}
else
{
m_pFont->getDWriteTextFormat()->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
hr = Renderer::getIDWriteFactory()->CreateTextLayout(m_sText, length, m_pDWriteTextFormat, 0, 0, &m_pDWriteTextLayout);
// 为防止文本对齐问题,根据刚才创建的 layout 宽度重新创建它
if (m_pDWriteTextLayout)
{
// 获取文本布局的宽度和高度
DWRITE_TEXT_METRICS metrics;
m_pDWriteTextLayout->GetMetrics(&metrics);
// 重设文本宽高
this->setSize(metrics.width, metrics.height);
// 重新创建 layout
SafeReleaseInterface(&m_pDWriteTextLayout);
hr = Renderer::getIDWriteFactory()->CreateTextLayout(m_sText, length, m_pDWriteTextFormat, m_fWidth, 0, &m_pDWriteTextLayout);
}
}
// 获取 TextLayout
SafeReleaseInterface(&m_pDWriteTextLayout);
UINT32 length = static_cast<UINT32>(m_sText.getLength());
HRESULT hr = Renderer::getIDWriteFactory()->CreateTextLayout(
m_sText,
length,
m_pFont->getDWriteTextFormat(),
m_bWrappingEnable ? m_fWrappingWidth : 0,
0,
&m_pDWriteTextLayout
);
ASSERT(SUCCEEDED(hr), "Create IDWriteTextFormat Failed!");
// 添加下划线和删除线
if (m_bHasUnderline)
if (m_Font.underline)
{
m_pDWriteTextLayout->SetUnderline(true, { 0, length });
}
if (m_bHasStrikethrough)
if (m_Font.strikethrough)
{
m_pDWriteTextLayout->SetStrikethrough(true, { 0, length });
}
// 获取文本布局的宽度和高度
DWRITE_TEXT_METRICS metrics;
m_pDWriteTextLayout->GetMetrics(&metrics);
this->setSize(metrics.widthIncludingTrailingWhitespace, metrics.height);
m_fWrappingWidth = metrics.widthIncludingTrailingWhitespace;
}

View File

@ -9,31 +9,15 @@ namespace e2d
{
// 函数对象
typedef std::function<void()> Function;
// 创建函数对象
template<typename Object, typename Func>
inline Function CreateFunc(Object&& obj, Func&& func)
{
return std::bind(func, obj);
}
template<typename T>
inline void SafeDelete(T** p) { if (*p) { delete *p; *p = nullptr; } }
template<typename Object>
inline void SafeRelease(Object** p) { if (*p) { (*p)->release(); *p = nullptr; } }
template<class Interface>
inline void SafeReleaseInterface(Interface **pp) { if (*pp != nullptr) { (*pp)->Release(); (*pp) = nullptr; } }
struct Size;
// 表示坐标的结构体
struct Point
{
double x; // X 坐标
double y; // Y 坐标
/* 构造函数 */
Point();
Point(double x, double y);
@ -44,10 +28,6 @@ struct Point
Point operator / (double const & value);
operator e2d::Size() const;
/* 成员变量 */
double x; // X 坐标
double y; // Y 坐标
};
// 二维向量
@ -56,6 +36,10 @@ typedef Point Vector;
// 表示大小的结构体
struct Size
{
double width; // 宽度
double height; // 高度
/* 构造函数 */
Size();
Size(double width, double height);
@ -66,13 +50,20 @@ struct Size
Size operator / (double const & value);
operator e2d::Point() const;
/* 成员变量 */
double width; // 宽度
double height; // 高度
};
// 函数对象
typedef std::function<void()> Function;
// 创建函数对象
template<typename Object, typename Func>
inline Function CreateFunc(Object&& obj, Func&& func)
{
return std::bind(func, obj);
}
// 字符串
class String
{
@ -391,6 +382,32 @@ public:
};
// 文本样式
struct Font
{
String fontFamily; // 字体
double size; // 字号
UINT32 color; // 颜色
UINT32 weight; // 粗细值
bool italic; // 斜体
bool underline; // 下划线
bool strikethrough; // 删除线
/* 构造函数 */
Font();
Font(
String fontFamily,
double fontSize = 22,
UINT32 color = Color::WHITE,
UINT32 fontWeight = FontWeight::NORMAL,
bool italic = false,
bool hasUnderline = false,
bool hasStrikethrough = false
);
};
class ObjectManager;
// 基础对象
@ -418,81 +435,6 @@ private:
};
class Text;
class Font :
public Object
{
friend Text;
public:
Font();
Font(
String fontFamily,
double fontSize = 22,
UINT32 color = Color::WHITE,
UINT32 fontWeight = FontWeight::REGULAR,
bool italic = false
);
virtual ~Font();
// 获取当前字号
double getFontSize() const;
// 获取当前字体粗细值
UINT32 getFontWeight() const;
// 获取文字颜色
UINT32 getColor() const;
// 是否是斜体
bool isItalic() const;
// 设置字体
void setFamily(
String fontFamily
);
// 设置字号
void setSize(
double fontSize
);
// 设置字体粗细值
void setWeight(
UINT32 fontWeight
);
// 设置文字颜色
void setColor(
UINT32 color
);
// 设置文字斜体
void setItalic(
bool value
);
protected:
// 创建文字格式
void _initTextFormat();
// 获取文字格式
IDWriteTextFormat * getDWriteTextFormat();
protected:
String m_sFontFamily;
float m_fFontSize;
UINT32 m_FontWeight;
UINT32 m_Color;
bool m_bItalic;
bool m_bRecreateNeeded;
IDWriteTextFormat * m_pTextFormat;
};
// 图片
class Image :
public Object
@ -705,8 +647,8 @@ protected:
Function m_callback;
};
// String 类模板函数定义
// String 类模板函数定义
template<typename T>
inline e2d::String e2d::String::toString(T value)
{
@ -715,4 +657,13 @@ inline e2d::String e2d::String::toString(T value)
return std::move(tmp);
}
template<typename T>
inline void SafeDelete(T** p) { if (*p) { delete *p; *p = nullptr; } }
template<typename Object>
inline void SafeRelease(Object** p) { if (*p) { (*p)->release(); *p = nullptr; } }
template<class Interface>
inline void SafeReleaseInterface(Interface **pp) { if (*pp != nullptr) { (*pp)->Release(); (*pp) = nullptr; } }
}

View File

@ -503,12 +503,12 @@ public:
);
Text(
Font * font /* 字体样式 */
Font font /* 字体样式 */
);
Text(
String text, /* 文字内容 */
Font * font /* 字体样式 */
Font font /* 字体样式 */
);
Text(
@ -517,7 +517,9 @@ public:
double fontSize = 22, /* 字号 */
UINT32 color = Color::WHITE, /* 颜色 */
UINT32 fontWeight = FontWeight::NORMAL, /* 粗细值 */
bool italic = false /* 斜体 */
bool italic = false, /* 斜体 */
bool hasUnderline = false, /* 下划线 */
bool hasStrikethrough = false /* 删除线 */
);
virtual ~Text();
@ -525,20 +527,65 @@ public:
// 获取文本
String getText() const;
// 获取文本样式
Font getFont() const;
// 获取字体
Font * getFont() const;
String getFontFamily() const;
// 获取当前字号
double getFontSize() const;
// 获取当前字体粗细值
UINT32 getFontWeight() const;
// 获取文字颜色
UINT32 getColor() const;
// 是否是斜体
bool isItalic() const;
// 设置文本
void setText(
String text
);
// 设置字体
// 设置文本样式
void setFont(
Font * pFont
Font pFont
);
// 设置文本自动换行宽度(默认为 0
// 设置字体
void setFontFamily(
String fontFamily
);
// 设置字号(默认值为 22
void setFontSize(
double fontSize
);
// 设置字体粗细值(默认值为 FontWeight::NORMAL
void setFontWeight(
UINT32 fontWeight
);
// 设置文字颜色(默认值为 Color::WHITE
void setColor(
UINT32 color
);
// 设置文字斜体(默认值为 false
void setItalic(
bool value
);
// 设置文本自动换行(根据 WrappingWidth 进行自动换行,默认为 false
void setWrappingEnable(
bool bWrappingEnable
);
// 设置文本换行宽度WrappingEnable 开启时生效,默认为 0
void setWrappingWidth(
double fWrappingWidth
);
@ -553,12 +600,12 @@ public:
UINT32 nAlign
);
// 设置下划线
// 设置下划线(默认值为 false
void setUnderline(
bool hasUnderline
);
// 设置删除线
// 设置删除线(默认值为 false
void setStrikethrough(
bool hasStrikethrough
);
@ -567,16 +614,23 @@ public:
virtual void onRender() override;
protected:
// 重新排版文字
void _reset();
// 创建文字格式化
void _createFormat();
// 创建文字布局
void _initTextLayout();
void _createLayout();
protected:
String m_sText;
bool m_bWrappingEnable;
bool m_bHasUnderline;
bool m_bHasStrikethrough;
float m_fWrappingWidth;
Font * m_pFont;
Font m_Font;
UINT32 m_nAlign;
float m_fLineSpacing;
IDWriteTextFormat * m_pDWriteTextFormat;
IDWriteTextLayout * m_pDWriteTextLayout;
};