Compare commits
2 Commits
243bf41e90
...
fe9fc4d69c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe9fc4d69c
|
||
|
|
1772a3baff
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -35,3 +35,4 @@
|
|||||||
build/*
|
build/*
|
||||||
.vscode/*
|
.vscode/*
|
||||||
frame/src/Config.h
|
frame/src/Config.h
|
||||||
|
.editorconfig
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ set(src
|
|||||||
src/ScreenManager.hpp
|
src/ScreenManager.hpp
|
||||||
src/ScreenManager.cpp
|
src/ScreenManager.cpp
|
||||||
|
|
||||||
|
src/ServiceLocator.hpp
|
||||||
|
src/ServiceLocator.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
|
||||||
@@ -30,9 +33,14 @@ set(src
|
|||||||
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/font/FontRegistry.hpp
|
||||||
|
src/font/FontRegistry.cpp
|
||||||
|
|
||||||
|
|
||||||
src/widgets/Widget.hpp
|
src/widgets/Widget.hpp
|
||||||
src/widgets/Widget.cpp
|
src/widgets/Widget.cpp
|
||||||
|
src/widgets/WidgetRegistry.hpp
|
||||||
|
src/widgets/WidgetRegistry.cpp
|
||||||
src/widgets/clock/Digital.hpp
|
src/widgets/clock/Digital.hpp
|
||||||
src/widgets/clock/Digital.cpp
|
src/widgets/clock/Digital.cpp
|
||||||
src/widgets/clock/Analog.hpp
|
src/widgets/clock/Analog.hpp
|
||||||
|
|||||||
19
frame/src/ServiceLocator.cpp
Normal file
19
frame/src/ServiceLocator.cpp
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#include "ServiceLocator.hpp"
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
|
||||||
|
IService::IService(std::string_view name)
|
||||||
|
: name(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view IService::getName() const
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<std::type_index, std::shared_ptr<IService>>
|
||||||
|
Service::Services = {};
|
||||||
|
|
||||||
|
} // namespace frame
|
||||||
40
frame/src/ServiceLocator.hpp
Normal file
40
frame/src/ServiceLocator.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <typeindex>
|
||||||
|
#include <typeinfo>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
class IService
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IService(std::string_view name);
|
||||||
|
virtual ~IService() = default;
|
||||||
|
|
||||||
|
std::string_view getName() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Service
|
||||||
|
{
|
||||||
|
static std::unordered_map<std::type_index, std::shared_ptr<IService>>
|
||||||
|
Services;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template<class SERVICE>
|
||||||
|
static std::shared_ptr<SERVICE> get()
|
||||||
|
{
|
||||||
|
auto const type = std::type_index(typeid(SERVICE));
|
||||||
|
if(Services.find(type) == Services.end())
|
||||||
|
{
|
||||||
|
Services[type] = std::make_shared<SERVICE>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::static_pointer_cast<SERVICE>(Services[type]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame
|
||||||
@@ -65,6 +65,23 @@ namespace frame::font
|
|||||||
return y_offset;
|
return y_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Font::getOptimalSize(std::string_view text, Rect rect) const
|
||||||
|
{
|
||||||
|
auto best_size = 0;
|
||||||
|
|
||||||
|
for(auto const& [size, value] : sizes)
|
||||||
|
{
|
||||||
|
auto width = getLength(text, size);
|
||||||
|
auto height = getHeight(text, size);
|
||||||
|
|
||||||
|
if(rect.width < width || rect.height < height)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
best_size = size;
|
||||||
|
}
|
||||||
|
return best_size;
|
||||||
|
}
|
||||||
|
|
||||||
void Font::LoadFromStream(std::istream& os)
|
void Font::LoadFromStream(std::istream& os)
|
||||||
{
|
{
|
||||||
json file_data = json::parse(os);
|
json file_data = json::parse(os);
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Rect.hpp"
|
||||||
#include "Glyph.hpp"
|
#include "Glyph.hpp"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
|
||||||
namespace frame::font
|
namespace frame::font
|
||||||
{
|
{
|
||||||
using Glyphs = std::map<char, Glyph>;
|
using Glyphs = std::map<char, Glyph>;
|
||||||
@@ -27,6 +29,8 @@ namespace frame::font
|
|||||||
uint32_t getHeight(std::string_view text, uint32_t size) const;
|
uint32_t getHeight(std::string_view text, uint32_t size) const;
|
||||||
int32_t getMaxYOffset(std::string_view text, uint32_t size) const;
|
int32_t getMaxYOffset(std::string_view text, uint32_t size) const;
|
||||||
|
|
||||||
|
uint32_t getOptimalSize(std::string_view text, Rect rect) const;
|
||||||
|
|
||||||
uint32_t getLineSpacing(uint32_t size) const
|
uint32_t getLineSpacing(uint32_t size) const
|
||||||
{
|
{
|
||||||
return lineSpacing.at(size);
|
return lineSpacing.at(size);
|
||||||
|
|||||||
57
frame/src/font/FontRegistry.cpp
Normal file
57
frame/src/font/FontRegistry.cpp
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
#include "FontRegistry.hpp"
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace frame::font
|
||||||
|
{
|
||||||
|
std::shared_ptr<Font> GetFont(std::string_view name)
|
||||||
|
{
|
||||||
|
return Service::get<FontRegistry>()->Get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadFont(std::string_view name)
|
||||||
|
{
|
||||||
|
return Service::get<FontRegistry>()->Load(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
FontRegistry::FontRegistry()
|
||||||
|
: IService("FontRegistry")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontRegistry::Load(std::string_view name)
|
||||||
|
{
|
||||||
|
if(fonts.find(std::string{name}) != fonts.end())
|
||||||
|
{
|
||||||
|
fmt::print("Font {} allready loaded!\n", name);
|
||||||
|
return true;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
fmt::print("Loading font \"{}\": ", name);
|
||||||
|
auto ptr = Font::LoadFromFile(fmt::format("{}.json", name));
|
||||||
|
|
||||||
|
if(ptr == nullptr)
|
||||||
|
{
|
||||||
|
fmt::print("Error not found!\n");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
fonts[std::string{name}] = ptr;
|
||||||
|
fmt::print("OK\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Font> FontRegistry::Get(std::string_view name)
|
||||||
|
{
|
||||||
|
auto it = fonts.find({std::string{name}});
|
||||||
|
if(it == fonts.end())
|
||||||
|
{
|
||||||
|
if(!Load(name))
|
||||||
|
return nullptr;
|
||||||
|
it = fonts.find({std::string{name}});
|
||||||
|
}
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
} // namespace frame::font
|
||||||
26
frame/src/font/FontRegistry.hpp
Normal file
26
frame/src/font/FontRegistry.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../ServiceLocator.hpp"
|
||||||
|
#include "Font.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace frame::font
|
||||||
|
{
|
||||||
|
|
||||||
|
std::shared_ptr<Font> GetFont(std::string_view name);
|
||||||
|
bool LoadFont(std::string_view name);
|
||||||
|
|
||||||
|
class FontRegistry : public IService
|
||||||
|
{
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<Font>> fonts;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FontRegistry();
|
||||||
|
|
||||||
|
bool Load(std::string_view name);
|
||||||
|
std::shared_ptr<Font> Get(std::string_view name);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame::font
|
||||||
@@ -8,9 +8,10 @@ using namespace std::chrono_literals;
|
|||||||
|
|
||||||
#include "ScreenManager.hpp"
|
#include "ScreenManager.hpp"
|
||||||
#include "display/Display.hpp"
|
#include "display/Display.hpp"
|
||||||
#include "font/Font.hpp"
|
#include "font/FontRegistry.hpp"
|
||||||
#include "render/RenderTarget.hpp"
|
//#include "render/RenderTarget.hpp"
|
||||||
#include "widgets/clock/Analog.hpp"
|
//#include "widgets/clock/Analog.hpp"
|
||||||
|
#include "widgets/WidgetRegistry.hpp"
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
@@ -23,9 +24,13 @@ int main()
|
|||||||
|
|
||||||
display->Init();
|
display->Init();
|
||||||
|
|
||||||
|
frame::font::LoadFont("Fira Code");
|
||||||
|
|
||||||
frame::ScreenManager screen(std::move(display));
|
frame::ScreenManager screen(std::move(display));
|
||||||
|
|
||||||
screen.setRoot(frame::widgets::AnalogClock::Create());
|
auto const& widgets = frame::Service::get<frame::widgets::WidgetRegistry>();
|
||||||
|
|
||||||
|
screen.setRoot(widgets->Create("AnalogClock"));
|
||||||
|
|
||||||
screen.MainLoop();
|
screen.MainLoop();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,12 @@ namespace frame::render
|
|||||||
|| (position.x + current.left) >= root_size.width
|
|| (position.x + current.left) >= root_size.width
|
||||||
|| (position.y + current.top) >= root_size.height)
|
|| (position.y + current.top) >= root_size.height)
|
||||||
return;
|
return;
|
||||||
image.at(position.x + current.left, position.y + current.top) = color;
|
if(!invert)
|
||||||
|
image.at(position.x + current.left, position.y + current.top) =
|
||||||
|
color;
|
||||||
|
else
|
||||||
|
image.at(position.x + current.left, position.y + current.top) ^=
|
||||||
|
color;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderTarget::DrawLine(Vector const& start,
|
void RenderTarget::DrawLine(Vector const& start,
|
||||||
@@ -154,6 +159,15 @@ namespace frame::render
|
|||||||
{BottomRight.x, BottomRight.y - lw});
|
{BottomRight.x, BottomRight.y - lw});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
RenderTarget::DrawRect(Rect const& rect, uint8_t LineWidth, Color color)
|
||||||
|
{
|
||||||
|
DrawRect(Vector{rect.left, rect.top},
|
||||||
|
Vector{rect.left + rect.width, rect.top + rect.height},
|
||||||
|
LineWidth,
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
void RenderTarget::DrawImage(Vector topLeft, Image const& image)
|
void RenderTarget::DrawImage(Vector topLeft, Image const& image)
|
||||||
{
|
{
|
||||||
auto pos = topLeft;
|
auto pos = topLeft;
|
||||||
@@ -204,7 +218,7 @@ namespace frame::render
|
|||||||
auto const lineSpacing = pFont.getLineSpacing(size);
|
auto const lineSpacing = pFont.getLineSpacing(size);
|
||||||
auto const lineSpacing_3 = lineSpacing / 3;
|
auto const lineSpacing_3 = lineSpacing / 3;
|
||||||
|
|
||||||
Vector start{rect.top, rect.left};
|
Vector start{rect.left, rect.top};
|
||||||
auto text_height = pFont.getHeight(pText, size);
|
auto text_height = pFont.getHeight(pText, size);
|
||||||
auto length = pFont.getLength(pText, size);
|
auto length = pFont.getLength(pText, size);
|
||||||
auto y_offset = pFont.getMaxYOffset(pText, size);
|
auto y_offset = pFont.getMaxYOffset(pText, size);
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ namespace frame::render
|
|||||||
Rect root_size;
|
Rect root_size;
|
||||||
std::stack<Rect> Scissor;
|
std::stack<Rect> Scissor;
|
||||||
|
|
||||||
|
bool invert = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RenderTarget(Size size);
|
RenderTarget(Size size);
|
||||||
|
|
||||||
@@ -47,6 +49,8 @@ namespace frame::render
|
|||||||
uint8_t LineWidth,
|
uint8_t LineWidth,
|
||||||
Color color = BLACK);
|
Color color = BLACK);
|
||||||
|
|
||||||
|
void DrawRect(Rect const& rect, uint8_t LineWidth, Color color = BLACK);
|
||||||
|
|
||||||
void DrawImage(Vector topLeft, Image const& image);
|
void DrawImage(Vector topLeft, Image const& image);
|
||||||
|
|
||||||
Vector DrawGlyph(Vector centerLine,
|
Vector DrawGlyph(Vector centerLine,
|
||||||
@@ -81,6 +85,11 @@ namespace frame::render
|
|||||||
void pushViewport(Rect rect);
|
void pushViewport(Rect rect);
|
||||||
void popViewport();
|
void popViewport();
|
||||||
|
|
||||||
|
void setInvert(bool pInvert)
|
||||||
|
{
|
||||||
|
invert = pInvert;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DrawPointsMirrorCircle(Vector const& center,
|
void DrawPointsMirrorCircle(Vector const& center,
|
||||||
Vector const& pos,
|
Vector const& pos,
|
||||||
|
|||||||
22
frame/src/widgets/WidgetRegistry.cpp
Normal file
22
frame/src/widgets/WidgetRegistry.cpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include "WidgetRegistry.hpp"
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
WidgetRegistry::WidgetRegistry()
|
||||||
|
: IService("WidgetRegistry")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::shared_ptr WidgetRegistry::Create(std::string_view name) const
|
||||||
|
{
|
||||||
|
auto it = mWidgets.find(std::string{name});
|
||||||
|
if(it == mWidgets.end())
|
||||||
|
{
|
||||||
|
fmt::print("[ERROR] Widget {} not found!\n", name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return it->second();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
52
frame/src/widgets/WidgetRegistry.hpp
Normal file
52
frame/src/widgets/WidgetRegistry.hpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../ServiceLocator.hpp"
|
||||||
|
#include "Widget.hpp"
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#define REGISTER_WIDGET(TYPE, NAME) \
|
||||||
|
static bool registered = \
|
||||||
|
frame::Service::get<frame::widgets::WidgetRegistry>()->Register<TYPE>( \
|
||||||
|
NAME)
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
class WidgetRegistry : public IService
|
||||||
|
{
|
||||||
|
|
||||||
|
using Creator = std::function<Widget::shared_ptr()>;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, Creator> mWidgets;
|
||||||
|
|
||||||
|
public:
|
||||||
|
WidgetRegistry();
|
||||||
|
|
||||||
|
template<class WIDGET>
|
||||||
|
bool Register(std::string_view name);
|
||||||
|
|
||||||
|
Widget::shared_ptr Create(std::string_view name) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class WIDGET>
|
||||||
|
bool WidgetRegistry::Register(std::string_view name)
|
||||||
|
{
|
||||||
|
auto const name_string = std::string{name};
|
||||||
|
if(mWidgets.find(name_string) != mWidgets.end())
|
||||||
|
{
|
||||||
|
fmt::print("Widget {} already registered!\n", name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWidgets[name_string] = []() -> Widget::shared_ptr {
|
||||||
|
return WIDGET::Create();
|
||||||
|
};
|
||||||
|
|
||||||
|
fmt::print("Widget {} registered!\n", name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
#include "Analog.hpp"
|
#include "Analog.hpp"
|
||||||
|
|
||||||
|
#include "../../font/FontRegistry.hpp"
|
||||||
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <fmt/chrono.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
constexpr double pi = 3.14159;
|
constexpr double pi = 3.14159;
|
||||||
|
|
||||||
|
#include "../WidgetRegistry.hpp"
|
||||||
|
|
||||||
|
REGISTER_WIDGET(frame::widgets::AnalogClock, "AnalogClock");
|
||||||
|
|
||||||
namespace frame::widgets
|
namespace frame::widgets
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -72,8 +79,8 @@ namespace frame::widgets
|
|||||||
auto const min_rad = (min_steps * c_time->tm_min - 90) * pi / 180.f;
|
auto const min_rad = (min_steps * c_time->tm_min - 90) * pi / 180.f;
|
||||||
|
|
||||||
rt.DrawLine(center,
|
rt.DrawLine(center,
|
||||||
{center.x + int32_t(std::cos(min_rad) * radius),
|
{center.x + int32_t(std::cos(min_rad) * radius * 0.8),
|
||||||
center.y + int32_t(std::sin(min_rad) * radius)});
|
center.y + int32_t(std::sin(min_rad) * radius * 0.8)});
|
||||||
|
|
||||||
// Render Pointer Hour
|
// Render Pointer Hour
|
||||||
|
|
||||||
@@ -89,6 +96,37 @@ namespace frame::widgets
|
|||||||
center.y + int32_t(std::sin(hour_rad) * radius * 0.6)});
|
center.y + int32_t(std::sin(hour_rad) * radius * 0.6)});
|
||||||
|
|
||||||
setClear();
|
setClear();
|
||||||
|
|
||||||
|
// Text
|
||||||
|
|
||||||
|
auto font = font::GetFont("Fira Code");
|
||||||
|
|
||||||
|
if(!font)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto text = fmt::format("{:%d.%m.%Y}", fmt::localtime(t));
|
||||||
|
|
||||||
|
auto text_center = center;
|
||||||
|
text_center.y += radius / 2;
|
||||||
|
|
||||||
|
auto const text_height_h = radius / 4;
|
||||||
|
auto const text_width_h = radius / 2;
|
||||||
|
|
||||||
|
Rect text_box{text_center.y - text_height_h,
|
||||||
|
text_center.x - text_width_h,
|
||||||
|
text_width_h * 2,
|
||||||
|
text_height_h * 2};
|
||||||
|
|
||||||
|
auto font_size = font->getOptimalSize(text, text_box);
|
||||||
|
|
||||||
|
rt.setInvert(true);
|
||||||
|
rt.DrawText(text_box,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
font_size,
|
||||||
|
AlignHorizontal::CENTER,
|
||||||
|
AlignVertical::CENTER);
|
||||||
|
rt.setInvert(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace frame::widgets
|
} // namespace frame::widgets
|
||||||
Reference in New Issue
Block a user