Convert visual layers to scene nodes.

This commit is contained in:
James Grogan 2022-11-16 15:06:08 +00:00
parent 798cb365d7
commit 3e53bd9e00
64 changed files with 863 additions and 551 deletions

View file

@ -5,9 +5,10 @@
#include "KeyboardEvent.h"
#include "Widget.h"
#include "VisualLayer.h"
#include "Scene.h"
#include "TriMesh.h"
#include "RootNode.h"
#include "TransformNode.h"
#include "AbstractPainter.h"
#include "DrawingContext.h"
@ -119,7 +120,10 @@ void Window::doPaint(mt::Screen* screen)
{
mPlatformWindow->beforePaint(screen);
mDrawingContext->getScene()->syncLayers(mWidget->getLayers());
if (mScene && mScene->getRootNode()->getNumChildren() == 0)
{
mScene->getRootNode()->addChild(mWidget->getRootNode());
}
mDrawingContext->paint();

View file

@ -2,7 +2,8 @@
#include "TextNode.h"
#include "GeometryNode.h"
#include "VisualLayer.h"
#include "TransformNode.h"
#include "MouseEvent.h"
#include <iostream>
@ -32,7 +33,7 @@ void Button::setLabel(const std::string& text)
if (text != mLabel)
{
mLabel = text;
mDirty = true;
mContentDirty = true;
}
}
@ -53,36 +54,36 @@ void Button::onMyMouseEvent(const MouseEvent* event)
}
}
void Button::onPaintEvent(const PaintEvent* event)
bool Button::isDirty() const
{
if (!needsUpdate())
{
return;
}
mLayers.clear();
if (mDirty)
{
mMyLayers.clear();
if(!mVisible)
{
return;
}
addBackground(event);
if(!mLabel.empty())
{
unsigned fontOffset = unsigned(mLabel.size()) * 4;
auto middle = DiscretePoint(mLocation.GetX() + mSize.mWidth/2 - fontOffset, mLocation.GetY() + mSize.mHeight/2 + 4);
auto textLayer = VisualLayer::Create();
auto node = TextNode::Create(mLabel, middle);
node->setFillColor(mBackgroundColor);
textLayer->setTextNode(std::move(node));
mMyLayers.push_back(std::move(textLayer));
}
mDirty = false;
addMyLayers();
}
return Widget::isDirty() || mContentDirty;
}
void Button::doPaint(const PaintEvent* event)
{
updateBackground(event);
updateLabel(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);
mRootNode->addChild(mTextNode.get());
}
if (mMaterialDirty)
{
mTextNode->setFillColor(mBackgroundColor);
}
if (mContentDirty)
{
mTextNode->setContent(mLabel);
mContentDirty = false;
}
}

View file

@ -8,6 +8,7 @@
class PaintEvent;
class MouseEvent;
class TextNode;
class Button : public Widget
{
@ -25,13 +26,19 @@ public:
protected:
void onMyMouseEvent(const MouseEvent* event) override;
void onPaintEvent(const PaintEvent* event) override;
bool isDirty() const override;
void doPaint(const PaintEvent* event) override;
void updateLabel(const PaintEvent* event);
private:
std::string mLabel;
clickFunc mClickFunc;
Color mCachedColor;
Color mClickedColor;
std::unique_ptr<TextNode> mTextNode;
bool mContentDirty{true};
};
using ButtonUPtr = std::unique_ptr<Button>;

View file

@ -27,7 +27,7 @@ void HorizontalSpacer::addWidgetWithScale(WidgetUPtr widget, double scale)
mScales.push_back(scale);
}
void HorizontalSpacer::addChildLayers(const PaintEvent* event)
void HorizontalSpacer::updateChildLocations()
{
double scaleSum = std::accumulate(mScales.begin(), mScales.end(), 0.0);
double offset = 0;
@ -49,20 +49,6 @@ void HorizontalSpacer::addChildLayers(const PaintEvent* event)
}
child->setBounds(mSize.mWidth, unsigned(delta));
child->setLocation(DiscretePoint(mLocation.GetX(), mLocation.GetY() + unsigned(offset)));
child->onPaintEvent(event);
auto layers = child->getLayers();
mLayers.insert(mLayers.end(), layers.begin(), layers.end());
offset += delta;
}
}
void HorizontalSpacer::onPaintEvent(const PaintEvent* event)
{
if (!needsUpdate())
{
return;
}
mLayers.clear();
addChildLayers(event);
}

View file

@ -5,8 +5,6 @@
class HorizontalSpacer : public Widget
{
std::vector<double> mScales;
public:
HorizontalSpacer();
@ -15,10 +13,9 @@ public:
void addWidget(WidgetUPtr widget) override;
void addWidgetWithScale(WidgetUPtr widget, double scale);
void addChildLayers(const PaintEvent* event) override;
void onPaintEvent(const PaintEvent* event) override;
private:
void updateChildLocations() override;
std::vector<double> mScales;
};
using HorizontalSpacerUPtr = std::unique_ptr<HorizontalSpacer>;

View file

@ -1,8 +1,8 @@
#include "Label.h"
#include "TextNode.h"
#include "TransformNode.h"
#include "GeometryNode.h"
#include "VisualLayer.h"
Label::Label()
: Widget(),
@ -21,36 +21,40 @@ void Label::setLabel(const std::string& text)
if (text != mLabel)
{
mLabel = text;
mDirty = true;
mContentDirty = true;
}
}
void Label::onPaintEvent(const PaintEvent* event)
bool Label::isDirty() const
{
if (!needsUpdate())
return Widget::isDirty() || mContentDirty;
}
void Label::doPaint(const PaintEvent* event)
{
updateBackground(event);
updateLabel(event);
}
void Label::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)
{
return;
mTextNode = TextNode::Create(mLabel, middle);
mRootNode->addChild(mTextNode.get());
}
mLayers.clear();
if (mDirty)
if (mMaterialDirty)
{
mMyLayers.clear();
if(!mVisible)
{
return;
}
mTextNode->setFillColor(mBackgroundColor);
}
if(!mLabel.empty())
{
unsigned fontOffset = unsigned(mLabel.size()) * 4;
auto middle = DiscretePoint(mLocation.GetX() + mSize.mWidth/2 - fontOffset, mLocation.GetY() + mSize.mHeight/2 + 4);
auto textLayer = VisualLayer::Create();
auto textElement = TextNode::Create(mLabel, middle);
textElement->setFillColor(mBackgroundColor);
textLayer->setTextNode(std::move(textElement));
mMyLayers.push_back(std::move(textLayer));
}
addMyLayers();
if (mContentDirty)
{
mTextNode->setContent(mLabel);
mContentDirty = false;
}
}

View file

@ -4,6 +4,8 @@
#include <string>
class TextNode;
class Label : public Widget
{
@ -11,14 +13,21 @@ public:
Label();
virtual ~Label() = default;
static std::unique_ptr<Label> Create();
void setLabel(const std::string& text);
void onPaintEvent(const PaintEvent* event) override;
private:
bool isDirty() const override;
void doPaint(const PaintEvent* event) override;
void updateLabel(const PaintEvent* event);
std::string mLabel;
std::unique_ptr<TextNode> mTextNode;
bool mContentDirty{true};
};

View file

@ -1,9 +1,9 @@
#include "TextBox.h"
#include "TextNode.h"
#include "VisualLayer.h"
#include "GeometryNode.h"
#include "KeyboardEvent.h"
#include "TransformNode.h"
#include <sstream>
@ -24,6 +24,7 @@ std::unique_ptr<TextBox> TextBox::Create()
void TextBox::setContent(const std::string& text)
{
mContent = text;
mContentDirty = true;
}
std::string TextBox::getContent() const
@ -34,6 +35,7 @@ std::string TextBox::getContent() const
void TextBox::appendContent(const std::string& text)
{
mContent += text;
mContentDirty = true;
}
bool TextBox::onMyKeyboardEvent(const KeyboardEvent* event)
@ -72,6 +74,7 @@ bool TextBox::onMyKeyboardEvent(const KeyboardEvent* event)
return true;
}
/*
void TextBox::onPaintEvent(const PaintEvent* event)
{
mMyLayers.clear();
@ -101,3 +104,38 @@ void TextBox::onPaintEvent(const PaintEvent* event)
}
addMyLayers();
}
*/
bool TextBox::isDirty() const
{
return Widget::isDirty() || mContentDirty;
}
void TextBox::doPaint(const PaintEvent* event)
{
updateBackground(event);
updateLabel(event);
}
void TextBox::updateLabel(const PaintEvent* event)
{
unsigned fontOffset = unsigned(mContent.size()) * 4;
auto middle = DiscretePoint(mLocation.GetX() + mSize.mWidth/2 - fontOffset, mLocation.GetY() + mSize.mHeight/2 + 4);
if (!mTextNode)
{
mTextNode = TextNode::Create(mContent, middle);
mRootNode->addChild(mTextNode.get());
}
if (mMaterialDirty)
{
mTextNode->setFillColor(mBackgroundColor);
}
if (mContentDirty)
{
mTextNode->setContent(mContent);
mContentDirty = false;
}
}

View file

@ -4,6 +4,8 @@
#include <string>
class TextNode;
class TextBox : public Widget
{
public:
@ -17,12 +19,19 @@ public:
void appendContent(const std::string& text);
void onPaintEvent(const PaintEvent* event) override;
//void onPaintEvent(const PaintEvent* event) override;
bool onMyKeyboardEvent(const KeyboardEvent* event) override;
private:
bool isDirty() const override;
void doPaint(const PaintEvent* event) override;
void updateLabel(const PaintEvent* event);
std::string mContent;
std::unique_ptr<TextNode> mTextNode;
bool mContentDirty{true};
bool mCaps;
};

View file

@ -26,9 +26,8 @@ void VerticalSpacer::AddWidgetWithScale(WidgetUPtr widget, double scale)
mScales.push_back(scale);
}
void VerticalSpacer::addChildLayers(const PaintEvent* event)
void VerticalSpacer::updateChildLocations()
{
mLayers.clear();
double scaleSum = std::accumulate(mScales.begin(), mScales.end(), 0.0);
double offset = 0;
unsigned delta = mSize.mWidth / unsigned(mChildren.size());
@ -39,14 +38,7 @@ void VerticalSpacer::addChildLayers(const PaintEvent* event)
double delta = mSize.mWidth * (scale/scaleSum);
child->setBounds(unsigned(delta), mSize.mHeight);
child->setLocation(DiscretePoint(mLocation.GetX() + unsigned(offset), mLocation.GetY()));
child->onPaintEvent(event);
auto layers = child->getLayers();
mLayers.insert(mLayers.end(), layers.begin(), layers.end());
offset += delta;
}
}
void VerticalSpacer::onPaintEvent(const PaintEvent* event)
{
addChildLayers(event);
}

View file

@ -4,7 +4,6 @@
class VerticalSpacer : public Widget
{
std::vector<double> mScales;
public:
VerticalSpacer();
@ -15,9 +14,9 @@ public:
void AddWidgetWithScale(WidgetUPtr widget, double scale);
void addChildLayers(const PaintEvent* event) override;
void onPaintEvent(const PaintEvent* event) override;
private:
void updateChildLocations() override;
std::vector<double> mScales;
};
using VerticalSpacerUPtr = std::unique_ptr<VerticalSpacer>;

View file

@ -4,9 +4,11 @@
#include "MouseEvent.h"
#include "KeyboardEvent.h"
#include "PaintEvent.h"
#include "VisualLayer.h"
#include "AbstractVisualNode.h"
#include "TextNode.h"
#include "Color.h"
#include "TransformNode.h"
#include "RootNode.h"
#include <algorithm>
#include <iterator>
@ -17,8 +19,7 @@ Widget::Widget()
mSize({100, 0, 0, 100, 0, 0}),
mPadding(),
mMargin(),
mMyLayers(),
mLayers(),
mRootNode(std::make_unique<TransformNode>()),
mChildren(),
mBorderThickness(0),
mBackgroundColor(Color(255, 255, 255)),
@ -40,6 +41,7 @@ std::unique_ptr<Widget> Widget::Create()
void Widget::addWidget(WidgetUPtr widget)
{
mPendingChildNodes.push_back(widget->getRootNode());
mChildren.push_back(std::move(widget));
}
@ -53,9 +55,9 @@ const DiscretePoint& Widget::getLocation() const
return mLocation;
}
std::vector<VisualLayer*> Widget::getLayers() const
TransformNode* Widget::getRootNode() const
{
return mLayers;
return mRootNode.get();
}
void Widget::setSize(const BoundedSize& size)
@ -63,7 +65,7 @@ void Widget::setSize(const BoundedSize& size)
if (size != mSize)
{
mSize = size;
mDirty = true;
mTransformDirty = true;
}
}
@ -77,7 +79,7 @@ void Widget::setMargin(const BoundaryOffset& margin)
if (margin != mMargin)
{
mMargin = margin;
mDirty = true;
mTransformDirty = true;
}
}
@ -91,7 +93,7 @@ void Widget::setPadding(const BoundaryOffset& padding)
if (padding != mPadding)
{
mPadding = padding;
mDirty = true;
mTransformDirty = true;
}
}
@ -99,7 +101,7 @@ void Widget::setBounds(unsigned width, unsigned height)
{
if (width != mSize.mWidth || height != mSize.mHeight)
{
mDirty = true;
mTransformDirty = true;
mSize.mWidth = width;
mSize.mHeight = height;
}
@ -110,7 +112,7 @@ void Widget::setBackgroundColor(const Color& color)
if (mBackgroundColor != color)
{
mBackgroundColor = std::move(color);
mDirty = true;
mMaterialDirty = true;
}
}
@ -119,7 +121,7 @@ void Widget::setLocation(const DiscretePoint& loc)
if (mLocation != loc)
{
mLocation = loc;
mDirty = true;
mTransformDirty = true;
}
}
@ -127,35 +129,19 @@ void Widget::setVisible(bool visible)
{
if (mVisible != visible)
{
mDirty = true;
mVisibilityDirty = true;
}
mVisible = visible;
}
void Widget::addMyLayers()
bool Widget::isDirty() const
{
mLayers.clear();
mLayers.reserve(mMyLayers.size());
auto getRaw = [](const VisualLayerUPtr& uptr){return uptr.get();};
std::transform(mMyLayers.begin(), mMyLayers.end(), std::back_inserter(mLayers), getRaw);
}
void Widget::addChildLayers(const PaintEvent* event)
{
for(auto& child: mChildren)
{
child->setBounds(mSize.mWidth, mSize.mHeight);
child->setLocation(mLocation);
child->onPaintEvent(event);
const auto layers = child->getLayers();
mLayers.insert(mLayers.end(), layers.begin(), layers.end());
}
return mTransformDirty || mMaterialDirty || mVisibilityDirty || mPendingChildNodes.size() > 0;
}
bool Widget::needsUpdate() const
{
if (mDirty)
if (isDirty())
{
return true;
}
@ -169,26 +155,48 @@ bool Widget::needsUpdate() const
return false;
}
void Widget::doPaint(const PaintEvent* event)
{
updateBackground(event);
}
void Widget::onPaintEvent(const PaintEvent* event)
{
if (!needsUpdate())
{
return;
}
mLayers.clear();
if (mDirty)
if (isDirty())
{
mMyLayers.clear();
if(!mVisible)
{
return;
}
addBackground(event);
mDirty = false;
doPaint(event);
mTransformDirty = false;
mMaterialDirty = false;
mVisibilityDirty = false;
}
for (auto node : mPendingChildNodes)
{
mRootNode->addChild(node);
}
mPendingChildNodes.clear();
updateChildLocations();
for(auto& child: mChildren)
{
child->onPaintEvent(event);
}
}
void Widget::updateChildLocations()
{
for(auto& child: mChildren)
{
child->setBounds(mSize.mWidth, mSize.mHeight);
child->setLocation(mLocation);
}
addMyLayers();
addChildLayers(event);
}
bool Widget::contains(const DiscretePoint& loc) const
@ -267,16 +275,32 @@ void Widget::onMyMouseEvent(const MouseEvent* event)
}
void Widget::addBackground(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;
auto node = RectangleNode::Create(DiscretePoint(locX, locY), deltaX, deltaY);
node->setFillColor(mBackgroundColor);
auto layer = VisualLayer::Create();
layer->setShapeNode(std::move(node));
mMyLayers.push_back(std::move(layer));
if (!mBackgroundNode)
{
mRootNode->addChild(mBackgroundNode.get());
}
if (mTransformDirty)
{
mBackgroundNode->setWidth(deltaX);
mBackgroundNode->setHeight(deltaY);
mBackgroundNode->setLocation(DiscretePoint(locX, locY));
}
if (mMaterialDirty)
{
mBackgroundNode->setFillColor(mBackgroundColor);
}
if (mVisibilityDirty)
{
mBackgroundNode->setIsVisible(mVisible);
}
}

View file

@ -10,7 +10,9 @@ class MouseEvent;
class KeyboardEvent;
class PaintEvent;
class VisualLayer;
class AbstractVisualNode;
class TransformNode;
class RectangleNode;
class Widget
{
@ -71,7 +73,7 @@ public:
BoundedSize getSize() const;
std::vector<VisualLayer*> getLayers() const;
TransformNode* getRootNode() const;
const DiscretePoint& getLocation() const;
@ -106,27 +108,38 @@ protected:
virtual void onMyMouseEvent(const MouseEvent* event);
virtual void addChildLayers(const PaintEvent* event);
virtual void updateBackground(const PaintEvent* event);
virtual void addBackground(const PaintEvent* event);
virtual void doPaint(const PaintEvent* event);
virtual void updateChildLocations();
void addMyLayers();
bool needsUpdate() const;
protected:
virtual bool isDirty() const;
DiscretePoint mLocation;
BoundedSize mSize;
BoundaryOffset mPadding;
BoundaryOffset mMargin;
std::vector<std::unique_ptr<VisualLayer> > mMyLayers;
std::vector<VisualLayer*> mLayers;
std::unique_ptr<TransformNode> mRootNode;
std::vector<std::unique_ptr<Widget> > mChildren;
unsigned mBorderThickness{0};
Color mBackgroundColor;
Color mBorderColor;
bool mVisible{false};
bool mDirty{true};
std::unique_ptr<RectangleNode> mBackgroundNode;
bool mTransformDirty{true};
bool mMaterialDirty{true};
bool mVisibilityDirty{true};
std::vector<TransformNode*> mPendingChildNodes;
};
using WidgetUPtr = std::unique_ptr<Widget>;