stuff-from-scratch/src/ui_elements/widgets/Widget.cpp
2022-11-16 17:27:19 +00:00

316 lines
5.9 KiB
C++

#include "Widget.h"
#include "RectangleNode.h"
#include "MouseEvent.h"
#include "KeyboardEvent.h"
#include "PaintEvent.h"
#include "AbstractVisualNode.h"
#include "TextNode.h"
#include "TransformNode.h"
#include "RootNode.h"
#include <algorithm>
#include <iterator>
#include <iostream>
Widget::Widget()
: mLocation(DiscretePoint(0, 0)),
mSize({100, 0, 0, 100, 0, 0}),
mPadding(),
mMargin(),
mRootNode(std::make_unique<TransformNode>()),
mChildren(),
mBorderThickness(0),
mBackgroundColor(Color(255, 255, 255)),
mBorderColor(Color(0, 0, 0)),
mVisible(true)
{
mName = "Widget";
}
Widget::~Widget()
{
}
std::unique_ptr<Widget> Widget::Create()
{
return std::make_unique<Widget>();
}
void Widget::addWidget(WidgetUPtr widget)
{
mPendingChildNodes.push_back(widget->getRootNode());
mChildren.push_back(std::move(widget));
}
Widget::BoundedSize Widget::getSize() const
{
return mSize;
}
const DiscretePoint& Widget::getLocation() const
{
return mLocation;
}
TransformNode* Widget::getRootNode() const
{
return mRootNode.get();
}
void Widget::setSize(const BoundedSize& size)
{
if (size != mSize)
{
mSize = size;
mTransformDirty = true;
}
}
void Widget::setMargin(unsigned margin)
{
setMargin({margin, margin, margin, margin});
}
void Widget::setMargin(const BoundaryOffset& margin)
{
if (margin != mMargin)
{
mMargin = margin;
mTransformDirty = true;
}
}
void Widget::setPadding(unsigned padding)
{
setPadding({padding, padding, padding, padding});
}
void Widget::setPadding(const BoundaryOffset& padding)
{
if (padding != mPadding)
{
mPadding = padding;
mTransformDirty = true;
}
}
void Widget::setBounds(unsigned width, unsigned height)
{
if (width != mSize.mWidth || height != mSize.mHeight)
{
mTransformDirty = true;
mSize.mWidth = width;
mSize.mHeight = height;
}
}
void Widget::setBackgroundColor(const Color& color)
{
if (mBackgroundColor != color)
{
mBackgroundColor = color;
mMaterialDirty = true;
}
}
void Widget::setLocation(const DiscretePoint& loc)
{
if (mLocation != loc)
{
mLocation = loc;
mTransformDirty = true;
}
}
void Widget::setVisible(bool visible)
{
if (mVisible != visible)
{
mVisibilityDirty = true;
}
mVisible = visible;
for (auto& child : mChildren)
{
child->setVisible(mVisible);
}
}
bool Widget::isDirty() const
{
return mTransformDirty || mMaterialDirty || mVisibilityDirty || mPendingChildNodes.size() > 0;
}
bool Widget::needsUpdate() const
{
if (isDirty())
{
return true;
}
for(auto& child: mChildren)
{
if (child->needsUpdate())
{
return true;
}
}
return false;
}
void Widget::doPaint(const PaintEvent* event)
{
updateBackground(event);
}
void Widget::onPaintEvent(const PaintEvent* event)
{
if (!needsUpdate())
{
return;
}
if (isDirty())
{
mRootNode->setName(mName);
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);
child->setVisible(mVisible);
}
}
bool Widget::contains(const DiscretePoint& loc) const
{
if(loc.GetX() < mLocation.GetX())
{
return false;
}
if(loc.GetX() > mLocation.GetX() + mSize.mWidth)
{
return false;
}
if(loc.GetY() > mLocation.GetY() + mSize.mHeight)
{
return false;
}
if(loc.GetY() < mLocation.GetY())
{
return false;
}
return true;
}
bool Widget::onKeyboardEvent(const KeyboardEvent* event)
{
bool inChild = false;
for(const auto& child : mChildren)
{
if(child->onKeyboardEvent(event))
{
inChild = true;
break;
}
}
if(!inChild)
{
return onMyKeyboardEvent(event);
}
return true;
}
bool Widget::onMyKeyboardEvent(const KeyboardEvent* event)
{
return false;
}
bool Widget::onMouseEvent(const MouseEvent* event)
{
bool inChild = false;
for(const auto& child : mChildren)
{
if(child->onMouseEvent(event))
{
inChild = true;
break;
}
}
if(!inChild)
{
if(mVisible && contains(event->GetClientLocation()))
{
onMyMouseEvent(event);
return true;
}
else
{
return false;
}
}
return true;
}
void Widget::onMyMouseEvent(const MouseEvent* 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)
{
mBackgroundNode = std::make_unique<RectangleNode>(DiscretePoint(locX, locY), deltaX, deltaY);
mBackgroundNode->setName(mName + "_BackgroundNode");
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);
}
}