From f2be349841b9e095c5a8c9be6be10846ff117ea0 Mon Sep 17 00:00:00 2001 From: Haibo Date: Thu, 15 Nov 2018 14:35:19 +0800 Subject: [PATCH] optimize: Text class --- core/base/Canvas.cpp | 2 +- core/base/Font.cpp | 32 --- core/base/{Font.h => Font.hpp} | 10 +- core/base/Game.cpp | 40 ++-- core/base/Image.cpp | 4 +- core/base/MouseEvent.cpp | 8 +- core/base/Music.cpp | 4 +- core/base/Node.cpp | 28 ++- core/base/Node.h | 16 +- core/base/Rect.hpp | 18 ++ core/base/Singleton.hpp | 9 +- core/base/Sprite.cpp | 2 +- core/base/Text.cpp | 270 +++++++++++--------------- core/base/Text.h | 119 +++++------- core/base/TextRenderer.cpp | 2 +- core/base/TextStyle.hpp | 91 +++++++++ core/base/Transition.cpp | 24 +-- core/base/audio.cpp | 2 +- core/base/render.h | 2 +- core/base/window.cpp | 2 +- core/easy2d.h | 3 +- core/ui/Button.cpp | 2 +- core/utils/Path.cpp | 4 +- project/vs2013/Easy2D.vcxproj | 4 +- project/vs2013/Easy2D.vcxproj.filters | 12 +- project/vs2015/Easy2D.vcxproj | 4 +- project/vs2015/Easy2D.vcxproj.filters | 12 +- project/vs2017/Easy2D.vcxproj | 4 +- project/vs2017/Easy2D.vcxproj.filters | 12 +- 29 files changed, 393 insertions(+), 349 deletions(-) delete mode 100644 core/base/Font.cpp rename core/base/{Font.h => Font.hpp} (94%) create mode 100644 core/base/TextStyle.hpp diff --git a/core/base/Canvas.cpp b/core/base/Canvas.cpp index 05825029..07fb32f4 100644 --- a/core/base/Canvas.cpp +++ b/core/base/Canvas.cpp @@ -88,7 +88,7 @@ namespace easy2d { SafeRelease(stroke_style_); - stroke_style_ = devices::Graphics::Instance().GetStrokeStyle(stroke); + stroke_style_ = devices::Graphics::Instance()->GetStrokeStyle(stroke); if (stroke_style_) stroke_style_->AddRef(); diff --git a/core/base/Font.cpp b/core/base/Font.cpp deleted file mode 100644 index ec102fb9..00000000 --- a/core/base/Font.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// 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 "Font.h" - -namespace easy2d -{ - Font::Font(const std::wstring & family, float size, unsigned int weight, bool italic) - : family(family) - , size(size) - , weight(weight) - , italic(italic) - { - } -} diff --git a/core/base/Font.h b/core/base/Font.hpp similarity index 94% rename from core/base/Font.h rename to core/base/Font.hpp index 6cc42e9d..49035798 100644 --- a/core/base/Font.h +++ b/core/base/Font.hpp @@ -48,11 +48,17 @@ namespace easy2d }; public: - explicit Font( + Font( const std::wstring& family = L"", float size = 22, unsigned int weight = Font::Weight::Normal, bool italic = false - ); + ) + : family(family) + , size(size) + , weight(weight) + , italic(italic) + { + } }; } diff --git a/core/base/Game.cpp b/core/base/Game.cpp index def75cdb..4d68c404 100644 --- a/core/base/Game.cpp +++ b/core/base/Game.cpp @@ -61,10 +61,10 @@ namespace easy2d debug_enabled_ = options.debug; - Window::Instance().Init(options.title, options.width, options.height, options.icon, debug_enabled_); - devices::Graphics::Instance().Init(Window::Instance().GetHandle(), debug_enabled_); - devices::Input::Instance().Init(debug_enabled_); - devices::Audio::Instance().Init(debug_enabled_); + Window::Instance()->Init(options.title, options.width, options.height, options.icon, debug_enabled_); + devices::Graphics::Instance()->Init(Window::Instance()->GetHandle(), debug_enabled_); + devices::Input::Instance()->Init(debug_enabled_); + devices::Audio::Instance()->Init(debug_enabled_); HWND console = ::GetConsoleWindow(); if (debug_enabled_) @@ -95,7 +95,7 @@ namespace easy2d } ::SetWindowLongPtrW( - Window::Instance().GetHandle(), + Window::Instance()->GetHandle(), GWLP_USERDATA, PtrToUlong(this) ); @@ -114,9 +114,9 @@ namespace easy2d next_scene_ = nullptr; } - const auto& window = Window::Instance(); - ::ShowWindow(window.GetHandle(), SW_SHOWNORMAL); - ::UpdateWindow(window.GetHandle()); + const auto window = Window::Instance(); + ::ShowWindow(window->GetHandle(), SW_SHOWNORMAL); + ::UpdateWindow(window->GetHandle()); const int64_t min_interval = 5; auto last = time::Now(); @@ -132,10 +132,10 @@ namespace easy2d const auto dt = now - last; last = now; - devices::Input::Instance().Update( - window.GetHandle(), - window.GetContentScaleX(), - window.GetContentScaleY() + devices::Input::Instance()->Update( + window->GetHandle(), + window->GetContentScaleX(), + window->GetContentScaleY() ); UpdateScene(dt); @@ -264,8 +264,8 @@ namespace easy2d void Game::DrawScene() { - auto& graphics = devices::Graphics::Instance(); - graphics.BeginDraw(Window::Instance().GetHandle()); + auto graphics = devices::Graphics::Instance(); + graphics->BeginDraw(Window::Instance()->GetHandle()); if (transition_) { @@ -280,20 +280,20 @@ namespace easy2d { if (curr_scene_) { - graphics.SetTransform(math::Matrix()); - graphics.SetBrushOpacity(1.f); + graphics->SetTransform(math::Matrix()); + graphics->SetBrushOpacity(1.f); curr_scene_->DrawBorder(); } if (next_scene_) { - graphics.SetTransform(math::Matrix()); - graphics.SetBrushOpacity(1.f); + graphics->SetTransform(math::Matrix()); + graphics->SetBrushOpacity(1.f); next_scene_->DrawBorder(); } - graphics.DrawDebugInfo(); + graphics->DrawDebugInfo(); } - graphics.EndDraw(); + graphics->EndDraw(); } } \ No newline at end of file diff --git a/core/base/Image.cpp b/core/base/Image.cpp index ab6a9dc9..46a74f26 100644 --- a/core/base/Image.cpp +++ b/core/base/Image.cpp @@ -69,7 +69,7 @@ namespace easy2d bool Image::Load(Resource& res) { ID2D1Bitmap* bitmap; - HRESULT hr = devices::Graphics::Instance().CreateBitmapFromResource(res, &bitmap); + HRESULT hr = devices::Graphics::Instance()->CreateBitmapFromResource(res, &bitmap); if (FAILED(hr)) { logs::Trace(L"Load Image from resource failed!", hr); @@ -95,7 +95,7 @@ namespace easy2d String image_file_path = image_file.GetPath(); ID2D1Bitmap* bitmap; - HRESULT hr = devices::Graphics::Instance().CreateBitmapFromFile(image_file_path, &bitmap); + HRESULT hr = devices::Graphics::Instance()->CreateBitmapFromFile(image_file_path, &bitmap); if (FAILED(hr)) { logs::Trace(L"Load Image from file failed!", hr); diff --git a/core/base/MouseEvent.cpp b/core/base/MouseEvent.cpp index 96dbff00..1af5fc3a 100644 --- a/core/base/MouseEvent.cpp +++ b/core/base/MouseEvent.cpp @@ -32,19 +32,19 @@ namespace easy2d float MouseEvent::GetX() const { - return ((float)(short)LOWORD(l_param_)) * Window::Instance().GetContentScaleX(); + return ((float)(short)LOWORD(l_param_)) * Window::Instance()->GetContentScaleX(); } float MouseEvent::GetY() const { - return ((float)(short)HIWORD(l_param_)) * Window::Instance().GetContentScaleY(); + return ((float)(short)HIWORD(l_param_)) * Window::Instance()->GetContentScaleY(); } Point MouseEvent::GetPosition() const { return Point( - ((float)(short)LOWORD(l_param_)) * Window::Instance().GetContentScaleX(), - ((float)(short)HIWORD(l_param_)) * Window::Instance().GetContentScaleY() + ((float)(short)LOWORD(l_param_)) * Window::Instance()->GetContentScaleX(), + ((float)(short)HIWORD(l_param_)) * Window::Instance()->GetContentScaleY() ); } diff --git a/core/base/Music.cpp b/core/base/Music.cpp index 96ace47a..3a413abb 100644 --- a/core/base/Music.cpp +++ b/core/base/Music.cpp @@ -87,7 +87,7 @@ namespace easy2d return false; } - hr = devices::Audio::Instance().CreateVoice(&voice_, transcoder.GetWaveFormatEx()); + hr = devices::Audio::Instance()->CreateVoice(&voice_, transcoder.GetWaveFormatEx()); if (FAILED(hr)) { if (wave_data_) @@ -119,7 +119,7 @@ namespace easy2d return false; } - hr = devices::Audio::Instance().CreateVoice(&voice_, transcoder.GetWaveFormatEx()); + hr = devices::Audio::Instance()->CreateVoice(&voice_, transcoder.GetWaveFormatEx()); if (FAILED(hr)) { if (wave_data_) diff --git a/core/base/Node.cpp b/core/base/Node.cpp index 3eb6c2cd..fab80bb4 100644 --- a/core/base/Node.cpp +++ b/core/base/Node.cpp @@ -26,6 +26,18 @@ namespace easy2d { + namespace + { + float default_pivot_x = 0.f; + float default_pivot_y = 0.f; + } + + void Node::SetDefaultPivot(float pivot_x, float pivot_y) + { + default_pivot_x = pivot_x; + default_pivot_y = pivot_y; + } + Node::Node() : visible_(true) , parent_(nullptr) @@ -43,6 +55,8 @@ namespace easy2d , final_matrix_() , border_color_(Color::Red, 0.6f) { + transform_.pivot.x = default_pivot_x; + transform_.pivot.y = default_pivot_y; } Node::~Node() @@ -55,16 +69,16 @@ namespace easy2d if (!visible_) return; - auto& graphics = devices::Graphics::Instance(); + auto graphics = devices::Graphics::Instance(); if (clip_enabled_) { - graphics.PushClip(final_matrix_, transform_.size); + graphics->PushClip(final_matrix_, transform_.size); } if (children_.empty()) { - graphics.SetTransform(final_matrix_); + graphics->SetTransform(final_matrix_); OnDraw(); } else @@ -96,7 +110,7 @@ namespace easy2d } } - graphics.SetTransform(final_matrix_); + graphics->SetTransform(final_matrix_); OnDraw(); // 访问剩余节点 @@ -106,7 +120,7 @@ namespace easy2d if (clip_enabled_) { - graphics.PopClip(); + graphics->PopClip(); } } @@ -153,7 +167,7 @@ namespace easy2d { if (border_) { - devices::Graphics::Instance().DrawGeometry(border_, border_color_, 1.f, 1.5f); + devices::Graphics::Instance()->DrawGeometry(border_, border_color_, 1.f, 1.5f); } for (const auto& child : children_) @@ -184,7 +198,7 @@ namespace easy2d // 重新构造轮廓 SafeRelease(border_); ThrowIfFailed( - devices::Graphics::Instance().CreateRectGeometry(final_matrix_, transform_.size, &border_) + devices::Graphics::Instance()->CreateRectGeometry(final_matrix_, transform_.size, &border_) ); for (auto& child : children_) diff --git a/core/base/Node.h b/core/base/Node.h index b13db09f..3d429555 100644 --- a/core/base/Node.h +++ b/core/base/Node.h @@ -100,10 +100,10 @@ namespace easy2d // 获取节点纵向缩放比例 float GetScaleY() const; - // 获取节点横向倾斜角度 + // 获取节点横向错切角度 float GetSkewX() const; - // 获取节点纵向倾斜角度 + // 获取节点纵向错切角度 float GetSkewY() const; // 获取节点旋转角度 @@ -191,19 +191,19 @@ namespace easy2d float scale ); - // 设置横向倾斜角度 + // 设置横向错切角度 // 默认为 0 void SetSkewX( float skew_x ); - // 设置纵向倾斜角度 + // 设置纵向错切角度 // 默认为 0 void SetSkewY( float skew_y ); - // 设置倾斜角度 + // 设置错切角度 // 默认为 (0, 0) void SetSkew( float skew_x, @@ -332,6 +332,12 @@ namespace easy2d // 从父节点移除 void RemoveFromParent(); + // 设置默认支点 + static void SetDefaultPivot( + float pivot_x, + float pivot_y + ); + protected: virtual void Visit(); diff --git a/core/base/Rect.hpp b/core/base/Rect.hpp index ce5cab71..48efda20 100644 --- a/core/base/Rect.hpp +++ b/core/base/Rect.hpp @@ -81,6 +81,24 @@ namespace easy2d return (origin == rect.origin) && (size == rect.size); } + inline Point GetCenter() const { return Point{ origin.x + size.width / 2, origin.y + size.height / 2 }; } + + inline Point GetLeftTop() const { return origin; } + + inline Point GetRightBottom() const { return Point{ GetRight(), GetBottom() }; } + + inline Point GetRightTop() const { return Point{ GetRight(), GetTop() }; } + + inline Point GetLeftBottom() const { return Point{ GetLeft(), GetBottom() }; } + + inline float GetLeft() const { return origin.x; } + + inline float GetTop() const { return origin.y; } + + inline float GetRight() const { return origin.x + size.width; } + + inline float GetBottom() const { return origin.y + size.height; } + // 判断点是否在矩形内 inline bool ContainsPoint( const Point& point diff --git a/core/base/Singleton.hpp b/core/base/Singleton.hpp index 13317800..866b162e 100644 --- a/core/base/Singleton.hpp +++ b/core/base/Singleton.hpp @@ -27,7 +27,7 @@ namespace easy2d class ISingleton { public: - static inline T& Instance(); + static inline T* Instance(); private: ISingleton() {} @@ -40,12 +40,12 @@ namespace easy2d }; template - inline T & easy2d::ISingleton::Instance() + inline T* easy2d::ISingleton::Instance() { static std::unique_ptr instance_; if (!instance_) instance_.reset(new (std::nothrow) T); - return *instance_; + return instance_.get(); } } @@ -60,5 +60,6 @@ namespace easy2d #endif #ifndef E2D_DECLARE_SINGLETON_TYPE -#define E2D_DECLARE_SINGLETON_TYPE( type, singleton_type ) using singleton_type = ::easy2d::ISingleton< type > +#define E2D_DECLARE_SINGLETON_TYPE( type, singleton_type ) \ + using singleton_type = ::easy2d::ISingleton< type > #endif diff --git a/core/base/Sprite.cpp b/core/base/Sprite.cpp index 7a894191..a0b23d4d 100644 --- a/core/base/Sprite.cpp +++ b/core/base/Sprite.cpp @@ -132,7 +132,7 @@ namespace easy2d if (image_ && image_->GetBitmap()) { auto crop_pos = image_->GetCropPos(); - devices::Graphics::Instance().DrawImage( + devices::Graphics::Instance()->DrawImage( image_, GetDisplayOpacity(), Rect(Point(), GetTransform().size), diff --git a/core/base/Text.cpp b/core/base/Text.cpp index 60595071..5bc25a15 100644 --- a/core/base/Text.cpp +++ b/core/base/Text.cpp @@ -24,72 +24,54 @@ namespace easy2d { - //------------------------------------------------------- - // Style - //------------------------------------------------------- + namespace + { + Font text_default_font; + TextStyle text_default_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(StrokeStyle::Round) - {} + void easy2d::Text::SetDefaultFont(Font const & font) + { + text_default_font = font; + } - 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, - StrokeStyle 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 - //------------------------------------------------------- + void easy2d::Text::SetDefaultStyle(TextStyle const & style) + { + text_default_style = style; + } Text::Text() - : font_() - , style_() + : font_(text_default_font) + , style_(text_default_style) , text_layout_(nullptr) , text_format_(nullptr) + , dirty_layout_(false) { } - Text::Text(const String & text, const Font & font, const Style & style) + Text::Text(const String & text) + : Text(text, text_default_font, text_default_style) + { + } + + Text::Text(const String & text, const Font & font) + : Text(text, font, text_default_style) + { + } + + Text::Text(const String & text, const TextStyle & style) + : Text(text, text_default_font, style) + { + } + + Text::Text(const String & text, const Font & font, const TextStyle & style) : font_(font) , style_(style) + , text_(text) , text_layout_(nullptr) , text_format_(nullptr) - , text_(text) + , dirty_layout_(true) { - Reset(); } Text::~Text() @@ -108,7 +90,7 @@ namespace easy2d return font_; } - const Text::Style& Text::GetStyle() const + const TextStyle& Text::GetStyle() const { return style_; } @@ -123,7 +105,7 @@ namespace easy2d return font_.size; } - UINT Text::GetFontWeight() const + unsigned int Text::GetFontWeight() const { return font_.weight; } @@ -150,16 +132,30 @@ namespace easy2d int Text::GetLineCount() const { + UpdateLayout(); if (text_layout_) { DWRITE_TEXT_METRICS metrics; - text_layout_->GetMetrics(&metrics); - return static_cast(metrics.lineCount); + if (SUCCEEDED(text_layout_->GetMetrics(&metrics))) + { + return static_cast(metrics.lineCount); + } } - else + return 0; + } + + Rect Text::GetContentBounds() const + { + UpdateLayout(); + if (text_layout_) { - return 0; + DWRITE_TEXT_METRICS metrics; + if (SUCCEEDED(text_layout_->GetMetrics(&metrics))) + { + return Rect(0.f, 0.f, metrics.layoutWidth, metrics.height); + } } + return Rect{}; } bool Text::IsItalic() const @@ -167,17 +163,17 @@ namespace easy2d return font_.italic; } - bool Text::strikethrough() const + bool Text::HasStrikethrough() const { return style_.strikethrough; } - bool Text::underline() const + bool Text::HasUnderline() const { return style_.underline; } - bool Text::outline() const + bool Text::HasOutline() const { return style_.outline; } @@ -185,48 +181,60 @@ namespace easy2d void Text::SetText(const String& text) { text_ = text; - Reset(); + dirty_layout_ = true; } - void Text::SetStyle(const Style& style) + void Text::SetStyle(const TextStyle& style) { style_ = style; - Reset(); + dirty_layout_ = true; } void Text::SetFont(const Font & font) { font_ = font; - Reset(); + dirty_layout_ = true; } void Text::SetFontFamily(const String& family) { - font_.family = family; - Reset(); + if (font_.family != family) + { + font_.family = family; + dirty_layout_ = true; + } } void Text::SetFontSize(float size) { - font_.size = size; - Reset(); + if (font_.size != size) + { + font_.size = size; + dirty_layout_ = true; + } } - void Text::SetFontWeight(UINT weight) + void Text::SetFontWeight(unsigned int weight) { - font_.weight = weight; - Reset(); + if (font_.weight != weight) + { + font_.weight = weight; + dirty_layout_ = true; + } } - void Text::SetColor(Color color) + void Text::SetColor(Color const& color) { style_.color = color; } void Text::SetItalic(bool val) { - font_.italic = val; - Reset(); + if (font_.italic != val) + { + font_.italic = val; + dirty_layout_ = true; + } } void Text::SetWrapEnabled(bool wrap) @@ -234,7 +242,7 @@ namespace easy2d if (style_.wrap != wrap) { style_.wrap = wrap; - Reset(); + dirty_layout_ = true; } } @@ -243,11 +251,7 @@ namespace easy2d if (style_.wrap_width != wrap_width) { style_.wrap_width = std::max(wrap_width, 0.f); - - if (style_.wrap) - { - Reset(); - } + dirty_layout_ = true; } } @@ -256,16 +260,16 @@ namespace easy2d if (style_.line_spacing != line_spacing) { style_.line_spacing = line_spacing; - Reset(); + dirty_layout_ = true; } } - void Text::SetAlignment(Align align) + void Text::SetAlignment(TextAlign align) { if (style_.alignment != align) { style_.alignment = align; - Reset(); + dirty_layout_ = true; } } @@ -274,9 +278,7 @@ namespace easy2d if (style_.underline != underline) { style_.underline = underline; - if (!text_format_) - CreateFormat(); - CreateLayout(); + dirty_layout_ = true; } } @@ -285,9 +287,7 @@ namespace easy2d if (style_.strikethrough != strikethrough) { style_.strikethrough = strikethrough; - if (!text_format_) - CreateFormat(); - CreateLayout(); + dirty_layout_ = true; } } @@ -296,7 +296,7 @@ namespace easy2d style_.outline = outline; } - void Text::SetOutlineColor(Color outline_color) + void Text::SetOutlineColor(Color const&outline_color) { style_.outline_color = outline_color; } @@ -313,47 +313,43 @@ namespace easy2d void Text::OnDraw() const { + UpdateLayout(); + if (text_layout_) { - // 创建文本区域 - D2D1_RECT_F textLayoutRect = D2D1::RectF(0, 0, GetTransform().size.width, GetTransform().size.height); - // 设置画刷颜色和透明度 - devices::Graphics::Instance().SetBrushOpacity(GetDisplayOpacity()); - // 获取文本渲染器 - devices::Graphics::Instance().SetTextStyle( + auto graphics = devices::Graphics::Instance(); + graphics->SetBrushOpacity(GetDisplayOpacity()); + graphics->SetTextStyle( style_.color, style_.outline, style_.outline_color, style_.outline_width, style_.outline_stroke ); - devices::Graphics::Instance().DrawTextLayout(text_layout_); + graphics->DrawTextLayout(text_layout_); } } - void Text::Reset() + void Text::UpdateLayout() const { - // 创建文字格式化 - CreateFormat(); - // 创建文字布局 - CreateLayout(); - } + if (!dirty_layout_) + return; - void Text::CreateFormat() - { SafeRelease(text_format_); + SafeRelease(text_layout_); + + if (text_.empty()) + return; + + auto graphics = devices::Graphics::Instance(); ThrowIfFailed( - devices::Graphics::Instance().CreateTextFormat( + graphics->CreateTextFormat( &text_format_, font_ ) ); - // 设置文字对齐方式 - text_format_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style_.alignment)); - - // 设置行间距 if (style_.line_spacing == 0.f) { text_format_->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_DEFAULT, 0, 0); @@ -366,57 +362,24 @@ namespace easy2d style_.line_spacing * 0.8f ); } + text_format_->SetTextAlignment(DWRITE_TEXT_ALIGNMENT(style_.alignment)); + text_format_->SetWordWrapping(style_.wrap ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP); - // 打开文本自动换行时,设置换行属性 - if (style_.wrap) - { - text_format_->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP); - } - else - { - text_format_->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP); - } - } - - void Text::CreateLayout() - { - SafeRelease(text_layout_); - - // 文本为空字符串时,重置属性 - if (text_.empty()) - { - this->SetSize(0, 0); - return; - } - - if (text_format_ == nullptr) - { - E2D_WARNING("Text::CreateLayout failed! text_format_ NULL pointer exception."); - return; - } - - // 对文本自动换行情况下进行处理 if (style_.wrap) { ThrowIfFailed( - devices::Graphics::Instance().CreateTextLayout( + graphics->CreateTextLayout( &text_layout_, text_, text_format_, style_.wrap_width ) ); - // 获取文本布局的宽度和高度 - DWRITE_TEXT_METRICS metrics; - text_layout_->GetMetrics(&metrics); - // 重设文本宽高 - this->SetSize(metrics.layoutWidth, metrics.height); } else { - // 为防止文本对齐问题,根据先创建 layout 以获取宽度 ThrowIfFailed( - devices::Graphics::Instance().CreateTextLayout( + graphics->CreateTextLayout( &text_layout_, text_, text_format_, @@ -424,25 +387,20 @@ namespace easy2d ) ); - // 获取文本布局的宽度和高度 DWRITE_TEXT_METRICS metrics; text_layout_->GetMetrics(&metrics); - // 重设文本宽高 - this->SetSize(metrics.width, metrics.height); - // 重新创建 layout SafeRelease(text_layout_); ThrowIfFailed( - devices::Graphics::Instance().CreateTextLayout( + graphics->CreateTextLayout( &text_layout_, text_, text_format_, - GetTransform().size.width + metrics.width ) ); } - // 添加下划线和删除线 DWRITE_TEXT_RANGE range = { 0, static_cast(text_.length()) }; if (style_.underline) { @@ -452,5 +410,7 @@ namespace easy2d { text_layout_->SetStrikethrough(true, range); } + + dirty_layout_ = false; } } diff --git a/core/base/Text.h b/core/base/Text.h index 8a8eb1d7..bee080a4 100644 --- a/core/base/Text.h +++ b/core/base/Text.h @@ -20,7 +20,8 @@ #pragma once #include "Node.h" -#include "Font.h" +#include "Font.hpp" +#include "TextStyle.hpp" namespace easy2d { @@ -30,56 +31,27 @@ namespace easy2d { E2D_DISABLE_COPY(Text); - public: - // 文本对齐方式 - enum class Align - { - Left, /* 左对齐 */ - Right, /* 右对齐 */ - Center /* 居中对齐 */ - }; - - // 文本样式 - class Style - { - public: - Color color; // 颜色 - Align alignment; // 对齐方式 - bool wrap; // 打开自动换行 - float wrap_width; // 自动换行宽度 - float line_spacing; // 行间距 - bool underline; // 下划线 - bool strikethrough; // 删除线 - bool outline; // 显示描边 - Color outline_color; // 描边颜色 - float outline_width; // 描边线宽 - StrokeStyle outline_stroke; // 描边线相交样式 - - public: - Style(); - - Style( - Color color, - Align alignment = Align::Left, - bool wrap = false, - float wrap_width = 0.f, - float line_spacing = 0.f, - bool underline = false, - bool strikethrough = false, - bool outline = true, - Color outline_color = Color(Color::Black, 0.5), - float outline_width = 1.f, - StrokeStyle outline_stroke = StrokeStyle::Round - ); - }; - public: Text(); explicit Text( - const String& text, /* 文字内容 */ - const Font& font = Font(), /* 字体 */ - const Style& style = Style() /* 文本样式 */ + const String& text /* 文字内容 */ + ); + + explicit Text( + const String& text, /* 文字内容 */ + const Font& font /* 字体 */ + ); + + explicit Text( + const String& text, /* 文字内容 */ + const TextStyle& style /* 文本样式 */ + ); + + explicit Text( + const String& text, /* 文字内容 */ + const Font& font, /* 字体 */ + const TextStyle& style /* 文本样式 */ ); virtual ~Text(); @@ -91,7 +63,7 @@ namespace easy2d const Font& GetFont() const; // 获取文本样式 - const Style& GetStyle() const; + const TextStyle& GetStyle() const; // 获取字体族 const String& GetFontFamily() const; @@ -100,7 +72,7 @@ namespace easy2d float GetFontSize() const; // 获取当前字体粗细值 - UINT GetFontWeight() const; + unsigned int GetFontWeight() const; // 获取文字颜色 const Color& GetColor() const; @@ -117,17 +89,20 @@ namespace easy2d // 获取文本显示行数 int GetLineCount() const; + // 获取文字包围盒 + Rect GetContentBounds() const; + // 是否是斜体 bool IsItalic() const; // 是否显示删除线 - bool strikethrough() const; + bool HasStrikethrough() const; // 是否显示下划线 - bool underline() const; + bool HasUnderline() const; // 是否显示描边 - bool outline() const; + bool HasOutline() const; // 设置文本 void SetText( @@ -136,7 +111,7 @@ namespace easy2d // 设置文本样式 void SetStyle( - const Style& style + const TextStyle& style ); // 设置字体 @@ -156,12 +131,12 @@ namespace easy2d // 设置字体粗细值(默认值为 Text::Font::Weight::Normal) void SetFontWeight( - UINT weight + unsigned int weight ); // 设置文字颜色(默认值为 Color::WHITE) void SetColor( - Color color + Color const& color ); // 设置文字斜体(默认值为 false) @@ -184,9 +159,9 @@ namespace easy2d float line_spacing ); - // 设置对齐方式(默认为 Align::Left) + // 设置对齐方式(默认为 TextAlign::Left) void SetAlignment( - Align align + TextAlign align ); // 设置下划线(默认值为 false) @@ -206,7 +181,7 @@ namespace easy2d // 设置描边颜色 void SetOutlineColor( - Color outline_color + Color const& outline_color ); // 设置描边线宽 @@ -219,24 +194,28 @@ namespace easy2d StrokeStyle outline_stroke ); + // 设置默认字体 + static void SetDefaultFont( + Font const& font + ); + + // 设置默认文字样式 + static void SetDefaultStyle( + TextStyle const& style + ); + // 渲染文字 virtual void OnDraw() const override; private: - // 重新排版文字 - void Reset(); - - // 创建文字格式化 - void CreateFormat(); - - // 创建文字布局 - void CreateLayout(); + void UpdateLayout() const; private: String text_; - Font font_; - Style style_; - IDWriteTextFormat* text_format_; - IDWriteTextLayout* text_layout_; + Font font_; + TextStyle style_; + mutable bool dirty_layout_; + mutable IDWriteTextFormat* text_format_; + mutable IDWriteTextLayout* text_layout_; }; } \ No newline at end of file diff --git a/core/base/TextRenderer.cpp b/core/base/TextRenderer.cpp index a0a9affd..51ddceb8 100644 --- a/core/base/TextRenderer.cpp +++ b/core/base/TextRenderer.cpp @@ -73,7 +73,7 @@ namespace easy2d bShowOutline_ = outline; sOutlineColor_ = outline_color; fOutlineWidth = 2 * outline_width; - pCurrStrokeStyle_ = devices::Graphics::Instance().GetStrokeStyle(StrokeStyle(outlineJoin)); + pCurrStrokeStyle_ = devices::Graphics::Instance()->GetStrokeStyle(StrokeStyle(outlineJoin)); } STDMETHODIMP ITextRenderer::DrawGlyphRun( diff --git a/core/base/TextStyle.hpp b/core/base/TextStyle.hpp new file mode 100644 index 00000000..c1c57f79 --- /dev/null +++ b/core/base/TextStyle.hpp @@ -0,0 +1,91 @@ +// 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. + +#pragma once +#include "base.h" + +namespace easy2d +{ + // 文本对齐方式 + enum class TextAlign + { + Left, /* 左对齐 */ + Right, /* 右对齐 */ + Center /* 居中对齐 */ + }; + + // 文本样式 + class TextStyle + { + public: + Color color; // 颜色 + TextAlign alignment; // 对齐方式 + bool wrap; // 打开自动换行 + float wrap_width; // 自动换行宽度 + float line_spacing; // 行间距 + bool underline; // 下划线 + bool strikethrough; // 删除线 + bool outline; // 显示描边 + Color outline_color; // 描边颜色 + float outline_width; // 描边线宽 + StrokeStyle outline_stroke; // 描边线相交样式 + + public: + TextStyle() + : color(Color::White) + , alignment(TextAlign::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(StrokeStyle::Round) + {} + + TextStyle( + Color color, + TextAlign alignment = TextAlign::Left, + bool wrap = false, + float wrap_width = 0.f, + float line_spacing = 0.f, + bool underline = false, + bool strikethrough = false, + bool outline = true, + Color outline_color = Color(Color::Black, 0.5), + float outline_width = 1.f, + StrokeStyle outline_stroke = StrokeStyle::Round + ) + : 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) + {} + }; +} \ No newline at end of file diff --git a/core/base/Transition.cpp b/core/base/Transition.cpp index 7c160062..922eb4b1 100644 --- a/core/base/Transition.cpp +++ b/core/base/Transition.cpp @@ -67,18 +67,18 @@ namespace easy2d if (in_scene_) { ThrowIfFailed( - devices::Graphics::Instance().CreateLayer(&in_layer_) + devices::Graphics::Instance()->CreateLayer(&in_layer_) ); } if (out_scene_) { ThrowIfFailed( - devices::Graphics::Instance().CreateLayer(&out_layer_) + devices::Graphics::Instance()->CreateLayer(&out_layer_) ); } - window_size_ = Window::Instance().GetSize(); + window_size_ = Window::Instance()->GetSize(); out_layer_prop_ = in_layer_prop_ = LayerProperties{ Rect(Point(), window_size_),1.f }; } @@ -102,34 +102,34 @@ namespace easy2d void Transition::Draw() { - auto& graphics = devices::Graphics::Instance(); + auto graphics = devices::Graphics::Instance(); if (out_scene_) { - graphics.PushClip( + graphics->PushClip( out_scene_->GetTransform().ToMatrix(), window_size_ ); - graphics.PushLayer(out_layer_, out_layer_prop_); + graphics->PushLayer(out_layer_, out_layer_prop_); out_scene_->Visit(); - graphics.PopLayer(); - graphics.PopClip(); + graphics->PopLayer(); + graphics->PopClip(); } if (in_scene_) { - graphics.PushClip( + graphics->PushClip( in_scene_->GetTransform().ToMatrix(), window_size_ ); - graphics.PushLayer(in_layer_, in_layer_prop_); + graphics->PushLayer(in_layer_, in_layer_prop_); in_scene_->Visit(); - graphics.PopLayer(); - graphics.PopClip(); + graphics->PopLayer(); + graphics->PopClip(); } } diff --git a/core/base/audio.cpp b/core/base/audio.cpp index 86e61317..9e127089 100644 --- a/core/base/audio.cpp +++ b/core/base/audio.cpp @@ -45,7 +45,7 @@ namespace easy2d { Destroy(); - devices::Audio::Instance().DeleteVoice(this); + devices::Audio::Instance()->DeleteVoice(this); } HRESULT Voice::Play(const BYTE * wave_data, UINT32 data_size, UINT32 loop_count) diff --git a/core/base/render.h b/core/base/render.h index c6eebec4..f0ec43e9 100644 --- a/core/base/render.h +++ b/core/base/render.h @@ -21,7 +21,7 @@ #pragma once #include "base.h" #include "Singleton.hpp" -#include "Font.h" +#include "Font.hpp" #include "Resource.h" #include "TextRenderer.h" #include "../math/Matrix.hpp" diff --git a/core/base/window.cpp b/core/base/window.cpp index 3dda8a45..fafc6687 100644 --- a/core/base/window.cpp +++ b/core/base/window.cpp @@ -308,7 +308,7 @@ namespace easy2d // 如果程序接收到一个 WM_SIZE 消息,这个方法将调整渲染 // 目标的大小。它可能会调用失败,但是这里可以忽略有可能的 // 错误,因为这个错误将在下一次调用 EndDraw 时产生 - devices::Graphics::Instance().Resize(width, height); + devices::Graphics::Instance()->Resize(width, height); } break; diff --git a/core/easy2d.h b/core/easy2d.h index 32d07322..90247436 100644 --- a/core/easy2d.h +++ b/core/easy2d.h @@ -42,7 +42,8 @@ #include "base/Size.h" #include "base/Rect.hpp" -#include "base/Font.h" +#include "base/Font.hpp" +#include "base/TextStyle.hpp" #include "base/Color.h" #include "base/Resource.h" diff --git a/core/ui/Button.cpp b/core/ui/Button.cpp index bcb0d6dc..647de6c4 100644 --- a/core/ui/Button.cpp +++ b/core/ui/Button.cpp @@ -227,7 +227,7 @@ namespace easy2d if (IsVisible() && !enabled_ && normal_ && - normal_->ContainsPoint(devices::Input::Instance().GetMousePos())) + normal_->ContainsPoint(devices::Input::Instance()->GetMousePos())) { HCURSOR hcursor = ::LoadCursor(nullptr, IDC_NO); if (hcursor) diff --git a/core/utils/Path.cpp b/core/utils/Path.cpp index 583b8e88..7d21dc98 100644 --- a/core/utils/Path.cpp +++ b/core/utils/Path.cpp @@ -62,7 +62,7 @@ namespace easy2d { // 设置数据的保存路径 String local_app_data_path = Path::GetLocalAppDataPath(); - String title = Window::Instance().GetTitle(); + String title = Window::Instance()->GetTitle(); String folder_name = std::to_wstring(std::hash{}(title)); if (!local_app_data_path.empty()) @@ -90,7 +90,7 @@ namespace easy2d { // 设置临时文件保存路径 wchar_t path[_MAX_PATH]; - String title = Window::Instance().GetTitle(); + String title = Window::Instance()->GetTitle(); String folder_name = std::to_wstring(std::hash{}(title)); if (0 != ::GetTempPath(_MAX_PATH, path)) diff --git a/project/vs2013/Easy2D.vcxproj b/project/vs2013/Easy2D.vcxproj index a7adfffe..102fd657 100644 --- a/project/vs2013/Easy2D.vcxproj +++ b/project/vs2013/Easy2D.vcxproj @@ -30,7 +30,7 @@ - + @@ -54,6 +54,7 @@ + @@ -80,7 +81,6 @@ - diff --git a/project/vs2013/Easy2D.vcxproj.filters b/project/vs2013/Easy2D.vcxproj.filters index f6f9434a..402decff 100644 --- a/project/vs2013/Easy2D.vcxproj.filters +++ b/project/vs2013/Easy2D.vcxproj.filters @@ -29,9 +29,6 @@ base - - base - base @@ -152,6 +149,12 @@ math + + base + + + base + @@ -189,9 +192,6 @@ base - - base - base diff --git a/project/vs2015/Easy2D.vcxproj b/project/vs2015/Easy2D.vcxproj index 147515de..6363f073 100644 --- a/project/vs2015/Easy2D.vcxproj +++ b/project/vs2015/Easy2D.vcxproj @@ -30,7 +30,7 @@ - + @@ -54,6 +54,7 @@ + @@ -80,7 +81,6 @@ - diff --git a/project/vs2015/Easy2D.vcxproj.filters b/project/vs2015/Easy2D.vcxproj.filters index f6f9434a..402decff 100644 --- a/project/vs2015/Easy2D.vcxproj.filters +++ b/project/vs2015/Easy2D.vcxproj.filters @@ -29,9 +29,6 @@ base - - base - base @@ -152,6 +149,12 @@ math + + base + + + base + @@ -189,9 +192,6 @@ base - - base - base diff --git a/project/vs2017/Easy2D.vcxproj b/project/vs2017/Easy2D.vcxproj index bf0ad502..b1cfa82f 100644 --- a/project/vs2017/Easy2D.vcxproj +++ b/project/vs2017/Easy2D.vcxproj @@ -30,7 +30,7 @@ - + @@ -54,6 +54,7 @@ + @@ -80,7 +81,6 @@ - diff --git a/project/vs2017/Easy2D.vcxproj.filters b/project/vs2017/Easy2D.vcxproj.filters index f6f9434a..402decff 100644 --- a/project/vs2017/Easy2D.vcxproj.filters +++ b/project/vs2017/Easy2D.vcxproj.filters @@ -29,9 +29,6 @@ base - - base - base @@ -152,6 +149,12 @@ math + + base + + + base + @@ -189,9 +192,6 @@ base - - base - base