add: Simple widget system
This commit is contained in:
@@ -8,17 +8,40 @@ configure_file (
|
|||||||
|
|
||||||
set(src
|
set(src
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
|
|
||||||
|
src/Size.hpp
|
||||||
|
src/Vector.hpp
|
||||||
|
src/Rect.hpp
|
||||||
|
|
||||||
src/Image.hpp
|
src/Image.hpp
|
||||||
src/Image.cpp
|
src/Image.cpp
|
||||||
|
|
||||||
|
src/ScreenManager.hpp
|
||||||
|
src/ScreenManager.cpp
|
||||||
|
|
||||||
src/display/IDisplay.hpp
|
src/display/IDisplay.hpp
|
||||||
src/display/Display.hpp
|
src/display/Display.hpp
|
||||||
src/display/Display.cpp
|
src/display/Display.cpp
|
||||||
|
|
||||||
src/render/RenderTarget.hpp
|
src/render/RenderTarget.hpp
|
||||||
src/render/RenderTarget.cpp
|
src/render/RenderTarget.cpp
|
||||||
|
|
||||||
src/font/Font.hpp
|
src/font/Font.hpp
|
||||||
src/font/Font.cpp
|
src/font/Font.cpp
|
||||||
src/font/Glyph.hpp
|
src/font/Glyph.hpp
|
||||||
src/font/Glyph.cpp
|
src/font/Glyph.cpp
|
||||||
|
|
||||||
|
src/widgets/Widget.hpp
|
||||||
|
src/widgets/Widget.cpp
|
||||||
|
src/widgets/clock/Digital.hpp
|
||||||
|
src/widgets/clock/Digital.cpp
|
||||||
|
src/widgets/clock/Analog.hpp
|
||||||
|
src/widgets/clock/Analog.cpp
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (BUILD_EPD)
|
if (BUILD_EPD)
|
||||||
|
|||||||
64
frame/src/ScreenManager.cpp
Normal file
64
frame/src/ScreenManager.cpp
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#include "ScreenManager.hpp"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
|
||||||
|
ScreenManager::ScreenManager(std::unique_ptr<display::IDisplay> pDisplay)
|
||||||
|
: mDisplay(std::move(pDisplay))
|
||||||
|
, mRenderTarget(mDisplay->getSize())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenManager::Update()
|
||||||
|
{
|
||||||
|
if(mRoot)
|
||||||
|
{
|
||||||
|
mRoot->Update();
|
||||||
|
}
|
||||||
|
if(mDisplay)
|
||||||
|
{
|
||||||
|
mDisplay->Update();
|
||||||
|
if(!mDisplay->isOpen())
|
||||||
|
{
|
||||||
|
mIsRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenManager::Render()
|
||||||
|
{
|
||||||
|
if(mRoot)
|
||||||
|
{
|
||||||
|
mRenderTarget.Clear();
|
||||||
|
mRoot->Render(mRenderTarget);
|
||||||
|
if(mDisplay)
|
||||||
|
{
|
||||||
|
mDisplay->Display(mRenderTarget.getImage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenManager::MainLoop()
|
||||||
|
{
|
||||||
|
while(mIsRunning)
|
||||||
|
{
|
||||||
|
Update();
|
||||||
|
|
||||||
|
if(mRoot && mRoot->isDirty())
|
||||||
|
{
|
||||||
|
Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(mUpdateInterval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScreenManager::setRoot(widgets::Widget::shared_ptr widget)
|
||||||
|
{
|
||||||
|
mRoot = widget;
|
||||||
|
mRoot->ComputeChildSize(mDisplay->getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame
|
||||||
36
frame/src/ScreenManager.hpp
Normal file
36
frame/src/ScreenManager.hpp
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "display/IDisplay.hpp"
|
||||||
|
#include "render/RenderTarget.hpp"
|
||||||
|
#include "widgets/Widget.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
|
||||||
|
class ScreenManager
|
||||||
|
{
|
||||||
|
std::unique_ptr<display::IDisplay> mDisplay;
|
||||||
|
|
||||||
|
render::RenderTarget mRenderTarget;
|
||||||
|
widgets::Widget::shared_ptr mRoot;
|
||||||
|
|
||||||
|
std::chrono::duration<double> mUpdateInterval = 0.5s;
|
||||||
|
|
||||||
|
bool mIsRunning = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScreenManager(std::unique_ptr<display::IDisplay> pDisplay);
|
||||||
|
|
||||||
|
void Update();
|
||||||
|
void Render();
|
||||||
|
|
||||||
|
void MainLoop();
|
||||||
|
|
||||||
|
void setRoot(widgets::Widget::shared_ptr widget);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame
|
||||||
@@ -12,6 +12,8 @@ namespace frame::display
|
|||||||
std::string mName;
|
std::string mName;
|
||||||
Size mSize;
|
Size mSize;
|
||||||
|
|
||||||
|
bool mIsOpen = true;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IDisplay(std::string_view pName, Size pSize)
|
IDisplay(std::string_view pName, Size pSize)
|
||||||
: mName(pName)
|
: mName(pName)
|
||||||
@@ -33,5 +35,15 @@ namespace frame::display
|
|||||||
{
|
{
|
||||||
return mSize;
|
return mSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isOpen() const
|
||||||
|
{
|
||||||
|
return mIsOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close()
|
||||||
|
{
|
||||||
|
mIsOpen = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace frame::display
|
} // namespace frame::display
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ namespace frame::display
|
|||||||
sf::Event ev;
|
sf::Event ev;
|
||||||
while(window.pollEvent(ev))
|
while(window.pollEvent(ev))
|
||||||
{
|
{
|
||||||
|
if(ev.type == sf::Event::Closed)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,31 @@
|
|||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
#include "ScreenManager.hpp"
|
||||||
#include "display/Display.hpp"
|
#include "display/Display.hpp"
|
||||||
#include "font/Font.hpp"
|
#include "font/Font.hpp"
|
||||||
#include "render/RenderTarget.hpp"
|
#include "render/RenderTarget.hpp"
|
||||||
|
#include "widgets/clock/Analog.hpp"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
auto display = frame::display::Create();
|
||||||
|
|
||||||
|
if(!display)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
display->Init();
|
||||||
|
|
||||||
|
frame::ScreenManager screen(std::move(display));
|
||||||
|
|
||||||
|
screen.setRoot(frame::widgets::AnalogClock::Create());
|
||||||
|
|
||||||
|
screen.MainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
constexpr double pi = 3.14159;
|
constexpr double pi = 3.14159;
|
||||||
@@ -167,7 +188,7 @@ int main()
|
|||||||
|
|
||||||
display->Clear(frame::display::Color::WHITE);
|
display->Clear(frame::display::Color::WHITE);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
/*
|
/*
|
||||||
#include <EPD_7in5_V2.h>
|
#include <EPD_7in5_V2.h>
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,20 @@ namespace frame::render
|
|||||||
|
|
||||||
RenderTarget::RenderTarget(Size size)
|
RenderTarget::RenderTarget(Size size)
|
||||||
: image(size)
|
: image(size)
|
||||||
|
, root_size{0, 0, (int)size.width, (int)size.height}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderTarget::DrawPixel(Vector const& position, Color color)
|
void RenderTarget::DrawPixel(Vector const& position, Color color)
|
||||||
{
|
{
|
||||||
if(position.x < 0 || position.y < 0 || position.x >= image.getWidth()
|
auto current = getCurrentSize();
|
||||||
|| position.y >= image.getHeight())
|
|
||||||
|
if(position.x < 0 || position.y < 0 || position.x >= current.width
|
||||||
|
|| position.y >= current.height
|
||||||
|
|| (position.x + current.left) >= root_size.width
|
||||||
|
|| (position.y + current.top) >= root_size.height)
|
||||||
return;
|
return;
|
||||||
image.at(position.x, position.y) = color;
|
image.at(position.x + current.left, position.y + current.top) = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderTarget::DrawLine(Vector const& start,
|
void RenderTarget::DrawLine(Vector const& start,
|
||||||
@@ -77,12 +82,16 @@ namespace frame::render
|
|||||||
|
|
||||||
void RenderTarget::DrawCircle(Vector const& center,
|
void RenderTarget::DrawCircle(Vector const& center,
|
||||||
int32_t radius,
|
int32_t radius,
|
||||||
|
int32_t line,
|
||||||
Color color)
|
Color color)
|
||||||
{
|
{
|
||||||
int32_t const r_2 = radius * radius;
|
int32_t const r_2 = radius * radius;
|
||||||
Vector pos{0, -radius};
|
Vector pos{0, -radius};
|
||||||
|
|
||||||
DrawPointsMirrorCircle(center, pos, color);
|
for(auto i = 0; i < line; ++i)
|
||||||
|
{
|
||||||
|
DrawPointsMirrorCircle(center, {pos.x, pos.y + i}, color);
|
||||||
|
}
|
||||||
|
|
||||||
while(pos.x <= radius / std::sqrt(2.f))
|
while(pos.x <= radius / std::sqrt(2.f))
|
||||||
{
|
{
|
||||||
@@ -102,7 +111,10 @@ namespace frame::render
|
|||||||
E += 2 * pos.x - 2 * pos.y + 5;
|
E += 2 * pos.x - 2 * pos.y + 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrawPointsMirrorCircle(center, pos, color);
|
for(auto i = 0; i < line; ++i)
|
||||||
|
{
|
||||||
|
DrawPointsMirrorCircle(center, {pos.x, pos.y + i}, color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,7 +211,7 @@ namespace frame::render
|
|||||||
|
|
||||||
switch(alignVertical)
|
switch(alignVertical)
|
||||||
{
|
{
|
||||||
case AlignVertical::TOP: start.y += lineSpacing_3 * 2; break;
|
case AlignVertical::TOP: start.y -= y_offset; break;
|
||||||
case AlignVertical::CENTER:
|
case AlignVertical::CENTER:
|
||||||
start.y += rect.height / 2;
|
start.y += rect.height / 2;
|
||||||
start.y += text_height / 2;
|
start.y += text_height / 2;
|
||||||
@@ -207,7 +219,7 @@ namespace frame::render
|
|||||||
break;
|
break;
|
||||||
case AlignVertical::BOTTOM:
|
case AlignVertical::BOTTOM:
|
||||||
start.y += rect.height;
|
start.y += rect.height;
|
||||||
start.y += text_height + y_offset;
|
start.y -= text_height + y_offset;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,6 +261,30 @@ namespace frame::render
|
|||||||
image.Clear(color);
|
image.Clear(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rect RenderTarget::getCurrentSize() const
|
||||||
|
{
|
||||||
|
if(Scissor.size() == 0)
|
||||||
|
{
|
||||||
|
return root_size;
|
||||||
|
}
|
||||||
|
return Scissor.top();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::pushViewport(Rect rect)
|
||||||
|
{
|
||||||
|
auto current = getCurrentSize();
|
||||||
|
|
||||||
|
Scissor.push({current.top + rect.top,
|
||||||
|
current.left + rect.left,
|
||||||
|
rect.width,
|
||||||
|
rect.height});
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::popViewport()
|
||||||
|
{
|
||||||
|
Scissor.pop();
|
||||||
|
}
|
||||||
|
|
||||||
void RenderTarget::DrawPointsMirrorCircle(Vector const& center,
|
void RenderTarget::DrawPointsMirrorCircle(Vector const& center,
|
||||||
Vector const& pos,
|
Vector const& pos,
|
||||||
Color color)
|
Color color)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include "../Vector.hpp"
|
#include "../Vector.hpp"
|
||||||
#include "../font/Font.hpp"
|
#include "../font/Font.hpp"
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
namespace frame
|
namespace frame
|
||||||
{
|
{
|
||||||
enum class AlignVertical { TOP, CENTER, BOTTOM };
|
enum class AlignVertical { TOP, CENTER, BOTTOM };
|
||||||
@@ -19,6 +21,9 @@ namespace frame::render
|
|||||||
{
|
{
|
||||||
Image image;
|
Image image;
|
||||||
|
|
||||||
|
Rect root_size;
|
||||||
|
std::stack<Rect> Scissor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RenderTarget(Size size);
|
RenderTarget(Size size);
|
||||||
|
|
||||||
@@ -30,6 +35,7 @@ namespace frame::render
|
|||||||
|
|
||||||
void DrawCircle(Vector const& center,
|
void DrawCircle(Vector const& center,
|
||||||
int32_t radius,
|
int32_t radius,
|
||||||
|
int32_t line,
|
||||||
Color color = BLACK);
|
Color color = BLACK);
|
||||||
|
|
||||||
void DrawRectFilled(Vector const& TopLeft,
|
void DrawRectFilled(Vector const& TopLeft,
|
||||||
@@ -71,6 +77,10 @@ namespace frame::render
|
|||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rect getCurrentSize() const;
|
||||||
|
void pushViewport(Rect rect);
|
||||||
|
void popViewport();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DrawPointsMirrorCircle(Vector const& center,
|
void DrawPointsMirrorCircle(Vector const& center,
|
||||||
Vector const& pos,
|
Vector const& pos,
|
||||||
|
|||||||
56
frame/src/widgets/Widget.cpp
Normal file
56
frame/src/widgets/Widget.cpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include "Widget.hpp"
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
Widget::shared_ptr Widget::getParent() const
|
||||||
|
{
|
||||||
|
return mParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setParent(week_ptr ptr)
|
||||||
|
{
|
||||||
|
mParent = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Widget::isDirty() const
|
||||||
|
{
|
||||||
|
return mDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setSize(Vector size)
|
||||||
|
{
|
||||||
|
mSize = size;
|
||||||
|
ComputeChildSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector const& Widget::getSize() const
|
||||||
|
{
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setPosition(Vector size)
|
||||||
|
{
|
||||||
|
mRelativePosition = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector Widget::getPosition() const
|
||||||
|
{
|
||||||
|
return mRelativePosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setDirty()
|
||||||
|
{
|
||||||
|
mDirty = true;
|
||||||
|
if(mParent)
|
||||||
|
{
|
||||||
|
mParent->setDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Widget::setClear()
|
||||||
|
{
|
||||||
|
mDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
44
frame/src/widgets/Widget.hpp
Normal file
44
frame/src/widgets/Widget.hpp
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../Rect.hpp"
|
||||||
|
#include "../render/RenderTarget.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
class Widget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using shared_ptr = std::shared_ptr<Widget>;
|
||||||
|
using week_ptr = std::shared_ptr<Widget>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Widget() = default;
|
||||||
|
|
||||||
|
virtual void Update() = 0;
|
||||||
|
virtual void Render(render::RenderTarget& rt) = 0;
|
||||||
|
virtual void ComputeChildSize(Vector size){};
|
||||||
|
|
||||||
|
shared_ptr getParent() const;
|
||||||
|
void setParent(week_ptr ptr);
|
||||||
|
|
||||||
|
void setSize(Vector size);
|
||||||
|
Vector const& getSize() const;
|
||||||
|
|
||||||
|
void setPosition(Vector size);
|
||||||
|
Vector getPosition() const;
|
||||||
|
|
||||||
|
bool isDirty() const;
|
||||||
|
void setDirty();
|
||||||
|
void setClear();
|
||||||
|
|
||||||
|
private:
|
||||||
|
week_ptr mParent;
|
||||||
|
bool mDirty = true;
|
||||||
|
|
||||||
|
Vector mRelativePosition;
|
||||||
|
Vector mSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
94
frame/src/widgets/clock/Analog.cpp
Normal file
94
frame/src/widgets/clock/Analog.cpp
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#include "Analog.hpp"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
constexpr double pi = 3.14159;
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
Widget::shared_ptr AnalogClock::Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<AnalogClock>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogClock::Update()
|
||||||
|
{
|
||||||
|
auto const now = std::chrono::system_clock::now();
|
||||||
|
auto const min = std::chrono::floor<std::chrono::minutes>(now);
|
||||||
|
|
||||||
|
if(last_time != min)
|
||||||
|
{
|
||||||
|
setDirty();
|
||||||
|
last_time = min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AnalogClock::Render(render::RenderTarget& rt)
|
||||||
|
{
|
||||||
|
auto const size = rt.getCurrentSize();
|
||||||
|
auto const min = std::min(size.height, size.width);
|
||||||
|
|
||||||
|
auto const radius = (min / 2) - 10;
|
||||||
|
|
||||||
|
auto const center = Vector{size.width / 2, size.height / 2};
|
||||||
|
|
||||||
|
rt.DrawCircle(center, radius, 4);
|
||||||
|
rt.DrawCircle(center, 6, 4);
|
||||||
|
|
||||||
|
auto step = 360 / 60;
|
||||||
|
|
||||||
|
for(int i = 0; i < 60; ++i)
|
||||||
|
{
|
||||||
|
double const x = std::cos(step * i * pi / 180.f);
|
||||||
|
double const y = std::sin(step * i * pi / 180.f);
|
||||||
|
|
||||||
|
auto lineLength = 10;
|
||||||
|
if(i % 5 == 0)
|
||||||
|
{
|
||||||
|
lineLength = 20;
|
||||||
|
if(i % 3 == 0)
|
||||||
|
{
|
||||||
|
lineLength = 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const fromCenter = radius - lineLength;
|
||||||
|
|
||||||
|
rt.DrawLine({int32_t(x * (radius - 1) + center.x),
|
||||||
|
int32_t(y * (radius - 1) + center.y)},
|
||||||
|
{int32_t(x * fromCenter + center.x),
|
||||||
|
int32_t(y * fromCenter + center.y)});
|
||||||
|
}
|
||||||
|
|
||||||
|
// pls c++ 20
|
||||||
|
std::time_t t = std::chrono::system_clock::to_time_t(last_time);
|
||||||
|
auto c_time = std::localtime(&t);
|
||||||
|
|
||||||
|
// Render Pointer Minute
|
||||||
|
|
||||||
|
auto const min_steps = 360 / 60;
|
||||||
|
auto const min_rad = (min_steps * c_time->tm_min - 90) * pi / 180.f;
|
||||||
|
|
||||||
|
rt.DrawLine(center,
|
||||||
|
{center.x + int32_t(std::cos(min_rad) * radius),
|
||||||
|
center.y + int32_t(std::sin(min_rad) * radius)});
|
||||||
|
|
||||||
|
// Render Pointer Hour
|
||||||
|
|
||||||
|
auto const hour_steps = 360 / 12;
|
||||||
|
auto hour_deg = (hour_steps * c_time->tm_hour - 90);
|
||||||
|
auto const normalied_min = (c_time->tm_min / 59.0);
|
||||||
|
hour_deg += int32_t(normalied_min * hour_steps);
|
||||||
|
|
||||||
|
auto const hour_rad = hour_deg * pi / 180.f;
|
||||||
|
|
||||||
|
rt.DrawLine(center,
|
||||||
|
{center.x + int32_t(std::cos(hour_rad) * radius * 0.6),
|
||||||
|
center.y + int32_t(std::sin(hour_rad) * radius * 0.6)});
|
||||||
|
|
||||||
|
setClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
22
frame/src/widgets/clock/Analog.hpp
Normal file
22
frame/src/widgets/clock/Analog.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Widget.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
class AnalogClock : public Widget
|
||||||
|
{
|
||||||
|
using Time = std::chrono::time_point<std::chrono::system_clock>;
|
||||||
|
|
||||||
|
Time last_time;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Widget::shared_ptr Create();
|
||||||
|
|
||||||
|
void Update() override;
|
||||||
|
void Render(render::RenderTarget& rt) override;
|
||||||
|
};
|
||||||
|
} // namespace frame::widgets
|
||||||
0
frame/src/widgets/clock/Digital.cpp
Normal file
0
frame/src/widgets/clock/Digital.cpp
Normal file
0
frame/src/widgets/clock/Digital.hpp
Normal file
0
frame/src/widgets/clock/Digital.hpp
Normal file
Reference in New Issue
Block a user