Adding origin to text. Adds origin to text object that works just like the origin of a parametric path. It can be moved in freeze mode too. Adds support in the editor, Flutter runtime, and C++ runtime. Diffs= 9b8dacbac Adding origin to text. (#5533) Co-authored-by: Luigi Rosso <luigi-rosso@users.noreply.github.com>
diff --git a/.rive_head b/.rive_head index 45184f9..fe43500 100644 --- a/.rive_head +++ b/.rive_head
@@ -1 +1 @@ -797fb4cbd547509dac0a34e1039bfad5de8cd80c +9b8dacbacbfb232303773dd7a6008fdffaecc29c
diff --git a/dev/defs/text/text.json b/dev/defs/text/text.json index 01868a8..faaa9f7 100644 --- a/dev/defs/text/text.json +++ b/dev/defs/text/text.json
@@ -50,6 +50,26 @@ "string": "height" }, "description": "Height of the text object." + }, + "originX": { + "type": "double", + "initialValue": "0.0", + "animates": true, + "key": { + "int": 363, + "string": "originx" + }, + "description": "Origin x in normalized coordinates (0.5 = center, 0 = left, 1 = right)." + }, + "originY": { + "type": "double", + "initialValue": "0.0", + "animates": true, + "key": { + "int": 364, + "string": "originy" + }, + "description": "Origin y in normalized coordinates (0.5 = center, 0 = top, 1 = bottom)." } } -} +} \ No newline at end of file
diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp index 7698ca9..dd2a0a3 100644 --- a/include/rive/generated/core_registry.hpp +++ b/include/rive/generated/core_registry.hpp
@@ -868,6 +868,12 @@ case TextBase::heightPropertyKey: object->as<TextBase>()->height(value); break; + case TextBase::originXPropertyKey: + object->as<TextBase>()->originX(value); + break; + case TextBase::originYPropertyKey: + object->as<TextBase>()->originY(value); + break; case DrawableAssetBase::heightPropertyKey: object->as<DrawableAssetBase>()->height(value); break; @@ -1326,6 +1332,10 @@ return object->as<TextBase>()->width(); case TextBase::heightPropertyKey: return object->as<TextBase>()->height(); + case TextBase::originXPropertyKey: + return object->as<TextBase>()->originX(); + case TextBase::originYPropertyKey: + return object->as<TextBase>()->originY(); case DrawableAssetBase::heightPropertyKey: return object->as<DrawableAssetBase>()->height(); case DrawableAssetBase::widthPropertyKey: @@ -1574,6 +1584,8 @@ case TextStyleAxisBase::axisValuePropertyKey: case TextBase::widthPropertyKey: case TextBase::heightPropertyKey: + case TextBase::originXPropertyKey: + case TextBase::originYPropertyKey: case DrawableAssetBase::heightPropertyKey: case DrawableAssetBase::widthPropertyKey: return CoreDoubleType::id;
diff --git a/include/rive/generated/text/text_base.hpp b/include/rive/generated/text/text_base.hpp index 3d5bcf0..8665d52 100644 --- a/include/rive/generated/text/text_base.hpp +++ b/include/rive/generated/text/text_base.hpp
@@ -39,6 +39,8 @@ static const uint16_t overflowValuePropertyKey = 287; static const uint16_t widthPropertyKey = 285; static const uint16_t heightPropertyKey = 286; + static const uint16_t originXPropertyKey = 363; + static const uint16_t originYPropertyKey = 364; private: uint32_t m_AlignValue = 0; @@ -46,6 +48,8 @@ uint32_t m_OverflowValue = 0; float m_Width = 0.0f; float m_Height = 0.0f; + float m_OriginX = 0.0f; + float m_OriginY = 0.0f; public: inline uint32_t alignValue() const { return m_AlignValue; } @@ -103,6 +107,28 @@ heightChanged(); } + inline float originX() const { return m_OriginX; } + void originX(float value) + { + if (m_OriginX == value) + { + return; + } + m_OriginX = value; + originXChanged(); + } + + inline float originY() const { return m_OriginY; } + void originY(float value) + { + if (m_OriginY == value) + { + return; + } + m_OriginY = value; + originYChanged(); + } + Core* clone() const override; void copy(const TextBase& object) { @@ -111,6 +137,8 @@ m_OverflowValue = object.m_OverflowValue; m_Width = object.m_Width; m_Height = object.m_Height; + m_OriginX = object.m_OriginX; + m_OriginY = object.m_OriginY; Drawable::copy(object); } @@ -133,6 +161,12 @@ case heightPropertyKey: m_Height = CoreDoubleType::deserialize(reader); return true; + case originXPropertyKey: + m_OriginX = CoreDoubleType::deserialize(reader); + return true; + case originYPropertyKey: + m_OriginY = CoreDoubleType::deserialize(reader); + return true; } return Drawable::deserialize(propertyKey, reader); } @@ -143,6 +177,8 @@ virtual void overflowValueChanged() {} virtual void widthChanged() {} virtual void heightChanged() {} + virtual void originXChanged() {} + virtual void originYChanged() {} }; } // namespace rive
diff --git a/include/rive/text/text.hpp b/include/rive/text/text.hpp index bc1fa17..d10b8aa 100644 --- a/include/rive/text/text.hpp +++ b/include/rive/text/text.hpp
@@ -155,6 +155,7 @@ private: #ifdef WITH_RIVE_TEXT + void updateOriginWorldTransform(); std::vector<TextValueRun*> m_runs; std::vector<TextStyle*> m_renderStyles; SimpleArray<Paragraph> m_shape; @@ -163,6 +164,9 @@ std::vector<OrderedLine> m_orderedLines; GlyphRun m_ellipsisRun; std::unique_ptr<RenderPath> m_clipRenderPath; + Mat2D m_originWorldTransform; + float m_actualWidth = 0.0f; + float m_actualHeight = 0.0f; #endif }; } // namespace rive
diff --git a/src/text/text.cpp b/src/text/text.cpp index d70cdf9..4589ccf 100644 --- a/src/text/text.cpp +++ b/src/text/text.cpp
@@ -259,6 +259,7 @@ int paragraphIndex = 0; int lineIndex = 0; float y = 0.0f; + float maxX = 0.0f; int ellipsisLine = -1; bool isEllipsisLineLast = false; @@ -360,6 +361,10 @@ style->propagateOpacity(renderOpacity()); } } + if (x > maxX) + { + maxX = x; + } if (lineIndex == ellipsisLine) { return; @@ -372,6 +377,27 @@ } y += paragraphSpacing; } + switch (sizing()) + { + case TextSizing::autoWidth: + m_actualWidth = maxX; + m_actualHeight = std::max(0.0f, y - paragraphSpacing); + break; + case TextSizing::autoHeight: + m_actualWidth = width(); + m_actualHeight = std::max(0.0f, y - paragraphSpacing); + break; + case TextSizing::fixed: + m_actualWidth = width(); + m_actualHeight = height(); + break; + } +} + +void Text::updateOriginWorldTransform() +{ + m_originWorldTransform = m_WorldTransform * Mat2D::fromTranslate(-m_actualWidth * originX(), + -m_actualHeight * originY()); } void Text::draw(Renderer* renderer) @@ -382,7 +408,7 @@ // transformations. renderer->save(); } - renderer->transform(worldTransform()); + renderer->transform(m_originWorldTransform); if (overflow() == TextOverflow::clipped && m_clipRenderPath) { renderer->clipPath(m_clipRenderPath.get()); @@ -474,6 +500,11 @@ { Super::update(value); + if (hasDirt(value, ComponentDirt::WorldTransform)) + { + updateOriginWorldTransform(); + } + if (hasDirt(value, ComponentDirt::Path)) { std::vector<Unichar> unichars;