443 lines
8.4 KiB
C++
443 lines
8.4 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 "ThemeManager.h"
|
|
|
|
#include "Window.h"
|
|
#include "FileLogger.h"
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
|
|
Widget::Widget()
|
|
: BoxGeometry(),
|
|
mRootNode(std::make_unique<TransformNode>()),
|
|
mChildren(),
|
|
mBorderThickness(0),
|
|
mBackground(Theme::Sys::Color::Primary),
|
|
mBorder(Theme::Sys::Color::Outline),
|
|
mVisible(true)
|
|
{
|
|
mName = "Widget";
|
|
}
|
|
|
|
Widget::~Widget()
|
|
{
|
|
|
|
}
|
|
|
|
std::unique_ptr<Widget> Widget::Create()
|
|
{
|
|
return std::make_unique<Widget>();
|
|
}
|
|
|
|
void Widget::addWidget(WidgetUPtr widget)
|
|
{
|
|
widget->setParent(this);
|
|
|
|
mPendingChildNodes.push_back(widget->getRootNode());
|
|
mChildren.push_back(std::move(widget));
|
|
}
|
|
|
|
void Widget::setName(const std::string& name)
|
|
{
|
|
mName = name;
|
|
}
|
|
|
|
const std::string& Widget::getName() const
|
|
{
|
|
return mName;
|
|
}
|
|
|
|
|
|
TransformNode* Widget::getRootNode() const
|
|
{
|
|
return mRootNode.get();
|
|
}
|
|
|
|
void Widget::setBackground(Theme::Sys::Color token)
|
|
{
|
|
if (mBackground != token)
|
|
{
|
|
mBackground = token;
|
|
mMaterialDirty = true;
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
mBackgroundOpacity = opacity;
|
|
mMaterialDirty = true;
|
|
}
|
|
}
|
|
|
|
void Widget::setOutlineThickness(double thickness)
|
|
{
|
|
if (mBorderThickness != thickness)
|
|
{
|
|
mBorderThickness = thickness;
|
|
mMaterialDirty = true;
|
|
}
|
|
}
|
|
|
|
void Widget::setOutline(Theme::Sys::Color token)
|
|
{
|
|
if (mBorder != token)
|
|
{
|
|
mBorder = token;
|
|
mMaterialDirty = true;
|
|
}
|
|
}
|
|
|
|
void Widget::setRadius(double radius)
|
|
{
|
|
if (mRadius != radius)
|
|
{
|
|
mRadius = radius;
|
|
mGeometryDirty = 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 mStateDirty || mGeometryDirty || 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::updateState()
|
|
{
|
|
|
|
}
|
|
|
|
void Widget::doPaint(const PaintEvent* event)
|
|
{
|
|
updateBackground(event);
|
|
}
|
|
|
|
void Widget::onPaintEvent(const PaintEvent* event)
|
|
{
|
|
if (!needsUpdate())
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (isDirty())
|
|
{
|
|
mRootNode->setName(mName + "_RootNode");
|
|
|
|
if (mStateDirty)
|
|
{
|
|
updateState();
|
|
mStateDirty = false;
|
|
}
|
|
|
|
doPaint(event);
|
|
mGeometryDirty = false;
|
|
mMaterialDirty = false;
|
|
mTransformDirty = false;
|
|
|
|
if (mVisibilityDirty)
|
|
{
|
|
mRootNode->setIsVisible(mVisible);
|
|
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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
bool Widget::onFocusInEvent(const FocusEvent* event)
|
|
{
|
|
bool inChild = false;
|
|
for (const auto& child : mChildren)
|
|
{
|
|
if (child->onFocusInEvent(event))
|
|
{
|
|
inChild = true;
|
|
break;
|
|
}
|
|
}
|
|
if (inChild)
|
|
{
|
|
return true;
|
|
}
|
|
else if (mAcceptsFocus)
|
|
{
|
|
setFocus(true);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void Widget::setFocus(bool hasFocus)
|
|
{
|
|
if (mHasFocus != hasFocus)
|
|
{
|
|
mHasFocus = hasFocus;
|
|
mStateDirty = true;
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
const auto locX = mLocation.getX() + mMargin.mLeft;
|
|
const auto locY = mLocation.getY() + mMargin.mTop;
|
|
mBackgroundNode = std::make_unique<RectangleNode>(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()
|
|
{
|
|
const auto locX = mLocation.getX() + mMargin.mLeft;
|
|
const auto locY = mLocation.getY() + mMargin.mTop;
|
|
mBackgroundNode->setLocation(DiscretePoint(locX, locY));
|
|
}
|
|
|
|
void Widget::updateMaterial(const PaintEvent* event)
|
|
{
|
|
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);
|
|
background_color.setAlpha(mBackgroundOpacity);
|
|
mBackgroundNode->setFillColor(background_color);
|
|
//}
|
|
//else
|
|
//{
|
|
//event->getThemesManager()->getColor(mBackground);
|
|
//}
|
|
}
|
|
else
|
|
{
|
|
mBackgroundNode->setHasFillColor(false);
|
|
}
|
|
|
|
if (mBorder != Theme::Sys::Color::None)
|
|
{
|
|
mBackgroundNode->setStrokeColor(event->getThemesManager()->getColor(mBorder));
|
|
mBackgroundNode->setStrokeThickness(mBorderThickness);
|
|
}
|
|
else
|
|
{
|
|
mBackgroundNode->setHasStrokeColor(false);
|
|
}
|
|
}
|
|
|
|
void Widget::updateBackground(const PaintEvent* event)
|
|
{
|
|
if (mGeometryDirty)
|
|
{
|
|
createOrUpdateGeometry();
|
|
}
|
|
|
|
if (mTransformDirty)
|
|
{
|
|
updateTransform();
|
|
}
|
|
|
|
if (mMaterialDirty)
|
|
{
|
|
updateMaterial(event);
|
|
}
|
|
|
|
if (mVisibilityDirty)
|
|
{
|
|
mBackgroundNode->setIsVisible(mVisible);
|
|
}
|
|
}
|
|
|
|
mt::Window* Widget::getTopLevelWindow() const
|
|
{
|
|
if(mWindow)
|
|
{
|
|
return mWindow;
|
|
}
|
|
|
|
std::cout << "I am " << getName() << std::endl;
|
|
|
|
auto lastParent = mParent;
|
|
auto nextParent = mParent;
|
|
while(nextParent)
|
|
{
|
|
lastParent = nextParent;
|
|
nextParent = lastParent->getParent();
|
|
std::cout << "Checking if " << lastParent->getName() << std::endl;
|
|
if (nextParent)
|
|
{
|
|
std::cout << "Next is " << nextParent->getName() << std::endl;
|
|
}
|
|
else
|
|
{
|
|
std::cout << "no next" << std::endl;
|
|
}
|
|
}
|
|
return lastParent->getTopLevelWindow();
|
|
}
|
|
|
|
Widget* Widget::getParent() const
|
|
{
|
|
return mParent;
|
|
}
|
|
|
|
mt::Window* Widget::getWindow() const
|
|
{
|
|
return mWindow;
|
|
}
|
|
|
|
void Widget::setParent(Widget* parent)
|
|
{
|
|
mParent = parent;
|
|
}
|
|
|
|
void Widget::setWindow(mt::Window* window)
|
|
{
|
|
mWindow = window;
|
|
}
|