Fix incorrect TextLayout width
This commit is contained in:
parent
60899a6a9b
commit
794df63a10
|
|
@ -80,7 +80,7 @@ FixturePtr Fixture::CreateRect(Body* body, Param const& param, Size const& size,
|
|||
b2Vec2 b2offset = world->Stage2World(offset);
|
||||
|
||||
b2PolygonShape shape;
|
||||
shape.SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, rotation);
|
||||
shape.SetAsBox(b2size.x / 2, b2size.y / 2, b2offset, math::Degree2Radian(rotation));
|
||||
|
||||
return CreateFixture(body, &shape, param);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,10 +242,23 @@ ContactList World::GetContactList()
|
|||
|
||||
void World::Update(Duration dt)
|
||||
{
|
||||
world_.Step(dt.Seconds(), vel_iter_, pos_iter_);
|
||||
|
||||
b2Body* b2body = world_.GetBodyList();
|
||||
while (b2body)
|
||||
{
|
||||
Body* body = static_cast<Body*>(b2body->GetUserData());
|
||||
if (body && body->GetType() != Body::Type::Static)
|
||||
{
|
||||
body->UpdateFromActor();
|
||||
}
|
||||
|
||||
b2body = b2body->GetNext();
|
||||
}
|
||||
|
||||
world_.Step(dt.Seconds(), vel_iter_, pos_iter_);
|
||||
|
||||
b2body = world_.GetBodyList();
|
||||
while (b2body)
|
||||
{
|
||||
Body* body = static_cast<Body*>(b2body->GetUserData());
|
||||
if (body && body->GetType() != Body::Type::Static)
|
||||
|
|
|
|||
|
|
@ -260,13 +260,13 @@ void Actor::HandleEvent(Event* evt)
|
|||
}
|
||||
}
|
||||
|
||||
Matrix3x2 const& Actor::GetTransformMatrix() const
|
||||
const Matrix3x2& Actor::GetTransformMatrix() const
|
||||
{
|
||||
UpdateTransform();
|
||||
return transform_matrix_;
|
||||
}
|
||||
|
||||
Matrix3x2 const& Actor::GetTransformInverseMatrix() const
|
||||
const Matrix3x2& Actor::GetTransformInverseMatrix() const
|
||||
{
|
||||
UpdateTransform();
|
||||
if (dirty_transform_inverse_)
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 获取坐标
|
||||
Point const& GetPosition() const;
|
||||
virtual Point GetPosition() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取 x 坐标
|
||||
|
|
@ -124,6 +124,10 @@ public:
|
|||
/// @brief 获取 y 坐标
|
||||
float GetPositionY() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取大小
|
||||
virtual Size GetSize() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取宽度
|
||||
float GetWidth() const;
|
||||
|
|
@ -132,10 +136,6 @@ public:
|
|||
/// @brief 获取高度
|
||||
float GetHeight() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取大小
|
||||
Size const& GetSize() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放后的宽度
|
||||
float GetScaledWidth() const;
|
||||
|
|
@ -150,7 +150,7 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 获取锚点
|
||||
Point const& GetAnchor() const;
|
||||
virtual Point GetAnchor() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取 x 方向锚点
|
||||
|
|
@ -162,7 +162,7 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 获取透明度
|
||||
float GetOpacity() const;
|
||||
virtual float GetOpacity() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取显示透明度
|
||||
|
|
@ -170,11 +170,11 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 获取旋转角度
|
||||
float GetRotation() const;
|
||||
virtual float GetRotation() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取缩放比例
|
||||
Point const& GetScale() const;
|
||||
virtual Point GetScale() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取横向缩放比例
|
||||
|
|
@ -186,7 +186,7 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 获取错切角度
|
||||
Point const& GetSkew() const;
|
||||
virtual Point GetSkew() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取横向错切角度
|
||||
|
|
@ -218,11 +218,11 @@ public:
|
|||
|
||||
/// \~chinese
|
||||
/// @brief 获取二维变换矩阵
|
||||
Matrix3x2 const& GetTransformMatrix() const;
|
||||
const Matrix3x2& GetTransformMatrix() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取二维变换的逆矩阵
|
||||
Matrix3x2 const& GetTransformInverseMatrix() const;
|
||||
const Matrix3x2& GetTransformInverseMatrix() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置角色是否可见
|
||||
|
|
@ -284,14 +284,6 @@ public:
|
|||
/// @brief 设置锚点位置,默认为 (0, 0), 范围 [0, 1]
|
||||
void SetAnchor(float anchorx, float anchory);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改宽度
|
||||
virtual void SetWidth(float width);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改高度
|
||||
virtual void SetHeight(float height);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改大小
|
||||
virtual void SetSize(Size const& size);
|
||||
|
|
@ -300,6 +292,14 @@ public:
|
|||
/// @brief 修改大小
|
||||
void SetSize(float width, float height);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改宽度
|
||||
void SetWidth(float width);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 修改高度
|
||||
void SetHeight(float height);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置透明度,默认为 1.0, 范围 [0, 1]
|
||||
virtual void SetOpacity(float opacity);
|
||||
|
|
@ -514,7 +514,7 @@ inline int Actor::GetZOrder() const
|
|||
return z_order_;
|
||||
}
|
||||
|
||||
inline Point const& Actor::GetPosition() const
|
||||
inline Point Actor::GetPosition() const
|
||||
{
|
||||
return transform_.position;
|
||||
}
|
||||
|
|
@ -529,7 +529,7 @@ inline float Actor::GetPositionY() const
|
|||
return GetPosition().y;
|
||||
}
|
||||
|
||||
inline Point const& Actor::GetScale() const
|
||||
inline Point Actor::GetScale() const
|
||||
{
|
||||
return transform_.scale;
|
||||
}
|
||||
|
|
@ -544,7 +544,7 @@ inline float Actor::GetScaleY() const
|
|||
return GetScale().y;
|
||||
}
|
||||
|
||||
inline Point const& Actor::GetSkew() const
|
||||
inline Point Actor::GetSkew() const
|
||||
{
|
||||
return transform_.skew;
|
||||
}
|
||||
|
|
@ -574,7 +574,7 @@ inline float Actor::GetHeight() const
|
|||
return GetSize().y;
|
||||
}
|
||||
|
||||
inline Size const& Actor::GetSize() const
|
||||
inline Size Actor::GetSize() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
|
@ -594,7 +594,7 @@ inline Size Actor::GetScaledSize() const
|
|||
return Size{ GetScaledWidth(), GetScaledHeight() };
|
||||
}
|
||||
|
||||
inline Point const& Actor::GetAnchor() const
|
||||
inline Point Actor::GetAnchor() const
|
||||
{
|
||||
return anchor_;
|
||||
}
|
||||
|
|
@ -693,4 +693,5 @@ inline void Actor::SetSkew(float skewx, float skewy)
|
|||
{
|
||||
SetSkew(Vec2{ skewx, skewy });
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ void DebugActor::OnUpdate(Duration dt)
|
|||
|
||||
debug_text_.Reset(ss.str(), debug_text_style_);
|
||||
|
||||
Size layout_size = debug_text_.GetLayoutSize();
|
||||
Size layout_size = debug_text_.GetSize();
|
||||
if (layout_size.x > GetWidth() - 20)
|
||||
{
|
||||
SetWidth(20 + layout_size.x);
|
||||
|
|
|
|||
|
|
@ -61,34 +61,10 @@ void TextActor::OnRender(RenderContext& ctx)
|
|||
}
|
||||
}
|
||||
|
||||
void TextActor::OnUpdate(Duration dt)
|
||||
Size TextActor::GetSize() const
|
||||
{
|
||||
UpdateLayout();
|
||||
}
|
||||
|
||||
void TextActor::UpdateLayout()
|
||||
{
|
||||
if (!layout_)
|
||||
return;
|
||||
|
||||
if (layout_->GetDirtyFlag() == TextLayout::DirtyFlag::Updated)
|
||||
{
|
||||
layout_->SetDirtyFlag(TextLayout::DirtyFlag::Clean);
|
||||
|
||||
if (text_.empty())
|
||||
{
|
||||
SetSize(Size());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSize(layout_->GetLayoutSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool TextActor::CheckVisibility(RenderContext& ctx) const
|
||||
{
|
||||
return layout_ && layout_->IsValid() && Actor::CheckVisibility(ctx);
|
||||
const_cast<TextActor*>(this)->UpdateDirtyLayout();
|
||||
return Actor::GetSize();
|
||||
}
|
||||
|
||||
void TextActor::SetFillColor(Color const& color)
|
||||
|
|
@ -124,7 +100,7 @@ void TextActor::SetTextLayout(TextLayoutPtr layout)
|
|||
if (layout_ != layout)
|
||||
{
|
||||
layout_ = layout;
|
||||
UpdateLayout();
|
||||
ForceUpdateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -294,4 +270,39 @@ void TextActor::SetOutlineStrokeStyle(StrokeStylePtr stroke)
|
|||
}
|
||||
}
|
||||
|
||||
void TextActor::Update(Duration dt)
|
||||
{
|
||||
this->UpdateDirtyLayout();
|
||||
Actor::Update(dt);
|
||||
}
|
||||
|
||||
bool TextActor::CheckVisibility(RenderContext& ctx) const
|
||||
{
|
||||
return layout_ && layout_->IsValid() && Actor::CheckVisibility(ctx);
|
||||
}
|
||||
|
||||
void TextActor::UpdateDirtyLayout()
|
||||
{
|
||||
KGE_ASSERT(layout_);
|
||||
if (layout_->UpdateWhenDirty())
|
||||
{
|
||||
ForceUpdateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
void TextActor::ForceUpdateLayout()
|
||||
{
|
||||
KGE_ASSERT(layout_);
|
||||
|
||||
layout_->UpdateWhenDirty();
|
||||
if (text_.empty())
|
||||
{
|
||||
SetSize(Size());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetSize(layout_->GetSize());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -67,8 +67,8 @@ public:
|
|||
TextLayoutPtr GetLayout() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取文本布局大小
|
||||
Size GetLayoutSize() const;
|
||||
/// @brief 获取大小
|
||||
Size GetSize() const override;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取填充画刷
|
||||
|
|
@ -159,15 +159,20 @@ public:
|
|||
void SetTextLayout(TextLayoutPtr layout);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 更新文字布局
|
||||
/// @brief 更新脏文字布局
|
||||
/// @details 仅当文字布局脏时更新
|
||||
void UpdateDirtyLayout();
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 强制更新文字布局
|
||||
/// @details 文字布局是懒更新的,手动更新文字布局以更新节点状态
|
||||
void UpdateLayout();
|
||||
void ForceUpdateLayout();
|
||||
|
||||
void OnRender(RenderContext& ctx) override;
|
||||
|
||||
void OnUpdate(Duration dt) override;
|
||||
|
||||
protected:
|
||||
void Update(Duration dt) override;
|
||||
|
||||
bool CheckVisibility(RenderContext& ctx) const override;
|
||||
|
||||
private:
|
||||
|
|
@ -198,15 +203,6 @@ inline TextLayoutPtr TextActor::GetLayout() const
|
|||
return layout_;
|
||||
}
|
||||
|
||||
inline Size TextActor::GetLayoutSize() const
|
||||
{
|
||||
if (layout_)
|
||||
{
|
||||
return layout_->GetLayoutSize();
|
||||
}
|
||||
return Size();
|
||||
}
|
||||
|
||||
inline BrushPtr TextActor::GetFillBrush() const
|
||||
{
|
||||
return style_.fill_brush;
|
||||
|
|
|
|||
|
|
@ -610,7 +610,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c
|
|||
if (content.empty())
|
||||
{
|
||||
layout.Clear();
|
||||
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
|
||||
layout.SetDirtyFlag(TextLayout::DirtyFlag::Dirty);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -635,7 +635,7 @@ void RendererImpl::CreateTextLayout(TextLayout& layout, const String& content, c
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
NativePtr::Set(layout, output);
|
||||
layout.SetDirtyFlag(TextLayout::DirtyFlag::Updated);
|
||||
layout.SetDirtyFlag(TextLayout::DirtyFlag::Dirty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,14 +45,15 @@ TextLayoutPtr TextLayout::Create(const String& content, const TextStyle& style)
|
|||
|
||||
TextLayout::TextLayout()
|
||||
: dirty_flag_(DirtyFlag::Clean)
|
||||
, line_count_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void TextLayout::Reset(const String& text, const TextStyle& style)
|
||||
void TextLayout::Reset(const String& content, const TextStyle& style)
|
||||
{
|
||||
if (!text.empty())
|
||||
if (!content.empty())
|
||||
{
|
||||
Renderer::GetInstance().CreateTextLayout(*this, text, style);
|
||||
Renderer::GetInstance().CreateTextLayout(*this, content, style);
|
||||
|
||||
SetAlignment(style.alignment);
|
||||
SetWrapWidth(style.wrap_width);
|
||||
|
|
@ -63,80 +64,58 @@ void TextLayout::Reset(const String& text, const TextStyle& style)
|
|||
SetDefaultOutlineStrokeStyle(style.outline_stroke);
|
||||
|
||||
if (style.show_underline)
|
||||
SetUnderline(style.show_underline, { 0, text.length() });
|
||||
SetUnderline(style.show_underline, { 0, content.length() });
|
||||
|
||||
if (style.show_strikethrough)
|
||||
SetStrikethrough(style.show_strikethrough, { 0, text.length() });
|
||||
SetStrikethrough(style.show_strikethrough, { 0, content.length() });
|
||||
}
|
||||
else
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
content_ = content;
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
Size TextLayout::GetSize() const
|
||||
{
|
||||
const_cast<TextLayout*>(this)->UpdateWhenDirty();
|
||||
return size_;
|
||||
}
|
||||
|
||||
uint32_t TextLayout::GetLineCount() const
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
{
|
||||
DWRITE_TEXT_METRICS metrics;
|
||||
if (SUCCEEDED(native->GetMetrics(&metrics)))
|
||||
{
|
||||
return metrics.lineCount;
|
||||
}
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
Size TextLayout::GetLayoutSize() const
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
{
|
||||
DWRITE_TEXT_METRICS metrics;
|
||||
if (SUCCEEDED(native->GetMetrics(&metrics)))
|
||||
{
|
||||
return (metrics.layoutWidth > 0) ? Size(metrics.layoutWidth, metrics.height)
|
||||
: Size(metrics.width, metrics.height);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
return Size();
|
||||
const_cast<TextLayout*>(this)->UpdateWhenDirty();
|
||||
return line_count_;
|
||||
}
|
||||
|
||||
void TextLayout::SetFont(FontPtr font, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
if (native)
|
||||
{
|
||||
ComPtr<IDWriteFontCollection> collection = NativePtr::Get<IDWriteFontCollection>(font);
|
||||
auto collection = NativePtr::Get<IDWriteFontCollection>(font);
|
||||
|
||||
HRESULT hr = native->SetFontCollection(collection.Get(), { range.start, range.length });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontCollection failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetFontFamily(String const& family, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
|
@ -147,16 +126,18 @@ void TextLayout::SetFontFamily(String const& family, TextRange range)
|
|||
|
||||
HRESULT hr = native->SetFontFamilyName(font_family.c_str(), { range.start, range.length });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontFamilyName failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetFontSize(float size, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
|
@ -165,16 +146,18 @@ void TextLayout::SetFontSize(float size, TextRange range)
|
|||
{
|
||||
HRESULT hr = native->SetFontSize(size, { range.start, range.length });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontSize failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetFontWeight(uint32_t weight, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
|
@ -185,16 +168,18 @@ void TextLayout::SetFontWeight(uint32_t weight, TextRange range)
|
|||
|
||||
HRESULT hr = native->SetFontWeight(font_weight, { range.start, range.length });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontWeight failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetItalic(bool italic, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
|
@ -205,16 +190,18 @@ void TextLayout::SetItalic(bool italic, TextRange range)
|
|||
|
||||
HRESULT hr = native->SetFontStyle(font_style, { range.start, range.length });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetFontStyle failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetUnderline(bool enable, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
|
@ -223,16 +210,18 @@ void TextLayout::SetUnderline(bool enable, TextRange range)
|
|||
{
|
||||
HRESULT hr = native->SetUnderline(enable, { range.start, range.length });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetUnderline failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetStrikethrough(bool enable, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
|
@ -241,16 +230,18 @@ void TextLayout::SetStrikethrough(bool enable, TextRange range)
|
|||
{
|
||||
HRESULT hr = native->SetStrikethrough(enable, { range.start, range.length });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetStrikethrough failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetFillBrush(BrushPtr brush, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
|
@ -260,16 +251,18 @@ void TextLayout::SetFillBrush(BrushPtr brush, TextRange range)
|
|||
HRESULT hr =
|
||||
native->SetDrawingEffect(NativePtr::Get<ID2D1Brush>(brush).Get(), { range.start, range.length });
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetDrawingEffect failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetOutlineBrush(BrushPtr brush, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
// TODO
|
||||
KGE_NOT_USED(range);
|
||||
|
|
@ -281,6 +274,8 @@ void TextLayout::SetOutlineBrush(BrushPtr brush, TextRange range)
|
|||
|
||||
void TextLayout::SetOutlineStrokeStyle(StrokeStylePtr stroke, TextRange range)
|
||||
{
|
||||
KGE_ASSERT(content_.size() >= (range.start + range.length));
|
||||
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
// TODO
|
||||
KGE_NOT_USED(range);
|
||||
|
|
@ -317,12 +312,12 @@ void TextLayout::SetAlignment(TextAlign align)
|
|||
|
||||
HRESULT hr = native->SetTextAlignment(alignment);
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetTextAlignment failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetWrapWidth(float wrap_width)
|
||||
|
|
@ -333,34 +328,26 @@ void TextLayout::SetWrapWidth(float wrap_width)
|
|||
|
||||
if (native)
|
||||
{
|
||||
DWRITE_WORD_WRAPPING wrapping = (wrap_width > 0) ? DWRITE_WORD_WRAPPING_WRAP : DWRITE_WORD_WRAPPING_NO_WRAP;
|
||||
|
||||
HRESULT hr = native->SetWordWrapping(wrapping);
|
||||
if (SUCCEEDED(hr))
|
||||
HRESULT hr = S_OK;
|
||||
if (wrap_width > 0)
|
||||
{
|
||||
if (wrap_width > 0)
|
||||
hr = native->SetWordWrapping(DWRITE_WORD_WRAPPING_WRAP);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = native->SetMaxWidth(wrap_width);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fix the layout width when the text does not wrap
|
||||
DWRITE_TEXT_METRICS metrics;
|
||||
hr = native->GetMetrics(&metrics);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = native->SetMaxWidth(metrics.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = native->SetWordWrapping(DWRITE_WORD_WRAPPING_NO_WRAP);
|
||||
}
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetWordWrapping failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
void TextLayout::SetLineSpacing(float line_spacing)
|
||||
|
|
@ -383,12 +370,62 @@ void TextLayout::SetLineSpacing(float line_spacing)
|
|||
hr = native->SetLineSpacing(DWRITE_LINE_SPACING_METHOD_UNIFORM, spacing, spacing * 0.8f);
|
||||
}
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::SetLineSpacing failed");
|
||||
|
||||
dirty_flag_ = DirtyFlag::Updated;
|
||||
}
|
||||
#else
|
||||
return; // not supported
|
||||
// not supported
|
||||
#endif
|
||||
|
||||
SetDirtyFlag(DirtyFlag::Dirty);
|
||||
}
|
||||
|
||||
bool TextLayout::UpdateWhenDirty()
|
||||
{
|
||||
#if KGE_RENDER_ENGINE == KGE_RENDER_ENGINE_DIRECTX
|
||||
if (dirty_flag_ == DirtyFlag::Dirty)
|
||||
{
|
||||
SetDirtyFlag(DirtyFlag::Clean);
|
||||
|
||||
auto native = NativePtr::Get<IDWriteTextLayout>(this);
|
||||
KGE_ASSERT(native);
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
DWRITE_TEXT_METRICS metrics;
|
||||
hr = native->GetMetrics(&metrics);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
if (native->GetWordWrapping() == DWRITE_WORD_WRAPPING_NO_WRAP)
|
||||
{
|
||||
// Fix the layout width when the text does not wrap
|
||||
hr = native->SetMaxWidth(metrics.widthIncludingTrailingWhitespace);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = native->GetMetrics(&metrics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
line_count_ = metrics.lineCount;
|
||||
|
||||
if (metrics.layoutWidth > 0)
|
||||
{
|
||||
size_ = Size(metrics.layoutWidth, metrics.height);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_ = Size(metrics.widthIncludingTrailingWhitespace, metrics.height);
|
||||
}
|
||||
}
|
||||
|
||||
KGE_THROW_IF_FAILED(hr, "IDWriteTextLayout::GetMetrics failed");
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
// not supported
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace kiwano
|
||||
|
|
|
|||
|
|
@ -67,12 +67,12 @@ public:
|
|||
void Reset(const String& content, const TextStyle& style);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取文本行数
|
||||
uint32_t GetLineCount() const;
|
||||
/// @brief 获取文本布局大小
|
||||
Size GetSize() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取文本布局大小
|
||||
Size GetLayoutSize() const;
|
||||
/// @brief 获取文本行数
|
||||
uint32_t GetLineCount() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取默认填充画刷
|
||||
|
|
@ -183,23 +183,34 @@ public:
|
|||
void SetDefaultOutlineStrokeStyle(StrokeStylePtr stroke);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 脏数据标志
|
||||
/// @brief 脏布局标志
|
||||
enum class DirtyFlag : uint8_t
|
||||
{
|
||||
Clean = 0, ///< 干净布局
|
||||
Dirty = 1 << 0, ///< 脏布局
|
||||
Updated = 1 << 1, ///< 已更新
|
||||
Clean = 0, ///< 干净布局
|
||||
Dirty = 1 << 0 ///< 脏布局
|
||||
};
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 获取脏布局标志
|
||||
DirtyFlag GetDirtyFlag() const;
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 设置脏布局标志
|
||||
void SetDirtyFlag(DirtyFlag flag);
|
||||
|
||||
/// \~chinese
|
||||
/// @brief 更新脏布局
|
||||
/// @return 是否需要更新
|
||||
bool UpdateWhenDirty();
|
||||
|
||||
private:
|
||||
DirtyFlag dirty_flag_;
|
||||
uint32_t line_count_;
|
||||
Size size_;
|
||||
BrushPtr default_fill_brush_;
|
||||
BrushPtr default_outline_brush_;
|
||||
StrokeStylePtr default_outline_stroke_;
|
||||
String content_;
|
||||
};
|
||||
|
||||
/** @} */
|
||||
|
|
|
|||
Loading…
Reference in New Issue