Update text rendering.

This commit is contained in:
jmsgrogan 2023-01-18 17:31:16 +00:00
parent 8536908eab
commit 8130308f7f
27 changed files with 503 additions and 77 deletions

View file

@ -2,7 +2,7 @@
struct Bounds 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), : mMinX(minX),
mMaxX(maxX), mMaxX(maxX),
mMinY(minY), mMinY(minY),
@ -60,4 +60,21 @@ struct Bounds
mMaxZ = z; 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);
}
}; };

View file

@ -31,6 +31,21 @@ public:
return !operator==(rhs); 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: private:
Point mLocation; Point mLocation;
double mScaleX{1}; double mScaleX{1};

View file

@ -13,8 +13,10 @@
#include "AbstractFace.h" #include "AbstractFace.h"
#include "Circle.h" #include "Circle.h"
#include "Rectangle.h"
#include "SvgShapeElements.h" #include "SvgShapeElements.h"
#include "SvgTextElement.h"
#include "XmlAttribute.h" #include "XmlAttribute.h"
std::unique_ptr<SvgDocument> SvgPainter::paint(Scene* scene, double width, double height) const std::unique_ptr<SvgDocument> SvgPainter::paint(Scene* scene, double width, double height) const
@ -102,22 +104,33 @@ void SvgPainter::setStyle(SceneModel* model, SvgShapeElement* element) const
if (model->hasOutlineColor()) if (model->hasOutlineColor())
{ {
element->setStrokeColor(model->getOutlineColor()); element->setStrokeColor(model->getOutlineColor());
element->setStrokeWidth(model->getOutlineThickness() / transform.getScaleX()); element->setStrokeWidth(model->getOutlineThickness());
} }
else else
{ {
element->setNoStroke(); element->setNoStroke();
} }
if (!transform.isDefaultTransform())
{
element->addAttribute(std::move(toTransform(transform))); element->addAttribute(std::move(toTransform(transform)));
}
} }
void SvgPainter::paintPrimitive(SvgDocument* document, SceneModel* model) const void SvgPainter::paintPrimitive(SvgDocument* document, SceneModel* model) const
{ {
if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE) if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE)
{ {
auto model_rect = dynamic_cast<ntk::Rectangle*>(model->getGeometry());
auto rect = std::make_unique<SvgRectangle>(); auto rect = std::make_unique<SvgRectangle>();
rect->setWidth(1.0); rect->setWidth(model_rect->getWidth());
rect->setHeight(1.0); rect->setHeight(model_rect->getHeight());
if (model_rect->getRadius() > 0.0)
{
rect->setRadius(model_rect->getRadius());
}
setStyle(model, rect.get()); setStyle(model, rect.get());
document->getRoot()->addChild(std::move(rect)); 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<SvgTextElement>();
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<XmlAttribute> SvgPainter::toTransform(const Transform& transform) const std::unique_ptr<XmlAttribute> SvgPainter::toTransform(const Transform& transform) const
@ -149,8 +170,14 @@ std::unique_ptr<XmlAttribute> SvgPainter::toTransform(const Transform& transform
auto svg_transform = std::make_unique<XmlAttribute>("transform"); auto svg_transform = std::make_unique<XmlAttribute>("transform");
std::string ops; std::string ops;
if (!transform.hasDefaultLocation())
{
ops += "translate(" + std::to_string(transform.getLocation().getX()) + " " + std::to_string(transform.getLocation().getY()) + ") "; 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()) + ") "; ops += "scale(" + std::to_string(transform.getScaleX()) + " " + std::to_string(transform.getScaleY()) + ") ";
}
svg_transform->setValue(ops); svg_transform->setValue(ops);
return std::move(svg_transform); return std::move(svg_transform);

View file

@ -34,23 +34,47 @@ void DirectX2dPainter::paint(SceneModel* model)
if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE) if (model->getGeometry()->getType() == AbstractGeometricItem::Type::RECTANGLE)
{ {
auto rect = dynamic_cast<ntk::Rectangle*>(model->getGeometry());
const auto loc = model->getTransform().getLocation(); const auto loc = model->getTransform().getLocation();
const auto scale_x = model->getTransform().getScaleX(); const auto scale_x = model->getTransform().getScaleX();
const auto scale_y = model->getTransform().getScaleY(); const auto scale_y = model->getTransform().getScaleY();
D2D1_RECT_F d2d_rect{ static_cast<float>(loc.getX()), static_cast<float>(loc.getY() + scale_y), static_cast<float>(loc.getX() + scale_x), static_cast<float>(loc.getY()) };
const auto min_x = static_cast<float>(loc.getX());
const auto max_x = static_cast<float>(loc.getX() + rect->getWidth()* scale_x);
const auto min_y = static_cast<float>(loc.getY());
const auto max_y = static_cast<float>(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()) if (model->hasFillColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getFillColor())); mSolidBrush->SetColor(toD2dColor(model->getFillColor()));
rt->FillRectangle(d2d_rect, mSolidBrush.Get()); rt->FillRectangle(d2d_rect, mSolidBrush.Get());
} }
if (model->hasOutlineColor()) if (model->hasOutlineColor())
{ {
mSolidBrush->SetColor(toD2dColor(model->getOutlineColor())); mSolidBrush->SetColor(toD2dColor(model->getOutlineColor()));
rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f); rt->DrawRectangle(d2d_rect, mSolidBrush.Get(), 1.0f);
} }
} }
else
{
D2D1_ROUNDED_RECT rounded_rect{ d2d_rect , static_cast<float>(rect->getRadius()), static_cast<float>(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) else if (model->getGeometry()->getType() == AbstractGeometricItem::Type::CIRCLE)
{ {
const auto loc = model->getTransform().getLocation(); const auto loc = model->getTransform().getLocation();

View file

@ -30,28 +30,40 @@ void DirectXTextPainter::setD2dInterface(DirectX2dInterface* d2dIterface)
mD2dInterface->getRenderTarget()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mTextBrush); mD2dInterface->getRenderTarget()->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &mTextBrush);
} }
void DirectXTextPainter::updateTextFormat(const FontItem& font) void DirectXTextPainter::updateTextFormat(SceneText* text)
{ {
mD2dInterface->getDirectWriteFactory()->CreateTextFormat( mD2dInterface->getDirectWriteFactory()->CreateTextFormat(
UnicodeUtils::utf8ToUtf16WString(font.getFaceName()).c_str(), UnicodeUtils::utf8ToUtf16WString(text->getTextData().mFont.getFaceName()).c_str(),
nullptr, nullptr,
DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
static_cast<float>(font.getSize()), static_cast<float>(text->getTextData().mFont.getSize()),
L"en-us", L"en-us",
&mTextFormat &mTextFormat
); );
//mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER); mTextFormat->SetTextAlignment(DWRITE_TEXT_ALIGNMENT_CENTER);
//mTextFormat->SetParagraphAlignment(DWRITE_PARAGRAPH_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<float>(color.getR() / 255.0), static_cast<float>(color.getG() / 255.0),
static_cast<float>(color.getB() / 255.0), static_cast<float>(color.getAlpha()));
} }
void DirectXTextPainter::paint(SceneText* text, DrawingContext* context) void DirectXTextPainter::paint(SceneText* text, DrawingContext* context)
{ {
const auto location = text->getTransform().getLocation(); const auto location = text->getTransform().getLocation();
D2D1_RECT_F textRect = D2D1::RectF(static_cast<float>(location.getX()), static_cast<float>(location.getY()), static_cast<float>(location.getX() + 200), static_cast<float>(location.getY() + 100));
updateTextFormat(text->getTextData().mFont); const auto width = static_cast<float>(text->getTextWidth());
const auto height = static_cast<float>(text->getTextHeight());
D2D1_RECT_F textRect = D2D1::RectF(static_cast<float>(location.getX()), static_cast<float>(location.getY()), static_cast<float>(location.getX() + width), static_cast<float>(location.getY() + height));
updateTextFormat(text);
auto content = UnicodeUtils::utf8ToUtf16WString(text->getTextData().mContent); auto content = UnicodeUtils::utf8ToUtf16WString(text->getTextData().mContent);

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "FontItem.h" #include "FontItem.h"
#include "Color.h"
#include <wrl.h> #include <wrl.h>
#include <dwrite.h> #include <dwrite.h>
@ -32,7 +33,9 @@ public:
void setD2dInterface(DirectX2dInterface* d2dIterface); void setD2dInterface(DirectX2dInterface* d2dIterface);
private: private:
void updateTextFormat(const FontItem& font); void updateTextFormat(SceneText* text);
D2D1::ColorF toD2dColor(const Color& color);
DirectX2dInterface* mD2dInterface{ nullptr }; DirectX2dInterface* mD2dInterface{ nullptr };
Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mTextBrush; Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> mTextBrush;

View file

@ -23,6 +23,8 @@ list(APPEND visual_elements_LIB_INCLUDES
svg/SvgReader.h svg/SvgReader.h
svg/SvgShapeElement.h svg/SvgShapeElement.h
svg/SvgElement.h svg/SvgElement.h
svg/SvgTextElement.h
svg/SvgTextElement.cpp
svg/elements/SvgShapeElements.h svg/elements/SvgShapeElements.h
svg/SvgDocument.cpp svg/SvgDocument.cpp
svg/SvgReader.cpp svg/SvgReader.cpp

View file

@ -42,7 +42,7 @@ void RectangleNode::setWidth(double width)
{ {
if (mWidth != width) if (mWidth != width)
{ {
mTransformIsDirty = true; mGeometryIsDirty = true;
mWidth = width; mWidth = width;
} }
} }
@ -51,7 +51,7 @@ void RectangleNode::setHeight(double height)
{ {
if (mHeight != height) if (mHeight != height)
{ {
mTransformIsDirty = true; mGeometryIsDirty = true;
mHeight = height; mHeight = height;
} }
} }
@ -71,7 +71,7 @@ void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
{ {
if (sceneInfo->mSupportsGeometryPrimitives) if (sceneInfo->mSupportsGeometryPrimitives)
{ {
auto rect = std::make_unique<ntk::Rectangle>(Point{ 0, 0 }, 1, 1); auto rect = std::make_unique<ntk::Rectangle>(Point{ 0, 0 }, mWidth, mHeight);
rect->setRadius(mRadius); rect->setRadius(mRadius);
mBackgroundItem = std::make_unique<SceneModel>(std::move(rect)); mBackgroundItem = std::make_unique<SceneModel>(std::move(rect));
} }
@ -87,7 +87,7 @@ void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
{ {
if (sceneInfo->mSupportsGeometryPrimitives) if (sceneInfo->mSupportsGeometryPrimitives)
{ {
auto rect = std::make_unique<ntk::Rectangle>(Point{ 0, 0 }, 1, 1); auto rect = std::make_unique<ntk::Rectangle>(Point{ 0, 0 }, mWidth, mHeight);
rect->setRadius(mRadius); rect->setRadius(mRadius);
mBackgroundItem->updateGeometry(std::move(rect)); mBackgroundItem->updateGeometry(std::move(rect));
} }
@ -96,5 +96,5 @@ void RectangleNode::createOrUpdateGeometry(SceneInfo* sceneInfo)
void RectangleNode::updateTransform() void RectangleNode::updateTransform()
{ {
mBackgroundItem->updateTransform({ mLocation, mWidth, mHeight }); mBackgroundItem->updateTransform({ mLocation });
} }

View file

@ -161,7 +161,7 @@ void TextNode::update(SceneInfo* sceneInfo)
if (mContentIsDirty || mLinesAreDirty) if (mContentIsDirty || mLinesAreDirty)
{ {
dynamic_cast<SceneText*>(mTextItem.get())->setTextData(mTextData); mTextItem->setTextData(mTextData);
mContentIsDirty = false; mContentIsDirty = false;
mLinesAreDirty = false; mLinesAreDirty = false;
} }
@ -169,6 +169,8 @@ void TextNode::update(SceneInfo* sceneInfo)
if (mTransformIsDirty) if (mTransformIsDirty)
{ {
mTextItem->updateTransform({mLocation}); mTextItem->updateTransform({mLocation});
mTextItem->setTextWidth(mWidth);
mTextItem->setTextHeight(mHeight);
mTransformIsDirty = false; mTransformIsDirty = false;
} }

View file

@ -4,6 +4,8 @@
#include "FontItem.h" #include "FontItem.h"
#include "TextData.h" #include "TextData.h"
#include "Bounds.h"
#include "SceneText.h"
#include <memory> #include <memory>
#include <string> #include <string>
@ -47,7 +49,7 @@ private:
double mWidth{1}; double mWidth{1};
double mHeight{1}; double mHeight{1};
std::unique_ptr<SceneItem> mTextItem; std::unique_ptr<SceneText> mTextItem;
}; };
using TextNodetr = std::unique_ptr<TextNode>; using TextNodetr = std::unique_ptr<TextNode>;

View file

@ -23,3 +23,31 @@ void SceneText::setTextData(const TextData& data)
mTextData = 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;
}
}

View file

@ -10,11 +10,21 @@ public:
Type getType() const override; Type getType() const override;
double getTextWidth() const;
double getTextHeight() const;
const TextData& getTextData() const; const TextData& getTextData() const;
void setTextWidth(double width);
void setTextHeight(double height);
void setTextData(const TextData& content); void setTextData(const TextData& content);
private: private:
bool mTextGeometryIsDirty{true}; bool mTextGeometryIsDirty{true};
TextData mTextData; TextData mTextData;
double mTextWidth{ 0.0 };
double mTextHeight{ 0.0 };
}; };

View file

@ -0,0 +1,53 @@
#include "SvgTextElement.h"
#include "XmlAttribute.h"
#include <sstream>
SvgTextElement::SvgTextElement()
:SvgElement("text")
{
}
void SvgTextElement::setLocation(const Point& loc)
{
auto x = std::make_unique<XmlAttribute>("x");
auto y = std::make_unique<XmlAttribute>("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<XmlAttribute>("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<XmlAttribute>("font-family");
attr->setValue(family);
addAttribute(std::move(attr));
}
void SvgTextElement::setFontSize(float size)
{
auto attr = std::make_unique<XmlAttribute>("font-size");
attr->setValue(std::to_string(size));
addAttribute(std::move(attr));
}

View file

@ -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);
};

View file

@ -124,6 +124,15 @@ void SvgRectangle::setHeight(double h)
addAttribute(std::move(height)); addAttribute(std::move(height));
} }
void SvgRectangle::setRadius(double radius)
{
auto rx = std::make_unique<XmlAttribute>("rx");
rx->setValue(std::to_string(radius));
addAttribute(std::move(rx));
}
SvgPolygon::SvgPolygon() SvgPolygon::SvgPolygon()
: SvgShapeElement("polygon") : SvgShapeElement("polygon")

View file

@ -43,6 +43,8 @@ public:
void setWidth(double width); void setWidth(double width);
void setHeight(double height); void setHeight(double height);
void setRadius(double radius);
}; };
class SvgPolygon : public SvgShapeElement class SvgPolygon : public SvgShapeElement

View file

@ -6,6 +6,8 @@
#include "ThemeManager.h" #include "ThemeManager.h"
#include "PaintEvent.h" #include "PaintEvent.h"
#include "FontTokens.h"
#include "MouseEvent.h" #include "MouseEvent.h"
#include "FileLogger.h" #include "FileLogger.h"
@ -16,6 +18,10 @@ Button::Button(ButtonData::Component component)
{ {
mStyle.mComponent = component; mStyle.mComponent = component;
mName = "Button"; mName = "Button";
setHeight(mStyle.getContainerHeight());
setMaxHeight(mStyle.getContainerHeight());
setRadius(mStyle.getContainerCornerRadius());
} }
Button::~Button() Button::~Button()
@ -66,7 +72,39 @@ void Button::setEnabled(bool isEnabled)
void Button::updateState() void Button::updateState()
{ {
setBackground(mStyle.getContainerColor()); 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) void Button::onMyMouseEvent(const MouseEvent* event)
@ -131,29 +169,31 @@ void Button::doPaint(const PaintEvent* event)
void Button::updateLabel(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) if (!mTextNode)
{ {
mTextNode = TextNode::Create(mLabel, middle); mTextNode = TextNode::Create(mLabel, mLocation);
mTextNode->setName(mName + "_TextNode"); mTextNode->setName(mName + "_TextNode");
mTextNode->setContent(mLabel); mTextNode->setContent(mLabel);
mTextNode->setWidth(mSize.mWidth);
mTextNode->setHeight(mSize.mHeight);
mRootNode->addChild(mTextNode.get()); mRootNode->addChild(mTextNode.get());
} }
if (mTransformDirty) if (mTransformDirty)
{ {
mTextNode->setLocation(middle); mTextNode->setLocation(mLocation);
mTextNode->setWidth(mSize.mWidth); mTextNode->setWidth(mSize.mWidth);
mTextNode->setHeight(mSize.mHeight); mTextNode->setHeight(mSize.mHeight);
} }
if (mMaterialDirty) 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<float>(size));
mTextNode->setFont(font_data);
} }
if (mContentDirty) if (mContentDirty)

View file

@ -34,6 +34,10 @@ protected:
bool isDirty() const override; bool isDirty() const override;
void doPaint(const PaintEvent* event) 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 updateLabel(const PaintEvent* event);
void setState(ButtonData::State state); void setState(ButtonData::State state);
@ -44,6 +48,10 @@ private:
ButtonData mStyle; ButtonData mStyle;
std::string mLabel; std::string mLabel;
Theme::Sys::Color mLabelTextColor;
Theme::Sys::Typescale mLabelTextTypescale;
float mLabelOpacity{ 1.0 };
clickFunc mClickFunc; clickFunc mClickFunc;
std::unique_ptr<TextNode> mTextNode; std::unique_ptr<TextNode> mTextNode;

View file

@ -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 Theme::Sys::Typescale ButtonData::getLabelTypescale() const
{ {
switch (mComponent) switch (mComponent)

View file

@ -40,20 +40,21 @@ public:
Theme::Sys::Color getContainerShadowColor() const; Theme::Sys::Color getContainerShadowColor() const;
Theme::Sys::Color getContainerSurfaceTintColor() const; Theme::Sys::Color getContainerSurfaceTintColor() const;
Theme::Sys::Elevation getContainerElevation() const; Theme::Sys::Elevation getContainerElevation() const;
float getStateLayerOverlayOpacity() const;
Theme::Sys::Color getLabelTextColor() const; Theme::Sys::Color getLabelTextColor() const;
Theme::Sys::Typescale getLabelTypescale() const; Theme::Sys::Typescale getLabelTypescale() const;
float getLabelOpacity() const;
bool canHaveIcon() const; bool canHaveIcon() const;
Theme::Sys::Color getIconColor() const; Theme::Sys::Color getIconColor() const;
float getStateLayerOverlayOpacity() const;
unsigned getContainerHeight() const; unsigned getContainerHeight() const;
unsigned getContainerCornerRadius() const; unsigned getContainerCornerRadius() const;
unsigned getIconSize() const; unsigned getIconSize() const;
unsigned getLeftRightPadding() const;
unsigned getLeftRightPadding() const;
unsigned getLeftPaddingWithIcon() const; unsigned getLeftPaddingWithIcon() const;
unsigned getRightPaddingWithIcon() const; unsigned getRightPaddingWithIcon() const;

View file

@ -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<unsigned>(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;
}

View file

@ -51,6 +51,7 @@ namespace Theme
class FontTokens class FontTokens
{ {
public:
static std::string getFont(Theme::Ref::Typeface::Font font); static std::string getFont(Theme::Ref::Typeface::Font font);
static Theme::Ref::Typeface::Font getFont(Theme::Sys::Typescale typescale); static Theme::Ref::Typeface::Font getFont(Theme::Sys::Typescale typescale);

View file

@ -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) void BoxGeometry::setLocation(const DiscretePoint& loc)
{ {
if (mLocation != loc) if (mLocation != loc)

View file

@ -59,6 +59,12 @@ public:
const DiscretePoint& getLocation() const; const DiscretePoint& getLocation() const;
void setWidth(unsigned width);
void setHeight(unsigned height);
void setMaxHeight(unsigned maxHieght);
void setBounds(unsigned width, unsigned height); void setBounds(unsigned width, unsigned height);
void setSize(const BoundedSize& size); void setSize(const BoundedSize& size);

View file

@ -16,7 +16,6 @@
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <iostream>
Widget::Widget() Widget::Widget()
: BoxGeometry(), : 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) void Widget::setBackgroundOpacity(float opacity)
{ {
if (mBackgroundOpacity != opacity) if (mBackgroundOpacity != opacity)
@ -173,6 +190,9 @@ void Widget::onPaintEvent(const PaintEvent* event)
} }
doPaint(event); doPaint(event);
mGeometryDirty = false;
mMaterialDirty = false;
mTransformDirty = false;
if (mVisibilityDirty) if (mVisibilityDirty)
{ {
@ -293,32 +313,30 @@ void Widget::onMyMouseEvent(const MouseEvent* event)
void Widget::createOrUpdateGeometry() void Widget::createOrUpdateGeometry()
{ {
const auto deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight;
const auto deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom;
if (!mBackgroundNode) if (!mBackgroundNode)
{ {
unsigned locX = mLocation.getX() + mMargin.mLeft; const auto locX = mLocation.getX() + mMargin.mLeft;
unsigned locY = mLocation.getY() + mMargin.mTop; const auto locY = mLocation.getY() + mMargin.mTop;
unsigned deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight;
unsigned deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom;
mBackgroundNode = std::make_unique<RectangleNode>(DiscretePoint(locX, locY), deltaX, deltaY); mBackgroundNode = std::make_unique<RectangleNode>(DiscretePoint(locX, locY), deltaX, deltaY);
mBackgroundNode->setRadius(mRadius);
mBackgroundNode->setName(mName + "_BackgroundNode"); mBackgroundNode->setName(mName + "_BackgroundNode");
mRootNode->addChild(mBackgroundNode.get()); mRootNode->addChild(mBackgroundNode.get());
} }
else else
{ {
mBackgroundNode->setWidth(deltaX);
mBackgroundNode->setHeight(deltaY);
mBackgroundNode->setRadius(mRadius); mBackgroundNode->setRadius(mRadius);
} }
} }
void Widget::updateTransform() void Widget::updateTransform()
{ {
unsigned locX = mLocation.getX() + mMargin.mLeft; const auto locX = mLocation.getX() + mMargin.mLeft;
unsigned locY = mLocation.getY() + mMargin.mTop; const auto 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);
mBackgroundNode->setLocation(DiscretePoint(locX, locY)); mBackgroundNode->setLocation(DiscretePoint(locX, locY));
} }
@ -326,9 +344,16 @@ void Widget::updateMaterial(const PaintEvent* event)
{ {
if (mBackground != Theme::Sys::Color::None) if (mBackground != Theme::Sys::Color::None)
{ {
//if (mBackgroundTone == Theme::Sys::Color::None || mElevation == Theme::Sys::Elevation::Level_0)
//{
auto background_color = event->getThemesManager()->getColor(mBackground); auto background_color = event->getThemesManager()->getColor(mBackground);
background_color.setAlpha(mBackgroundOpacity); background_color.setAlpha(mBackgroundOpacity);
mBackgroundNode->setFillColor(background_color); mBackgroundNode->setFillColor(background_color);
//}
//else
//{
//event->getThemesManager()->getColor(mBackground);
//}
} }
else else
{ {
@ -348,22 +373,14 @@ void Widget::updateMaterial(const PaintEvent* event)
void Widget::updateBackground(const PaintEvent* event) void Widget::updateBackground(const PaintEvent* event)
{ {
unsigned locX = mLocation.getX() + mMargin.mLeft; if (mGeometryDirty)
unsigned locY = mLocation.getY() + mMargin.mTop;
unsigned deltaX = mSize.mWidth - mMargin.mLeft - mMargin.mRight;
unsigned deltaY = mSize.mHeight - mMargin.mTop - mMargin.mBottom;
if (!mBackgroundNode)
{ {
mBackgroundNode = std::make_unique<RectangleNode>(DiscretePoint(locX, locY), deltaX, deltaY); createOrUpdateGeometry();
mBackgroundNode->setName(mName + "_BackgroundNode");
mRootNode->addChild(mBackgroundNode.get());
} }
if (mTransformDirty) if (mTransformDirty)
{ {
updateTransform(); updateTransform();
mTransformDirty = false;
} }
if (mMaterialDirty) if (mMaterialDirty)

View file

@ -1,11 +1,13 @@
#pragma once #pragma once
#include "FontItem.h" #include "FontItem.h"
#include "ITheme.h"
#include "WidgetState.h" #include "WidgetState.h"
#include "BoxGeometry.h" #include "BoxGeometry.h"
#include "TransformNode.h" #include "TransformNode.h"
#include "ITheme.h"
#include "ElevationTokens.h"
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <string> #include <string>
@ -55,6 +57,10 @@ public:
void setBackground(Theme::Sys::Color token); void setBackground(Theme::Sys::Color token);
void setBackgroundTone(Theme::Sys::Color token);
void setElevation(Theme::Sys::Elevation elevation);
void setOutlineThickness(double thickness); void setOutlineThickness(double thickness);
void setOutline(Theme::Sys::Color token); void setOutline(Theme::Sys::Color token);
@ -102,7 +108,9 @@ protected:
Theme::Sys::Color mBorder; Theme::Sys::Color mBorder;
double mBorderThickness{0}; double mBorderThickness{0};
Theme::Sys::Color mBackgroundTone;
Theme::Sys::Color mBackground; Theme::Sys::Color mBackground;
Theme::Sys::Elevation mElevation{ Theme::Sys::Elevation::Level_0 };
float mBackgroundOpacity{ 1.0 }; float mBackgroundOpacity{ 1.0 };
bool mVisible{true}; bool mVisible{true};

View file

@ -5,25 +5,37 @@
#include "ThemeManager.h" #include "ThemeManager.h"
#include "PaintEvent.h" #include "PaintEvent.h"
#include "VerticalSpacer.h"
#include "Button.h" #include "Button.h"
TEST_CASE(TestButton_Elevated, "ui_controls") TEST_CASE(TestButton_Elevated, "ui_controls")
{ {
auto theme_manager = std::make_unique<ThemeManager>(); auto theme_manager = std::make_unique<ThemeManager>();
auto paint_event = PaintEvent::Create(theme_manager.get(), nullptr); VerticalSpacer spacer;
spacer.setWidth(300);
spacer.setHeight(200);
Button button(ButtonData::Component::Elevated); auto enabled_button = Button::Create(ButtonData::Component::Elevated);
button.setLabel("Enabled"); 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; TestRenderer renderer;
renderer.getScene()->addNode(node); renderer.getScene()->addNode(node);
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "Elevated_Enabled.svg"); auto paint_event = PaintEvent::Create(theme_manager.get(), nullptr);
renderer.write(TestUtils::getTestOutputDir(__FILE__) / "Elevated_Enabled.png"); spacer.onPaintEvent(paint_event.get());
renderer.writeSvg(TestUtils::getTestOutputDir(__FILE__) / "Elevated.svg");
renderer.write(TestUtils::getTestOutputDir(__FILE__) / "Elevated.png");
}; };