From 8130308f7f700e8e965ddace8770c6a32c07a0e5 Mon Sep 17 00:00:00 2001 From: jmsgrogan Date: Wed, 18 Jan 2023 17:31:16 +0000 Subject: [PATCH] Update text rendering. --- src/base/geometry/Bounds.h | 19 ++++- src/base/geometry/Transform.h | 15 ++++ src/publishing/svg/SvgPainter.cpp | 41 +++++++++-- .../graphics/directx/DirectX2dPainter.cpp | 44 +++++++++--- .../graphics/directx/DirectXTextPainter.cpp | 26 +++++-- .../graphics/directx/DirectXTextPainter.h | 5 +- src/rendering/visual_elements/CMakeLists.txt | 2 + .../basic_shapes/RectangleNode.cpp | 10 +-- .../visual_elements/nodes/TextNode.cpp | 4 +- .../visual_elements/nodes/TextNode.h | 4 +- .../visual_elements/scene/SceneText.cpp | 28 ++++++++ .../visual_elements/scene/SceneText.h | 10 +++ .../visual_elements/svg/SvgTextElement.cpp | 53 ++++++++++++++ .../visual_elements/svg/SvgTextElement.h | 21 ++++++ .../svg/elements/SvgShapeElements.cpp | 9 +++ .../svg/elements/SvgShapeElements.h | 2 + src/ui/ui_controls/Button.cpp | 56 ++++++++++++--- src/ui/ui_controls/Button.h | 8 +++ src/ui/ui_controls/ButtonData.cpp | 23 +++++++ src/ui/ui_controls/ButtonData.h | 5 +- src/ui/ui_elements/style/FontTokens.cpp | 64 +++++++++++++++++ src/ui/ui_elements/style/FontTokens.h | 1 + src/ui/ui_elements/widgets/BoxGeometry.cpp | 19 +++++ src/ui/ui_elements/widgets/BoxGeometry.h | 6 ++ src/ui/ui_elements/widgets/Widget.cpp | 69 ++++++++++++------- src/ui/ui_elements/widgets/Widget.h | 10 ++- test/ui_controls/TestButton.cpp | 26 +++++-- 27 files changed, 503 insertions(+), 77 deletions(-) create mode 100644 src/rendering/visual_elements/svg/SvgTextElement.cpp create mode 100644 src/rendering/visual_elements/svg/SvgTextElement.h diff --git a/src/base/geometry/Bounds.h b/src/base/geometry/Bounds.h index d954b7b..abf4c73 100644 --- a/src/base/geometry/Bounds.h +++ b/src/base/geometry/Bounds.h @@ -2,7 +2,7 @@ struct Bounds { - Bounds(double minX, double maxX, double minY, double maxY, double minZ = 0.0, double maxZ = 0.0) + Bounds(double minX = 0.0, double maxX = 0.0, double minY = 0.0, double maxY = 0.0, double minZ = 0.0, double maxZ = 0.0) : mMinX(minX), mMaxX(maxX), mMinY(minY), @@ -60,4 +60,21 @@ struct Bounds mMaxZ = z; } } + + bool operator==(const Bounds& rhs) const + { + return (mMinX == rhs.mMinX) + && (mMaxX == rhs.mMaxX) + + && (mMinY == rhs.mMinY) + && (mMaxY == rhs.mMaxY) + + && (mMinZ == rhs.mMinZ) + && (mMaxZ == rhs.mMaxZ); + } + + bool operator!=(const Bounds& rhs) const + { + return !operator==(rhs); + } }; \ No newline at end of file diff --git a/src/base/geometry/Transform.h b/src/base/geometry/Transform.h index e482d3b..a0d0687 100644 --- a/src/base/geometry/Transform.h +++ b/src/base/geometry/Transform.h @@ -31,6 +31,21 @@ public: return !operator==(rhs); } + bool hasDefaultLocation() const + { + return mLocation.getX() == 0.0 && mLocation.getY() == 0.0 && mLocation.getZ() == 0.0; + } + + bool hasDefaultScale() const + { + return mScaleX == 1.0 && mScaleY == 1.0 && mScaleZ == 1.0; + } + + bool isDefaultTransform() const + { + return hasDefaultLocation() && hasDefaultScale(); + } + private: Point mLocation; double mScaleX{1}; diff --git a/src/publishing/svg/SvgPainter.cpp b/src/publishing/svg/SvgPainter.cpp index 02a12b4..c8e5e62 100644 --- a/src/publishing/svg/SvgPainter.cpp +++ b/src/publishing/svg/SvgPainter.cpp @@ -13,8 +13,10 @@ #include "AbstractFace.h" #include "Circle.h" +#include "Rectangle.h" #include "SvgShapeElements.h" +#include "SvgTextElement.h" #include "XmlAttribute.h" std::unique_ptr SvgPainter::paint(Scene* scene, double width, double height) const @@ -102,22 +104,33 @@ void SvgPainter::setStyle(SceneModel* model, SvgShapeElement* element) const if (model->hasOutlineColor()) { element->setStrokeColor(model->getOutlineColor()); - element->setStrokeWidth(model->getOutlineThickness() / transform.getScaleX()); + element->setStrokeWidth(model->getOutlineThickness()); } else { element->setNoStroke(); } - element->addAttribute(std::move(toTransform(transform))); + + if (!transform.isDefaultTransform()) + { + element->addAttribute(std::move(toTransform(transform))); + } } void SvgPainter::paintPrimitive(SvgDocument* document, SceneModel* model) const { if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE) { + auto model_rect = dynamic_cast(model->getGeometry()); + auto rect = std::make_unique(); - rect->setWidth(1.0); - rect->setHeight(1.0); + rect->setWidth(model_rect->getWidth()); + rect->setHeight(model_rect->getHeight()); + + if (model_rect->getRadius() > 0.0) + { + rect->setRadius(model_rect->getRadius()); + } setStyle(model, rect.get()); document->getRoot()->addChild(std::move(rect)); @@ -139,9 +152,17 @@ void SvgPainter::paintPrimitive(SvgDocument* document, SceneModel* model) const } } -void SvgPainter::paintText(SvgDocument* document, SceneText* model) const +void SvgPainter::paintText(SvgDocument* document, SceneText* text) const { + auto svg_text = std::make_unique(); + svg_text->setContent(text->getTextData().mContent); + svg_text->setLocation(text->getTransform().getLocation()); + svg_text->setFontFamily(text->getTextData().mFont.getFaceName()); + svg_text->setFill(text->getFillColor()); + svg_text->setFontSize(text->getTextData().mFont.getSize()); + + document->getRoot()->addChild(std::move(svg_text)); } std::unique_ptr SvgPainter::toTransform(const Transform& transform) const @@ -149,8 +170,14 @@ std::unique_ptr SvgPainter::toTransform(const Transform& transform auto svg_transform = std::make_unique("transform"); std::string ops; - ops += "translate(" + std::to_string(transform.getLocation().getX()) + " " + std::to_string(transform.getLocation().getY()) + ") "; - ops += "scale(" + std::to_string(transform.getScaleX()) + " " + std::to_string(transform.getScaleY()) + ") "; + if (!transform.hasDefaultLocation()) + { + ops += "translate(" + std::to_string(transform.getLocation().getX()) + " " + std::to_string(transform.getLocation().getY()) + ") "; + } + if (!transform.hasDefaultScale()) + { + ops += "scale(" + std::to_string(transform.getScaleX()) + " " + std::to_string(transform.getScaleY()) + ") "; + } svg_transform->setValue(ops); return std::move(svg_transform); diff --git a/src/rendering/graphics/directx/DirectX2dPainter.cpp b/src/rendering/graphics/directx/DirectX2dPainter.cpp index 07b38fe..9aff9f2 100644 --- a/src/rendering/graphics/directx/DirectX2dPainter.cpp +++ b/src/rendering/graphics/directx/DirectX2dPainter.cpp @@ -34,22 +34,46 @@ void DirectX2dPainter::paint(SceneModel* model) if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE) { + auto rect = dynamic_cast(model->getGeometry()); + const auto loc = model->getTransform().getLocation(); const auto scale_x = model->getTransform().getScaleX(); const auto scale_y = model->getTransform().getScaleY(); - D2D1_RECT_F d2d_rect{ static_cast(loc.getX()), static_cast(loc.getY() + scale_y), static_cast(loc.getX() + scale_x), static_cast(loc.getY()) }; - if (model->hasFillColor()) - { - mSolidBrush->SetColor(toD2dColor(model->getFillColor())); - rt->FillRectangle(d2d_rect, mSolidBrush.Get()); + const auto min_x = static_cast(loc.getX()); + const auto max_x = static_cast(loc.getX() + rect->getWidth()* scale_x); + + const auto min_y = static_cast(loc.getY()); + const auto max_y = static_cast(loc.getY() + rect->getHeight() * scale_y); + + D2D1_RECT_F d2d_rect{ min_x, max_y, max_x, min_y }; + if (rect->getRadius() == 0.0) + { + if (model->hasFillColor()) + { + mSolidBrush->SetColor(toD2dColor(model->getFillColor())); + rt->FillRectangle(d2d_rect, mSolidBrush.Get()); + } + if (model->hasOutlineColor()) + { + mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); + rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f); + } } - - if (model->hasOutlineColor()) + else { - mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); - rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f); - } + D2D1_ROUNDED_RECT rounded_rect{ d2d_rect , static_cast(rect->getRadius()), static_cast(rect->getRadius()) }; + if (model->hasFillColor()) + { + mSolidBrush->SetColor(toD2dColor(model->getFillColor())); + rt->FillRoundedRectangle(rounded_rect, mSolidBrush.Get()); + } + if (model->hasOutlineColor()) + { + mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); + rt->DrawRoundedRectangle(rounded_rect, mSolidBrush.Get(), 1.0f); + } + } } else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::CIRCLE) { diff --git a/src/rendering/graphics/directx/DirectXTextPainter.cpp b/src/rendering/graphics/directx/DirectXTextPainter.cpp index 29e11b8..ebf2980 100644 --- a/src/rendering/graphics/directx/DirectXTextPainter.cpp +++ b/src/rendering/graphics/directx/DirectXTextPainter.cpp @@ -30,28 +30,40 @@ void DirectXTextPainter::setD2dInterface(DirectX2dInterface* d2dIterface) mD2dInterface->getRenderTarget()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mTextBrush); } -void DirectXTextPainter::updateTextFormat(const FontItem& font) +void DirectXTextPainter::updateTextFormat(SceneText* text) { mD2dInterface->getDirectWriteFactory()->CreateTextFormat( - UnicodeUtils::utf8ToUtf16WString(font.getFaceName()).c_str(), + UnicodeUtils::utf8ToUtf16WString(text->getTextData().mFont.getFaceName()).c_str(), nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, - static_cast(font.getSize()), + static_cast(text->getTextData().mFont.getSize()), L"en-us", &mTextFormat ); - //mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); - //mTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); + mTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_CENTER); + + mTextBrush->SetColor(toD2dColor(text->getFillColor())); +} + +D2D1::ColorF DirectXTextPainter::toD2dColor(const Color& color) +{ + return D2D1::ColorF(static_cast(color.getR() / 255.0), static_cast(color.getG() / 255.0), + static_cast(color.getB() / 255.0), static_cast(color.getAlpha())); } void DirectXTextPainter::paint(SceneText* text, DrawingContext* context) { const auto location = text->getTransform().getLocation(); - D2D1_RECT_F textRect = D2D1::RectF(static_cast(location.getX()), static_cast(location.getY()), static_cast(location.getX() + 200), static_cast(location.getY() + 100)); - updateTextFormat(text->getTextData().mFont); + const auto width = static_cast(text->getTextWidth()); + const auto height = static_cast(text->getTextHeight()); + + D2D1_RECT_F textRect = D2D1::RectF(static_cast(location.getX()), static_cast(location.getY()), static_cast(location.getX() + width), static_cast(location.getY() + height)); + + updateTextFormat(text); auto content = UnicodeUtils::utf8ToUtf16WString(text->getTextData().mContent); diff --git a/src/rendering/graphics/directx/DirectXTextPainter.h b/src/rendering/graphics/directx/DirectXTextPainter.h index ffeb031..99418c4 100644 --- a/src/rendering/graphics/directx/DirectXTextPainter.h +++ b/src/rendering/graphics/directx/DirectXTextPainter.h @@ -1,6 +1,7 @@ #pragma once #include "FontItem.h" +#include "Color.h" #include #include @@ -32,7 +33,9 @@ public: void setD2dInterface(DirectX2dInterface* d2dIterface); private: - void updateTextFormat(const FontItem& font); + void updateTextFormat(SceneText* text); + + D2D1::ColorF toD2dColor(const Color& color); DirectX2dInterface* mD2dInterface{ nullptr }; Microsoft::WRL::ComPtr mTextBrush; diff --git a/src/rendering/visual_elements/CMakeLists.txt b/src/rendering/visual_elements/CMakeLists.txt index 3522bbe..8e42e6b 100644 --- a/src/rendering/visual_elements/CMakeLists.txt +++ b/src/rendering/visual_elements/CMakeLists.txt @@ -23,6 +23,8 @@ list(APPEND visual_elements_LIB_INCLUDES svg/SvgReader.h svg/SvgShapeElement.h svg/SvgElement.h + svg/SvgTextElement.h + svg/SvgTextElement.cpp svg/elements/SvgShapeElements.h svg/SvgDocument.cpp svg/SvgReader.cpp diff --git a/src/rendering/visual_elements/basic_shapes/RectangleNode.cpp b/src/rendering/visual_elements/basic_shapes/RectangleNode.cpp index 8670c50..a9e8f85 100644 --- a/src/rendering/visual_elements/basic_shapes/RectangleNode.cpp +++ b/src/rendering/visual_elements/basic_shapes/RectangleNode.cpp @@ -42,7 +42,7 @@ void RectangleNode::setWidth(double width) { if (mWidth != width) { - mTransformIsDirty = true; + mGeometryIsDirty = true; mWidth = width; } } @@ -51,7 +51,7 @@ void RectangleNode::setHeight(double height) { if (mHeight != height) { - mTransformIsDirty = true; + mGeometryIsDirty = true; mHeight = height; } } @@ -71,7 +71,7 @@ void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo) { if (sceneInfo->mSupportsGeometryPrimitives) { - auto rect = std::make_unique(Point{ 0, 0 }, 1, 1); + auto rect = std::make_unique(Point{ 0, 0 }, mWidth, mHeight); rect->setRadius(mRadius); mBackgroundItem = std::make_unique(std::move(rect)); } @@ -87,7 +87,7 @@ void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo) { if (sceneInfo->mSupportsGeometryPrimitives) { - auto rect = std::make_unique(Point{ 0, 0 }, 1, 1); + auto rect = std::make_unique(Point{ 0, 0 }, mWidth, mHeight); rect->setRadius(mRadius); mBackgroundItem->updateGeometry(std::move(rect)); } @@ -96,5 +96,5 @@ void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo) void RectangleNode::updateTransform() { - mBackgroundItem->updateTransform({ mLocation, mWidth, mHeight }); + mBackgroundItem->updateTransform({ mLocation }); } \ No newline at end of file diff --git a/src/rendering/visual_elements/nodes/TextNode.cpp b/src/rendering/visual_elements/nodes/TextNode.cpp index 362e286..56a7d83 100644 --- a/src/rendering/visual_elements/nodes/TextNode.cpp +++ b/src/rendering/visual_elements/nodes/TextNode.cpp @@ -161,7 +161,7 @@ void TextNode::update(SceneInfo* sceneInfo) if (mContentIsDirty || mLinesAreDirty) { - dynamic_cast(mTextItem.get())->setTextData(mTextData); + mTextItem->setTextData(mTextData); mContentIsDirty = false; mLinesAreDirty = false; } @@ -169,6 +169,8 @@ void TextNode::update(SceneInfo* sceneInfo) if (mTransformIsDirty) { mTextItem->updateTransform({mLocation}); + mTextItem->setTextWidth(mWidth); + mTextItem->setTextHeight(mHeight); mTransformIsDirty = false; } diff --git a/src/rendering/visual_elements/nodes/TextNode.h b/src/rendering/visual_elements/nodes/TextNode.h index ae5941d..42e7da9 100644 --- a/src/rendering/visual_elements/nodes/TextNode.h +++ b/src/rendering/visual_elements/nodes/TextNode.h @@ -4,6 +4,8 @@ #include "FontItem.h" #include "TextData.h" +#include "Bounds.h" +#include "SceneText.h" #include #include @@ -47,7 +49,7 @@ private: double mWidth{1}; double mHeight{1}; - std::unique_ptr mTextItem; + std::unique_ptr mTextItem; }; using TextNodetr = std::unique_ptr; diff --git a/src/rendering/visual_elements/scene/SceneText.cpp b/src/rendering/visual_elements/scene/SceneText.cpp index 5ab4822..bea0558 100644 --- a/src/rendering/visual_elements/scene/SceneText.cpp +++ b/src/rendering/visual_elements/scene/SceneText.cpp @@ -23,3 +23,31 @@ void SceneText::setTextData(const TextData& data) mTextData = data; } } + +double SceneText::getTextWidth() const +{ + return mTextWidth; +} + +double SceneText::getTextHeight() const +{ + return mTextHeight; +} + +void SceneText::setTextWidth(double width) +{ + if (mTextWidth != width) + { + mTextWidth = width; + mTextGeometryIsDirty = true; + } +} + +void SceneText::setTextHeight(double height) +{ + if (mTextHeight != height) + { + mTextHeight = height; + mTextGeometryIsDirty = true; + } +} diff --git a/src/rendering/visual_elements/scene/SceneText.h b/src/rendering/visual_elements/scene/SceneText.h index 59ec840..72de1c2 100644 --- a/src/rendering/visual_elements/scene/SceneText.h +++ b/src/rendering/visual_elements/scene/SceneText.h @@ -10,11 +10,21 @@ public: Type getType() const override; + double getTextWidth() const; + + double getTextHeight() const; + const TextData& getTextData() const; + void setTextWidth(double width); + + void setTextHeight(double height); + void setTextData(const TextData& content); private: bool mTextGeometryIsDirty{true}; TextData mTextData; + double mTextWidth{ 0.0 }; + double mTextHeight{ 0.0 }; }; diff --git a/src/rendering/visual_elements/svg/SvgTextElement.cpp b/src/rendering/visual_elements/svg/SvgTextElement.cpp new file mode 100644 index 0000000..4b463c2 --- /dev/null +++ b/src/rendering/visual_elements/svg/SvgTextElement.cpp @@ -0,0 +1,53 @@ +#include "SvgTextElement.h" + +#include "XmlAttribute.h" + +#include + +SvgTextElement::SvgTextElement() + :SvgElement("text") +{ + +} + +void SvgTextElement::setLocation(const Point& loc) +{ + auto x = std::make_unique("x"); + auto y = std::make_unique("y"); + + x->setValue(std::to_string(loc.getX())); + y->setValue(std::to_string(loc.getY())); + + addAttribute(std::move(x)); + addAttribute(std::move(y)); +} + +void SvgTextElement::setContent(const std::string& content) +{ + setText(content); +} + +void SvgTextElement::setFill(const Color& fill) +{ + auto attr = std::make_unique("fill"); + + std::stringstream sstr; + sstr << "rgb(" << fill.toString() << ")"; + attr->setValue(sstr.str()); + + addAttribute(std::move(attr)); +} + +void SvgTextElement::setFontFamily(const std::string& family) +{ + auto attr = std::make_unique("font-family"); + attr->setValue(family); + addAttribute(std::move(attr)); +} + +void SvgTextElement::setFontSize(float size) +{ + auto attr = std::make_unique("font-size"); + attr->setValue(std::to_string(size)); + addAttribute(std::move(attr)); +} \ No newline at end of file diff --git a/src/rendering/visual_elements/svg/SvgTextElement.h b/src/rendering/visual_elements/svg/SvgTextElement.h new file mode 100644 index 0000000..d988b2b --- /dev/null +++ b/src/rendering/visual_elements/svg/SvgTextElement.h @@ -0,0 +1,21 @@ +#pragma once + +#include "SvgElement.h" +#include "Point.h" +#include "Color.h" + +class SvgTextElement : public SvgElement +{ +public: + SvgTextElement(); + + void setLocation(const Point& loc); + + void setContent(const std::string& content); + + void setFill(const Color& fill); + + void setFontFamily(const std::string& family); + + void setFontSize(float size); +}; \ No newline at end of file diff --git a/src/rendering/visual_elements/svg/elements/SvgShapeElements.cpp b/src/rendering/visual_elements/svg/elements/SvgShapeElements.cpp index 40ca60d..db90bf5 100644 --- a/src/rendering/visual_elements/svg/elements/SvgShapeElements.cpp +++ b/src/rendering/visual_elements/svg/elements/SvgShapeElements.cpp @@ -124,6 +124,15 @@ void SvgRectangle::setHeight(double h) addAttribute(std::move(height)); } +void SvgRectangle::setRadius(double radius) +{ + auto rx = std::make_unique("rx"); + + rx->setValue(std::to_string(radius)); + + addAttribute(std::move(rx)); +} + SvgPolygon::SvgPolygon() : SvgShapeElement("polygon") diff --git a/src/rendering/visual_elements/svg/elements/SvgShapeElements.h b/src/rendering/visual_elements/svg/elements/SvgShapeElements.h index eb374b8..f529bca 100644 --- a/src/rendering/visual_elements/svg/elements/SvgShapeElements.h +++ b/src/rendering/visual_elements/svg/elements/SvgShapeElements.h @@ -43,6 +43,8 @@ public: void setWidth(double width); void setHeight(double height); + + void setRadius(double radius); }; class SvgPolygon : public SvgShapeElement diff --git a/src/ui/ui_controls/Button.cpp b/src/ui/ui_controls/Button.cpp index 83beacc..ac41981 100644 --- a/src/ui/ui_controls/Button.cpp +++ b/src/ui/ui_controls/Button.cpp @@ -6,6 +6,8 @@ #include "ThemeManager.h" #include "PaintEvent.h" +#include "FontTokens.h" + #include "MouseEvent.h" #include "FileLogger.h" @@ -16,6 +18,10 @@ Button::Button(ButtonData::Component component) { mStyle.mComponent = component; mName = "Button"; + + setHeight(mStyle.getContainerHeight()); + setMaxHeight(mStyle.getContainerHeight()); + setRadius(mStyle.getContainerCornerRadius()); } Button::~Button() @@ -66,7 +72,39 @@ void Button::setEnabled(bool isEnabled) void Button::updateState() { setBackground(mStyle.getContainerColor()); + setBackgroundTone(mStyle.getContainerSurfaceTintColor()); + setElevation(mStyle.getContainerElevation()); + setLabelTextColor(mStyle.getLabelTextColor()); + setLabelTextOpacity(mStyle.getLabelOpacity()); + setLabelTextTypescale(mStyle.getLabelTypescale()); +} + +void Button::setLabelTextColor(Theme::Sys::Color color) +{ + if (mLabelTextColor != color) + { + mLabelTextColor = color; + mMaterialDirty = true; + } +} + +void Button::setLabelTextOpacity(float opacity) +{ + if (mLabelOpacity != opacity) + { + mLabelOpacity = opacity; + mMaterialDirty = true; + } +} + +void Button::setLabelTextTypescale(Theme::Sys::Typescale typescale) +{ + if (mLabelTextTypescale != typescale) + { + mLabelTextTypescale = typescale; + mMaterialDirty = true; + } } void Button::onMyMouseEvent(const MouseEvent* event) @@ -131,29 +169,31 @@ void Button::doPaint(const PaintEvent* event) void Button::updateLabel(const PaintEvent* event) { - unsigned fontOffset = unsigned(mLabel.size()) * 4; - auto middle = DiscretePoint(mLocation.getX() + mSize.mWidth/2 - fontOffset, mLocation.getY() + mSize.mHeight/2 + 4); - if (!mTextNode) { - mTextNode = TextNode::Create(mLabel, middle); + mTextNode = TextNode::Create(mLabel, mLocation); mTextNode->setName(mName + "_TextNode"); mTextNode->setContent(mLabel); - mTextNode->setWidth(mSize.mWidth); - mTextNode->setHeight(mSize.mHeight); mRootNode->addChild(mTextNode.get()); } if (mTransformDirty) { - mTextNode->setLocation(middle); + mTextNode->setLocation(mLocation); mTextNode->setWidth(mSize.mWidth); mTextNode->setHeight(mSize.mHeight); } if (mMaterialDirty) { - mTextNode->setFillColor(event->getThemesManager()->getColor(mBackground)); + auto fill_color = event->getThemesManager()->getColor(mLabelTextColor); + fill_color.setAlpha(mLabelOpacity); + mTextNode->setFillColor(fill_color); + + auto size = FontTokens::getSize(mLabelTextTypescale); + auto family = FontTokens::getFont(FontTokens::getFont(mLabelTextTypescale)); + auto font_data = FontItem(family, static_cast(size)); + mTextNode->setFont(font_data); } if (mContentDirty) diff --git a/src/ui/ui_controls/Button.h b/src/ui/ui_controls/Button.h index 7b90e57..2bd6049 100644 --- a/src/ui/ui_controls/Button.h +++ b/src/ui/ui_controls/Button.h @@ -34,6 +34,10 @@ protected: bool isDirty() const override; void doPaint(const PaintEvent* event) override; + void setLabelTextColor(Theme::Sys::Color color); + void setLabelTextOpacity(float opacity); + void setLabelTextTypescale(Theme::Sys::Typescale typescale); + void updateLabel(const PaintEvent* event); void setState(ButtonData::State state); @@ -44,6 +48,10 @@ private: ButtonData mStyle; std::string mLabel; + Theme::Sys::Color mLabelTextColor; + Theme::Sys::Typescale mLabelTextTypescale; + float mLabelOpacity{ 1.0 }; + clickFunc mClickFunc; std::unique_ptr mTextNode; diff --git a/src/ui/ui_controls/ButtonData.cpp b/src/ui/ui_controls/ButtonData.cpp index fd57a89..130ae01 100644 --- a/src/ui/ui_controls/ButtonData.cpp +++ b/src/ui/ui_controls/ButtonData.cpp @@ -218,6 +218,29 @@ float ButtonData::getStateLayerOverlayOpacity() const } } +float ButtonData::getLabelOpacity() const +{ + if (auto iter = mLabelTextOpacity.find(std::make_pair(mComponent, mState)); iter != mLabelTextOpacity.end()) + { + return iter->second; + } + else + { + if (mState == State::Enabled) + { + return DEFAULT_CONTAINER_OPACITY; + } + else if (auto iter = mLabelTextOpacity.find(std::make_pair(mComponent, State::Enabled)); iter != mLabelTextOpacity.end()) + { + return iter->second; + } + else + { + return DEFAULT_CONTAINER_OPACITY; + } + } +} + Theme::Sys::Typescale ButtonData::getLabelTypescale() const { switch (mComponent) diff --git a/src/ui/ui_controls/ButtonData.h b/src/ui/ui_controls/ButtonData.h index f9cafbd..132e209 100644 --- a/src/ui/ui_controls/ButtonData.h +++ b/src/ui/ui_controls/ButtonData.h @@ -40,20 +40,21 @@ public: Theme::Sys::Color getContainerShadowColor() const; Theme::Sys::Color getContainerSurfaceTintColor() const; Theme::Sys::Elevation getContainerElevation() const; + float getStateLayerOverlayOpacity() const; Theme::Sys::Color getLabelTextColor() const; Theme::Sys::Typescale getLabelTypescale() const; + float getLabelOpacity() const; bool canHaveIcon() const; Theme::Sys::Color getIconColor() const; - float getStateLayerOverlayOpacity() const; unsigned getContainerHeight() const; unsigned getContainerCornerRadius() const; unsigned getIconSize() const; - unsigned getLeftRightPadding() const; + unsigned getLeftRightPadding() const; unsigned getLeftPaddingWithIcon() const; unsigned getRightPaddingWithIcon() const; diff --git a/src/ui/ui_elements/style/FontTokens.cpp b/src/ui/ui_elements/style/FontTokens.cpp index e69de29..57a0651 100644 --- a/src/ui/ui_elements/style/FontTokens.cpp +++ b/src/ui/ui_elements/style/FontTokens.cpp @@ -0,0 +1,64 @@ +#include "FontTokens.h" + + + +std::string FontTokens::getFont(Theme::Ref::Typeface::Font font) +{ + switch (font) + { + case Theme::Ref::Typeface::Font::Brand: + return "Segoe UI"; + case Theme::Ref::Typeface::Font::Plain: + return "Segoe UI"; + default: + return "Segoe UI"; + } +} + +Theme::Ref::Typeface::Font FontTokens::getFont(Theme::Sys::Typescale typescale) +{ + switch (typescale) + { + case Theme::Sys::Typescale::Label_Large: + return Theme::Ref::Typeface::Font::Brand; + default: + return Theme::Ref::Typeface::Font::Brand; + } +} + +unsigned FontTokens::getLineHeight(Theme::Sys::Typescale typescale) +{ + switch (typescale) + { + case Theme::Sys::Typescale::Label_Large: + return 67; + default: + return 67; + } +} + +unsigned FontTokens::getSize(Theme::Sys::Typescale typescale) +{ + switch (typescale) + { + case Theme::Sys::Typescale::Label_Large: + return static_cast(57/3); + default: + return 57; + } +} + +unsigned FontTokens::getTracking(Theme::Sys::Typescale typescale) +{ + return 0; +} + +unsigned FontTokens::getWeight(Theme::Ref::Typeface::Font font) +{ + return 0; +} + +Theme::Ref::Typeface::Font FontTokens::getWeight(Theme::Sys::Typescale typescale) +{ + return Theme::Ref::Typeface::Font::Brand; +} \ No newline at end of file diff --git a/src/ui/ui_elements/style/FontTokens.h b/src/ui/ui_elements/style/FontTokens.h index 9102372..8b04423 100644 --- a/src/ui/ui_elements/style/FontTokens.h +++ b/src/ui/ui_elements/style/FontTokens.h @@ -51,6 +51,7 @@ namespace Theme class FontTokens { +public: static std::string getFont(Theme::Ref::Typeface::Font font); static Theme::Ref::Typeface::Font getFont(Theme::Sys::Typescale typescale); diff --git a/src/ui/ui_elements/widgets/BoxGeometry.cpp b/src/ui/ui_elements/widgets/BoxGeometry.cpp index e60c26a..a8e96cc 100644 --- a/src/ui/ui_elements/widgets/BoxGeometry.cpp +++ b/src/ui/ui_elements/widgets/BoxGeometry.cpp @@ -77,6 +77,25 @@ void BoxGeometry::setBounds(unsigned width, unsigned height) } } +void BoxGeometry::setWidth(unsigned width) +{ + setBounds(width, mSize.mHeight); +} + +void BoxGeometry::setHeight(unsigned height) +{ + setBounds(mSize.mWidth, height); +} + +void BoxGeometry::setMaxHeight(unsigned maxHieght) +{ + if (mSize.mMaxHeight != maxHieght) + { + mTransformDirty = true; + mSize.mMaxHeight = maxHieght; + } +} + void BoxGeometry::setLocation(const DiscretePoint& loc) { if (mLocation != loc) diff --git a/src/ui/ui_elements/widgets/BoxGeometry.h b/src/ui/ui_elements/widgets/BoxGeometry.h index d8c47ae..df920eb 100644 --- a/src/ui/ui_elements/widgets/BoxGeometry.h +++ b/src/ui/ui_elements/widgets/BoxGeometry.h @@ -59,6 +59,12 @@ public: const DiscretePoint& getLocation() const; + void setWidth(unsigned width); + + void setHeight(unsigned height); + + void setMaxHeight(unsigned maxHieght); + void setBounds(unsigned width, unsigned height); void setSize(const BoundedSize& size); diff --git a/src/ui/ui_elements/widgets/Widget.cpp b/src/ui/ui_elements/widgets/Widget.cpp index f2d9a1c..89b619d 100644 --- a/src/ui/ui_elements/widgets/Widget.cpp +++ b/src/ui/ui_elements/widgets/Widget.cpp @@ -16,7 +16,6 @@ #include #include -#include Widget::Widget() : BoxGeometry(), @@ -73,6 +72,24 @@ void Widget::setBackground(Theme::Sys::Color token) } } +void Widget::setBackgroundTone(Theme::Sys::Color token) +{ + if (mBackgroundTone != token) + { + mBackgroundTone = token; + mMaterialDirty = true; + } +} + +void Widget::setElevation(Theme::Sys::Elevation elevation) +{ + if (mElevation != elevation) + { + mElevation = elevation; + mMaterialDirty = true; + } +} + void Widget::setBackgroundOpacity(float opacity) { if (mBackgroundOpacity != opacity) @@ -173,6 +190,9 @@ void Widget::onPaintEvent(const PaintEvent* event) } doPaint(event); + mGeometryDirty = false; + mMaterialDirty = false; + mTransformDirty = false; if (mVisibilityDirty) { @@ -293,32 +313,30 @@ void Widget::onMyMouseEvent(const MouseEvent* event) void Widget::createOrUpdateGeometry() { + const auto deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight; + const auto deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom; if (!mBackgroundNode) { - unsigned locX = mLocation.getX() + mMargin.mLeft; - unsigned locY = mLocation.getY() + mMargin.mTop; - unsigned deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight; - unsigned deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom; - + const auto locX = mLocation.getX() + mMargin.mLeft; + const auto locY = mLocation.getY() + mMargin.mTop; mBackgroundNode = std::make_unique(DiscretePoint(locX, locY), deltaX, deltaY); + mBackgroundNode->setRadius(mRadius); + mBackgroundNode->setName(mName + "_BackgroundNode"); mRootNode->addChild(mBackgroundNode.get()); } else { + mBackgroundNode->setWidth(deltaX); + mBackgroundNode->setHeight(deltaY); mBackgroundNode->setRadius(mRadius); } } void Widget::updateTransform() { - unsigned locX = mLocation.getX() + mMargin.mLeft; - unsigned locY = mLocation.getY() + mMargin.mTop; - unsigned deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight; - unsigned deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom; - - mBackgroundNode->setWidth(deltaX); - mBackgroundNode->setHeight(deltaY); + const auto locX = mLocation.getX() + mMargin.mLeft; + const auto locY = mLocation.getY() + mMargin.mTop; mBackgroundNode->setLocation(DiscretePoint(locX, locY)); } @@ -326,9 +344,16 @@ void Widget::updateMaterial(const PaintEvent* event) { if (mBackground != Theme::Sys::Color::None) { - auto background_color = event->getThemesManager()->getColor(mBackground); - background_color.setAlpha(mBackgroundOpacity); - mBackgroundNode->setFillColor(background_color); + //if (mBackgroundTone == Theme::Sys::Color::None || mElevation == Theme::Sys::Elevation::Level_0) + //{ + auto background_color = event->getThemesManager()->getColor(mBackground); + background_color.setAlpha(mBackgroundOpacity); + mBackgroundNode->setFillColor(background_color); + //} + //else + //{ + //event->getThemesManager()->getColor(mBackground); + //} } else { @@ -348,22 +373,14 @@ void Widget::updateMaterial(const PaintEvent* event) void Widget::updateBackground(const PaintEvent* event) { - unsigned locX = mLocation.getX() + mMargin.mLeft; - unsigned locY = mLocation.getY() + mMargin.mTop; - unsigned deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight; - unsigned deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom; - - if (!mBackgroundNode) + if (mGeometryDirty) { - mBackgroundNode = std::make_unique(DiscretePoint(locX, locY), deltaX, deltaY); - mBackgroundNode->setName(mName + "_BackgroundNode"); - mRootNode->addChild(mBackgroundNode.get()); + createOrUpdateGeometry(); } if (mTransformDirty) { updateTransform(); - mTransformDirty = false; } if (mMaterialDirty) diff --git a/src/ui/ui_elements/widgets/Widget.h b/src/ui/ui_elements/widgets/Widget.h index 20336df..3c8c234 100644 --- a/src/ui/ui_elements/widgets/Widget.h +++ b/src/ui/ui_elements/widgets/Widget.h @@ -1,11 +1,13 @@ #pragma once #include "FontItem.h" -#include "ITheme.h" #include "WidgetState.h" #include "BoxGeometry.h" #include "TransformNode.h" +#include "ITheme.h" +#include "ElevationTokens.h" + #include #include #include @@ -55,6 +57,10 @@ public: void setBackground(Theme::Sys::Color token); + void setBackgroundTone(Theme::Sys::Color token); + + void setElevation(Theme::Sys::Elevation elevation); + void setOutlineThickness(double thickness); void setOutline(Theme::Sys::Color token); @@ -102,7 +108,9 @@ protected: Theme::Sys::Color mBorder; double mBorderThickness{0}; + Theme::Sys::Color mBackgroundTone; Theme::Sys::Color mBackground; + Theme::Sys::Elevation mElevation{ Theme::Sys::Elevation::Level_0 }; float mBackgroundOpacity{ 1.0 }; bool mVisible{true}; diff --git a/test/ui_controls/TestButton.cpp b/test/ui_controls/TestButton.cpp index a60c3bc..a110ae2 100644 --- a/test/ui_controls/TestButton.cpp +++ b/test/ui_controls/TestButton.cpp @@ -5,25 +5,37 @@ #include "ThemeManager.h" #include "PaintEvent.h" +#include "VerticalSpacer.h" + #include "Button.h" TEST_CASE(TestButton_Elevated, "ui_controls") { auto theme_manager = std::make_unique(); - auto paint_event = PaintEvent::Create(theme_manager.get(), nullptr); + VerticalSpacer spacer; + spacer.setWidth(300); + spacer.setHeight(200); - Button button(ButtonData::Component::Elevated); - button.setLabel("Enabled"); + auto enabled_button = Button::Create(ButtonData::Component::Elevated); + enabled_button->setLabel("Enabled"); - button.onPaintEvent(paint_event.get()); + auto disabled_button = Button::Create(ButtonData::Component::Elevated); + disabled_button->setEnabled(false); + disabled_button->setLabel("Disabled"); - auto node = button.getRootNode(); + spacer.addWidget(std::move(enabled_button)); + spacer.addWidget(std::move(disabled_button)); + + auto node = spacer.getRootNode(); TestRenderer renderer; renderer.getScene()->addNode(node); - renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "Elevated_Enabled.svg"); - renderer.write(TestUtils::getTestOutputDir(__FILE__) / "Elevated_Enabled.png"); + auto paint_event = PaintEvent::Create(theme_manager.get(), nullptr); + spacer.onPaintEvent(paint_event.get()); + + renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "Elevated.svg"); + renderer.write(TestUtils::getTestOutputDir(__FILE__) / "Elevated.png"); };