Compare commits
32 Commits
4987702f4e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
e6591ce9be
|
|||
|
2a0334ba4b
|
|||
|
9867242098
|
|||
|
bacbf8a95b
|
|||
|
|
c43915a21e
|
||
|
|
9bb296f233
|
||
|
|
4c70f3440d
|
||
|
|
33f79d9f92
|
||
|
|
fe9fc4d69c
|
||
|
|
1772a3baff
|
||
|
|
243bf41e90
|
||
|
|
e1e410561c
|
||
|
|
0fe1509c6c
|
||
|
|
0553927dad
|
||
|
|
df1ce5583b
|
||
|
|
ae18232853
|
||
| 10c8a1fbf7 | |||
| 7fbad9a90d | |||
|
|
cd309c04f2
|
||
| 8a9d0286ef | |||
| 3e342396fe | |||
|
|
83f1872f43
|
||
|
|
420d4c9dc1
|
||
| 02562095d8 | |||
| f09c4700ba | |||
| bd87b1c074 | |||
| 753783bc3a | |||
|
7a8e4f6096
|
|||
|
a9bdbca571
|
|||
|
1aa27e6f96
|
|||
|
afc4244f9d
|
|||
|
183e9cf80c
|
73
.clang-format
Normal file
73
.clang-format
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
AccessModifierOffset: '-4'
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveMacros: 'true'
|
||||||
|
AlignConsecutiveAssignments: 'true'
|
||||||
|
AlignConsecutiveDeclarations: 'false'
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: 'true'
|
||||||
|
AlignTrailingComments: 'true'
|
||||||
|
AllowAllArgumentsOnNextLine: 'false'
|
||||||
|
AllowAllConstructorInitializersOnNextLine: 'false'
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: 'false'
|
||||||
|
AllowShortBlocksOnASingleLine: 'false'
|
||||||
|
AllowShortCaseLabelsOnASingleLine: 'true'
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: 'false'
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: 'false'
|
||||||
|
AlwaysBreakTemplateDeclarations: 'Yes'
|
||||||
|
BinPackArguments: 'false'
|
||||||
|
BinPackParameters: 'false'
|
||||||
|
BreakBeforeBinaryOperators: NonAssignment
|
||||||
|
BreakBeforeTernaryOperators: 'true'
|
||||||
|
BreakConstructorInitializers: BeforeComma
|
||||||
|
BreakInheritanceList: BeforeComma
|
||||||
|
BreakStringLiterals: 'true'
|
||||||
|
CompactNamespaces: 'false'
|
||||||
|
ContinuationIndentWidth: '4'
|
||||||
|
Cpp11BracedListStyle: 'true'
|
||||||
|
FixNamespaceComments: 'true'
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
IndentCaseLabels: 'true'
|
||||||
|
IndentPPDirectives: AfterHash
|
||||||
|
IndentWidth: '4'
|
||||||
|
IndentWrappedFunctionNames: 'true'
|
||||||
|
Language: Cpp
|
||||||
|
MaxEmptyLinesToKeep: '1'
|
||||||
|
NamespaceIndentation: All
|
||||||
|
PointerAlignment: Left
|
||||||
|
ReflowComments: 'true'
|
||||||
|
SortUsingDeclarations: 'true'
|
||||||
|
SpaceAfterCStyleCast: 'false'
|
||||||
|
SpaceAfterLogicalNot: 'false'
|
||||||
|
SpaceAfterTemplateKeyword: 'false'
|
||||||
|
SpaceBeforeAssignmentOperators: 'true'
|
||||||
|
SpaceBeforeCpp11BracedList: 'false'
|
||||||
|
SpaceBeforeCtorInitializerColon: 'true'
|
||||||
|
SpaceBeforeInheritanceColon: 'true'
|
||||||
|
SpaceBeforeParens: Never
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: 'true'
|
||||||
|
SpaceInEmptyParentheses: 'false'
|
||||||
|
SpacesInAngles: 'false'
|
||||||
|
SpacesInCStyleCastParentheses: 'false'
|
||||||
|
SpacesInContainerLiterals: 'false'
|
||||||
|
SpacesInSquareBrackets: 'false'
|
||||||
|
Standard: Auto
|
||||||
|
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: true
|
||||||
|
AfterStruct: true
|
||||||
|
BeforeCatch: true
|
||||||
|
AfterControlStatement: "Always"
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterUnion: true
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
|
||||||
|
|
||||||
38
.gitignore
vendored
38
.gitignore
vendored
@@ -32,37 +32,7 @@
|
|||||||
*.out
|
*.out
|
||||||
*.app
|
*.app
|
||||||
|
|
||||||
build/.ninja_deps
|
build/*
|
||||||
build/.ninja_log
|
.vscode/*
|
||||||
build/build.ninja
|
frame/src/Config.h
|
||||||
build/cmake_install.cmake
|
.editorconfig
|
||||||
build/CMakeCache.txt
|
|
||||||
build/compile_commands.json
|
|
||||||
build/.cmake/api/v1/query/client-vscode/query.json
|
|
||||||
build/.cmake/api/v1/reply/cache-v2-8e3d784e6607879cd18c.json
|
|
||||||
build/.cmake/api/v1/reply/codemodel-v2-97bfd906ef366d86b34b.json
|
|
||||||
build/.cmake/api/v1/reply/index-2022-02-11T18-35-30-0824.json
|
|
||||||
build/.cmake/api/v1/reply/target-frame-Debug-7d0b6524a58d8e907a2f.json
|
|
||||||
build/.cmake/api/v1/reply/toolchains-v1-65972111b21e4388dc41.json
|
|
||||||
build/CMakeFiles/cmake.check_cache
|
|
||||||
build/CMakeFiles/CMakeOutput.log
|
|
||||||
build/CMakeFiles/rules.ninja
|
|
||||||
build/CMakeFiles/TargetDirectories.txt
|
|
||||||
build/CMakeFiles/3.20.21032501-MSVC_2/CMakeCCompiler.cmake
|
|
||||||
build/CMakeFiles/3.20.21032501-MSVC_2/CMakeCXXCompiler.cmake
|
|
||||||
build/CMakeFiles/3.20.21032501-MSVC_2/CMakeDetermineCompilerABI_C.bin
|
|
||||||
build/CMakeFiles/3.20.21032501-MSVC_2/CMakeDetermineCompilerABI_CXX.bin
|
|
||||||
build/CMakeFiles/3.20.21032501-MSVC_2/CMakeRCCompiler.cmake
|
|
||||||
build/CMakeFiles/3.20.21032501-MSVC_2/CMakeSystem.cmake
|
|
||||||
build/CMakeFiles/3.20.21032501-MSVC_2/CompilerIdC/CMakeCCompilerId.c
|
|
||||||
build/CMakeFiles/3.20.21032501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.cpp
|
|
||||||
build/CMakeFiles/ShowIncludes/foo.h
|
|
||||||
build/CMakeFiles/ShowIncludes/main.c
|
|
||||||
build/frame/cmake_install.cmake
|
|
||||||
build/frame/frame.ilk
|
|
||||||
build/frame/frame.pdb
|
|
||||||
build/frame/CMakeFiles/frame.dir/embed.manifest
|
|
||||||
build/frame/CMakeFiles/frame.dir/intermediate.manifest
|
|
||||||
build/frame/CMakeFiles/frame.dir/manifest.rc
|
|
||||||
build/frame/CMakeFiles/frame.dir/manifest.res
|
|
||||||
build/frame/CMakeFiles/frame.dir/vc140.pdb
|
|
||||||
|
|||||||
@@ -1,8 +1,37 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
|
||||||
|
if (BUILD_VIRTUAL_DISPLAY)
|
||||||
|
set(VCPKG_MANIFEST_FEATURES virtual)
|
||||||
|
endif(BUILD_VIRTUAL_DISPLAY)
|
||||||
|
|
||||||
|
|
||||||
project(Frame)
|
project(Frame)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
|
option(BUILD_EPD
|
||||||
|
"Build EPD Display"
|
||||||
|
OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(fmt CONFIG REQUIRED)
|
||||||
|
find_package(nlohmann_json CONFIG REQUIRED)
|
||||||
|
|
||||||
|
option(BUILD_VIRTUAL_DISPLAY
|
||||||
|
"Build virtual sfml based display"
|
||||||
|
OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
if (BUILD_EPD)
|
||||||
|
add_subdirectory(bcm2835)
|
||||||
|
add_subdirectory(waveshare)
|
||||||
|
endif (BUILD_EPD)
|
||||||
|
|
||||||
|
if (BUILD_VIRTUAL_DISPLAY)
|
||||||
|
find_package(SFML COMPONENTS system window graphics CONFIG REQUIRED)
|
||||||
|
add_subdirectory(fontConverter)
|
||||||
|
endif(BUILD_VIRTUAL_DISPLAY)
|
||||||
|
|
||||||
add_subdirectory(frame)
|
add_subdirectory(frame)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
4
bcm2835/CMakeLists.txt
Normal file
4
bcm2835/CMakeLists.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
|
add_library(bcm2835 STATIC include/bcm2835.h src/bcm2835.c)
|
||||||
|
target_include_directories(bcm2835 PUBLIC include/)
|
||||||
2188
bcm2835/include/bcm2835.h
Normal file
2188
bcm2835/include/bcm2835.h
Normal file
File diff suppressed because it is too large
Load Diff
2243
bcm2835/src/bcm2835.c
Normal file
2243
bcm2835/src/bcm2835.c
Normal file
File diff suppressed because it is too large
Load Diff
10
fontConverter/CMakeLists.txt
Normal file
10
fontConverter/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
add_executable(font src/main.cpp)
|
||||||
|
target_link_libraries(font PUBLIC
|
||||||
|
sfml-system
|
||||||
|
sfml-window
|
||||||
|
sfml-graphics
|
||||||
|
fmt::fmt
|
||||||
|
nlohmann_json::nlohmann_json
|
||||||
|
)
|
||||||
102
fontConverter/src/main.cpp
Normal file
102
fontConverter/src/main.cpp
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <sfml/Graphics.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
void PrintGlyph(sf::Font const& font, sf::Glyph const& g, unsigned int size);
|
||||||
|
|
||||||
|
void ExportSize(json& out, uint32_t size, sf::Font& font);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
sf::Font font;
|
||||||
|
|
||||||
|
auto ok =
|
||||||
|
font.loadFromFile(R"(C:\Users\s-har\Downloads\FiraCode-Regular.ttf)");
|
||||||
|
|
||||||
|
fmt::print("Loaded {}\n", ok);
|
||||||
|
|
||||||
|
fmt::print("{}\n", font.getInfo().family);
|
||||||
|
fmt::print("Line Spacing: {}\n", font.getLineSpacing(14));
|
||||||
|
|
||||||
|
json export_font;
|
||||||
|
export_font["name"] = font.getInfo().family;
|
||||||
|
export_font["sizes"] = json::object();
|
||||||
|
|
||||||
|
std::vector<uint32_t> sizes =
|
||||||
|
{12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 35, 40, 100, 250};
|
||||||
|
|
||||||
|
for(auto& size : sizes)
|
||||||
|
{
|
||||||
|
fmt::print("Export: {}\n", size);
|
||||||
|
ExportSize(export_font["sizes"][fmt::format("{}", size)], size, font);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fstream out(fmt::format("{}.json", font.getInfo().family),
|
||||||
|
std::ios::out);
|
||||||
|
out << export_font.dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExportSize(json& out, uint32_t size, sf::Font& font)
|
||||||
|
{
|
||||||
|
std::map<char, sf::Glyph> glyphs;
|
||||||
|
|
||||||
|
for(uint8_t c = 32; c <= 126; ++c)
|
||||||
|
{
|
||||||
|
glyphs[(char)c] = font.getGlyph(c, size, false);
|
||||||
|
}
|
||||||
|
auto font_image = font.getTexture(size).copyToImage();
|
||||||
|
|
||||||
|
out["LineSpacing"] = font.getLineSpacing(size);
|
||||||
|
auto& Glyphs = out["Glyphs"];
|
||||||
|
|
||||||
|
for(auto&& [c, g] : glyphs)
|
||||||
|
{
|
||||||
|
auto& current = Glyphs[std::string{c}];
|
||||||
|
|
||||||
|
current["advance"] = g.advance;
|
||||||
|
current["x_offset"] = g.bounds.left;
|
||||||
|
current["y_offset"] = g.bounds.top;
|
||||||
|
current["width"] = g.bounds.width;
|
||||||
|
current["height"] = g.bounds.height;
|
||||||
|
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
for(int y = 0; y < (int)g.bounds.height; ++y)
|
||||||
|
{
|
||||||
|
for(int x = 0; x < (int)g.bounds.width; ++x)
|
||||||
|
{
|
||||||
|
auto c = font_image.getPixel(g.textureRect.left + x,
|
||||||
|
g.textureRect.top + y);
|
||||||
|
|
||||||
|
data.push_back(c.a > 100 ? 1 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
current["data"] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintGlyph(sf::Font const& font, sf::Glyph const& g, unsigned int size)
|
||||||
|
{
|
||||||
|
auto font_image = font.getTexture(size).copyToImage();
|
||||||
|
for(int y = 0; y < (int)g.bounds.height; ++y)
|
||||||
|
{
|
||||||
|
for(int x = 0; x < (int)g.bounds.width; ++x)
|
||||||
|
{
|
||||||
|
auto c = font_image.getPixel(g.textureRect.left + x,
|
||||||
|
g.textureRect.top + y);
|
||||||
|
|
||||||
|
if(c.a > 100)
|
||||||
|
{
|
||||||
|
fmt::print("X");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
fmt::print(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt::print("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,92 @@
|
|||||||
|
|
||||||
set(target frame)
|
set(target frame)
|
||||||
|
|
||||||
|
configure_file (
|
||||||
|
"${PROJECT_SOURCE_DIR}/frame/src/BuildConfig.h.in"
|
||||||
|
"${PROJECT_SOURCE_DIR}/frame/src/BuildConfig.h"
|
||||||
|
)
|
||||||
|
|
||||||
add_executable(${target} main.cpp)
|
set(src
|
||||||
|
src/main.cpp
|
||||||
|
|
||||||
|
src/Config.hpp
|
||||||
|
src/Config.cpp
|
||||||
|
|
||||||
|
src/Size.hpp
|
||||||
|
src/Vector.hpp
|
||||||
|
src/Rect.hpp
|
||||||
|
|
||||||
|
src/Image.hpp
|
||||||
|
src/Image.cpp
|
||||||
|
|
||||||
|
src/ScreenManager.hpp
|
||||||
|
src/ScreenManager.cpp
|
||||||
|
|
||||||
|
src/ServiceLocator.hpp
|
||||||
|
src/ServiceLocator.cpp
|
||||||
|
|
||||||
|
src/display/IDisplay.hpp
|
||||||
|
src/display/Display.hpp
|
||||||
|
src/display/Display.cpp
|
||||||
|
|
||||||
|
src/render/RenderTarget.hpp
|
||||||
|
src/render/RenderTarget.cpp
|
||||||
|
|
||||||
|
src/font/Font.hpp
|
||||||
|
src/font/Font.cpp
|
||||||
|
src/font/Glyph.hpp
|
||||||
|
src/font/Glyph.cpp
|
||||||
|
src/font/FontRegistry.hpp
|
||||||
|
src/font/FontRegistry.cpp
|
||||||
|
|
||||||
|
|
||||||
|
src/widgets/Widget.hpp
|
||||||
|
src/widgets/Widget.cpp
|
||||||
|
src/widgets/ContainerWidget.hpp
|
||||||
|
src/widgets/ContainerWidget.cpp
|
||||||
|
src/widgets/WidgetRegistry.hpp
|
||||||
|
src/widgets/WidgetRegistry.cpp
|
||||||
|
src/widgets/clock/Digital.hpp
|
||||||
|
src/widgets/clock/Digital.cpp
|
||||||
|
src/widgets/clock/Analog.hpp
|
||||||
|
src/widgets/clock/Analog.cpp
|
||||||
|
src/widgets/clock/Date.hpp
|
||||||
|
src/widgets/clock/Date.cpp
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
if (BUILD_EPD)
|
||||||
|
set(src ${src}
|
||||||
|
src/display/EPD_7in5_V2.hpp
|
||||||
|
src/display/EPD_7in5_V2.cpp
|
||||||
|
)
|
||||||
|
endif (BUILD_EPD)
|
||||||
|
|
||||||
|
if (BUILD_VIRTUAL_DISPLAY)
|
||||||
|
set(src ${src}
|
||||||
|
src/display/VirtualDisplay.hpp
|
||||||
|
src/display/VirtualDisplay.cpp
|
||||||
|
)
|
||||||
|
endif (BUILD_VIRTUAL_DISPLAY)
|
||||||
|
|
||||||
|
add_executable(${target} ${src})
|
||||||
|
target_link_libraries(${target} PRIVATE
|
||||||
|
fmt::fmt
|
||||||
|
nlohmann_json::nlohmann_json
|
||||||
|
)
|
||||||
|
|
||||||
|
if (BUILD_EPD)
|
||||||
|
target_link_libraries(${target} PRIVATE
|
||||||
|
waveshare
|
||||||
|
)
|
||||||
|
endif (BUILD_EPD)
|
||||||
|
|
||||||
|
if (BUILD_VIRTUAL_DISPLAY)
|
||||||
|
target_link_libraries(${target} PRIVATE
|
||||||
|
sfml-system
|
||||||
|
sfml-window
|
||||||
|
sfml-graphics
|
||||||
|
fmt::fmt
|
||||||
|
nlohmann_json::nlohmann_json
|
||||||
|
)
|
||||||
|
endif(BUILD_VIRTUAL_DISPLAY)
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
std::cout << "Hallo Welt" << std::endl;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
2
frame/src/BuildConfig.h
Normal file
2
frame/src/BuildConfig.h
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#define BUILD_VIRTUAL_DISPLAY
|
||||||
|
/* #undef BUILD_EPD */
|
||||||
2
frame/src/BuildConfig.h.in
Normal file
2
frame/src/BuildConfig.h.in
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
#cmakedefine BUILD_VIRTUAL_DISPLAY
|
||||||
|
#cmakedefine BUILD_EPD
|
||||||
8
frame/src/Color.hpp
Normal file
8
frame/src/Color.hpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
enum Color : uint32_t { WHITE = 0, BLACK = 0xFF };
|
||||||
|
}
|
||||||
89
frame/src/Config.cpp
Normal file
89
frame/src/Config.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include "Config.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
#define PROPERTY(str, member) str.member = j.value(#member, str.member)
|
||||||
|
#define PROPERTY_OPT(str, member, type) \
|
||||||
|
str.member = \
|
||||||
|
j.contains(#member) ? j[#member].get<type>() : std::optional<type>{};
|
||||||
|
|
||||||
|
#define OBJ(str, mem) \
|
||||||
|
{ \
|
||||||
|
# mem, str.mem \
|
||||||
|
}
|
||||||
|
|
||||||
|
Config Config::Load()
|
||||||
|
{
|
||||||
|
fs::path const config_path{"config.json"};
|
||||||
|
|
||||||
|
if(fs::is_regular_file(config_path))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::fstream file(config_path.string(), std::ios::in);
|
||||||
|
|
||||||
|
return json::parse(file);
|
||||||
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
fmt::print("Error: {}\n", e.what());
|
||||||
|
|
||||||
|
// TODO: Create Error Display Widget
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::print("[INFO] Creating config file\n");
|
||||||
|
Config config;
|
||||||
|
std::fstream file(config_path.string(), std::ios::out);
|
||||||
|
file << json(config).dump();
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
// == to json ==
|
||||||
|
void to_json(json& j, Config const& c)
|
||||||
|
{
|
||||||
|
j = {OBJ(c, font), OBJ(c, root)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void to_json(json& j, FontConfig const& fc)
|
||||||
|
{
|
||||||
|
j = {OBJ(fc, base_path), OBJ(fc, fonts)};
|
||||||
|
}
|
||||||
|
|
||||||
|
void to_json(json& j, WidgetConfig const& w)
|
||||||
|
{
|
||||||
|
j = {OBJ(w, name), OBJ(w, parameters), OBJ(w, widgets)};
|
||||||
|
|
||||||
|
if(w.slot)
|
||||||
|
{
|
||||||
|
j["slot"] = w.slot.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// == from json ==
|
||||||
|
void from_json(json const& j, Config& c)
|
||||||
|
{
|
||||||
|
PROPERTY(c, font);
|
||||||
|
PROPERTY(c, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
void from_json(json const& j, FontConfig& fc)
|
||||||
|
{
|
||||||
|
PROPERTY(fc, base_path);
|
||||||
|
PROPERTY(fc, fonts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void from_json(json const& j, WidgetConfig& w)
|
||||||
|
{
|
||||||
|
PROPERTY(w, name);
|
||||||
|
PROPERTY(w, parameters);
|
||||||
|
PROPERTY(w, widgets);
|
||||||
|
PROPERTY_OPT(w, slot, int);
|
||||||
|
}
|
||||||
38
frame/src/Config.hpp
Normal file
38
frame/src/Config.hpp
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
struct FontConfig
|
||||||
|
{
|
||||||
|
std::string base_path = "fonts/";
|
||||||
|
std::unordered_map<std::string, std::string> fonts{
|
||||||
|
{"Fira Code", "FiraCode.json"}};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WidgetConfig
|
||||||
|
{
|
||||||
|
std::string name = "DigitalClock";
|
||||||
|
std::unordered_map<std::string, json> parameters = {};
|
||||||
|
std::vector<WidgetConfig> widgets = {};
|
||||||
|
std::optional<int> slot = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Config
|
||||||
|
{
|
||||||
|
FontConfig font{};
|
||||||
|
WidgetConfig root{};
|
||||||
|
|
||||||
|
static Config Load();
|
||||||
|
};
|
||||||
|
|
||||||
|
void to_json(json& j, Config const& c);
|
||||||
|
void to_json(json& j, FontConfig const& fc);
|
||||||
|
void to_json(json& j, WidgetConfig const& w);
|
||||||
|
|
||||||
|
void from_json(json const& j, Config& c);
|
||||||
|
void from_json(json const& j, FontConfig& fc);
|
||||||
|
void from_json(json const& j, WidgetConfig& w);
|
||||||
60
frame/src/Image.cpp
Normal file
60
frame/src/Image.cpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include "Image.hpp"
|
||||||
|
|
||||||
|
#include "Color.hpp"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
|
||||||
|
Image::Image(uint32_t pWidth, uint32_t pHeight)
|
||||||
|
: mWidth(pWidth)
|
||||||
|
, mHeight(pHeight)
|
||||||
|
, mBuffer(mWidth * mHeight, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Image::Image(Size size)
|
||||||
|
: Image(size.width, size.height)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::Create(uint32_t pWidth, uint32_t pHeight)
|
||||||
|
{
|
||||||
|
mWidth = pWidth;
|
||||||
|
mHeight = pHeight;
|
||||||
|
|
||||||
|
mBuffer.clear();
|
||||||
|
mBuffer.resize(mWidth * mHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t& Image::at(uint32_t x, uint32_t y)
|
||||||
|
{
|
||||||
|
return mBuffer.at(toInternal(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t const& Image::at(uint32_t x, uint32_t y) const
|
||||||
|
{
|
||||||
|
return mBuffer.at(toInternal(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::Clear(Color color)
|
||||||
|
{
|
||||||
|
memset(mBuffer.data(), color, mBuffer.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::operator=(Image const& image)
|
||||||
|
{
|
||||||
|
mHeight = image.mHeight;
|
||||||
|
mWidth = image.mWidth;
|
||||||
|
mBuffer = image.mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Image::toInternal(uint32_t x, uint32_t y) const
|
||||||
|
{
|
||||||
|
return x + mWidth * y;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame
|
||||||
47
frame/src/Image.hpp
Normal file
47
frame/src/Image.hpp
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Color.hpp"
|
||||||
|
#include "Size.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
|
||||||
|
class Image
|
||||||
|
{
|
||||||
|
uint32_t mWidth;
|
||||||
|
uint32_t mHeight;
|
||||||
|
std::vector<uint8_t> mBuffer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Image() = default;
|
||||||
|
Image(uint32_t pWidth, uint32_t pHeight);
|
||||||
|
Image(Size size);
|
||||||
|
Image(Image const&) = default;
|
||||||
|
Image(Image&&) = default;
|
||||||
|
|
||||||
|
void Create(uint32_t pWidth, uint32_t pHeight);
|
||||||
|
|
||||||
|
uint8_t& at(uint32_t x, uint32_t y);
|
||||||
|
uint8_t const& at(uint32_t x, uint32_t y) const;
|
||||||
|
|
||||||
|
void Clear(Color color);
|
||||||
|
|
||||||
|
auto getWidth() const
|
||||||
|
{
|
||||||
|
return mWidth;
|
||||||
|
}
|
||||||
|
auto getHeight() const
|
||||||
|
{
|
||||||
|
return mHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(Image const& image);
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t toInternal(uint32_t x, uint32_t y) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame
|
||||||
15
frame/src/Rect.hpp
Normal file
15
frame/src/Rect.hpp
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Rect
|
||||||
|
{
|
||||||
|
int32_t top;
|
||||||
|
int32_t left;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
};
|
||||||
|
} // namespace frame
|
||||||
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->setSize(mDisplay->getSize());
|
||||||
|
mRoot->Render(mRenderTarget);
|
||||||
|
|
||||||
|
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
|
||||||
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
|
||||||
18
frame/src/Size.hpp
Normal file
18
frame/src/Size.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
struct Size
|
||||||
|
{
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Size operator/(Size const& size, int div)
|
||||||
|
{
|
||||||
|
return {size.width / div, size.height / div};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame
|
||||||
67
frame/src/Vector.hpp
Normal file
67
frame/src/Vector.hpp
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Size.hpp"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
struct Vector
|
||||||
|
{
|
||||||
|
int32_t x;
|
||||||
|
int32_t y;
|
||||||
|
|
||||||
|
Vector() = default;
|
||||||
|
Vector(int32_t x, int32_t y)
|
||||||
|
: x(x)
|
||||||
|
, y(y)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector(Size const& size)
|
||||||
|
: x(size.width)
|
||||||
|
, y(size.height)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(Size const& size)
|
||||||
|
{
|
||||||
|
x = size.width;
|
||||||
|
y = size.height;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline bool operator==(Vector const& a, Vector const& b)
|
||||||
|
{
|
||||||
|
return a.x == b.x && a.y == b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator!=(Vector const& a, Vector const& b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector& operator+=(Vector& a, Vector const& b)
|
||||||
|
{
|
||||||
|
a.x += b.x;
|
||||||
|
a.y += b.y;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector& operator-=(Vector& a, Vector const& b)
|
||||||
|
{
|
||||||
|
a.x -= b.x;
|
||||||
|
a.y -= b.y;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, Vector const& v)
|
||||||
|
{
|
||||||
|
return os << "x: " << v.x << " y: " << v.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector operator+(Vector const& a, Vector const& b)
|
||||||
|
{
|
||||||
|
return {a.x + b.x, a.y + b.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame
|
||||||
27
frame/src/display/Display.cpp
Normal file
27
frame/src/display/Display.cpp
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
#include "Display.hpp"
|
||||||
|
|
||||||
|
#include "../BuildConfig.h"
|
||||||
|
|
||||||
|
#ifdef BUILD_EPD
|
||||||
|
# include "EPD_7in5_V2.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BUILD_VIRTUAL_DISPLAY
|
||||||
|
# include "VirtualDisplay.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace frame::display
|
||||||
|
{
|
||||||
|
std::unique_ptr<IDisplay> Create()
|
||||||
|
{
|
||||||
|
#ifdef BUILD_EPD
|
||||||
|
return std::make_unique<EPD_7in5_V2>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BUILD_VIRTUAL_DISPLAY
|
||||||
|
return std::make_unique<VirtualDisplay>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
} // namespace frame::display
|
||||||
13
frame/src/display/Display.hpp
Normal file
13
frame/src/display/Display.hpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IDisplay.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
|
||||||
|
namespace frame::display
|
||||||
|
{
|
||||||
|
|
||||||
|
std::unique_ptr<IDisplay> Create();
|
||||||
|
|
||||||
|
}
|
||||||
74
frame/src/display/EPD_7in5_V2.cpp
Normal file
74
frame/src/display/EPD_7in5_V2.cpp
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "EPD_7in5_V2.hpp"
|
||||||
|
|
||||||
|
#include <EPD_7in5_V2.h>
|
||||||
|
|
||||||
|
namespace frame::display
|
||||||
|
{
|
||||||
|
constexpr uint32_t mWidth = EPD_7IN5_V2_WIDTH;
|
||||||
|
constexpr uint32_t mHeight = EPD_7IN5_V2_HEIGHT;
|
||||||
|
|
||||||
|
EPD_7in5_V2::EPD_7in5_V2()
|
||||||
|
: IDisplay("EPD_7in5_V2", {mWidth, mHeight})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
EPD_7in5_V2::~EPD_7in5_V2()
|
||||||
|
{
|
||||||
|
Sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EPD_7in5_V2::Init()
|
||||||
|
{
|
||||||
|
if(DEV_Module_Init()!=0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return EPD_7IN5_V2_Init() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EPD_7in5_V2::Clear(Color color)
|
||||||
|
{
|
||||||
|
if(color == Color::WHITE)
|
||||||
|
{
|
||||||
|
EPD_7IN5_V2_Clear();
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
EPD_7IN5_V2_ClearBlack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EPD_7in5_V2::Display(Image const& image, bool invert)
|
||||||
|
{
|
||||||
|
constexpr auto bytes_width = mWidth / 8;
|
||||||
|
std::vector<uint8_t> data(bytes_width * mHeight);
|
||||||
|
|
||||||
|
uint8_t bit_counter;
|
||||||
|
|
||||||
|
for(auto y = 0; y < mHeight; ++y)
|
||||||
|
{
|
||||||
|
for(auto x = 0; x < bytes_width; ++x)
|
||||||
|
{
|
||||||
|
uint8_t byte = 0xFF;
|
||||||
|
for(auto bit = 0; bit < 8; ++bit)
|
||||||
|
{
|
||||||
|
byte <<= 1;
|
||||||
|
|
||||||
|
if(image.at(x * 8 + bit, y) > 265 / 2)
|
||||||
|
{
|
||||||
|
byte ^= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
byte = ~ byte;
|
||||||
|
|
||||||
|
data[bytes_width * y + x] = byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EPD_7IN5_V2_Display(data.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void EPD_7in5_V2::Sleep()
|
||||||
|
{
|
||||||
|
EPD_7IN5_V2_Sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::display
|
||||||
23
frame/src/display/EPD_7in5_V2.hpp
Normal file
23
frame/src/display/EPD_7in5_V2.hpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "IDisplay.hpp"
|
||||||
|
|
||||||
|
namespace frame::display
|
||||||
|
{
|
||||||
|
|
||||||
|
class EPD_7in5_V2 : public IDisplay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EPD_7in5_V2();
|
||||||
|
~EPD_7in5_V2();
|
||||||
|
|
||||||
|
bool Init() override;
|
||||||
|
|
||||||
|
void Clear(Color color) override;
|
||||||
|
|
||||||
|
void Display(Image const& image, bool invert = false) override;
|
||||||
|
|
||||||
|
void Sleep() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame::display
|
||||||
49
frame/src/display/IDisplay.hpp
Normal file
49
frame/src/display/IDisplay.hpp
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../Image.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace frame::display
|
||||||
|
{
|
||||||
|
enum class Color { WHITE, BLACK };
|
||||||
|
|
||||||
|
class IDisplay
|
||||||
|
{
|
||||||
|
std::string mName;
|
||||||
|
Size mSize;
|
||||||
|
|
||||||
|
bool mIsOpen = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
IDisplay(std::string_view pName, Size pSize)
|
||||||
|
: mName(pName)
|
||||||
|
, mSize(pSize){};
|
||||||
|
virtual ~IDisplay() = default;
|
||||||
|
|
||||||
|
virtual bool Init() = 0;
|
||||||
|
|
||||||
|
virtual void Clear(Color color) = 0;
|
||||||
|
|
||||||
|
virtual void Display(Image const& image, bool invert = false) = 0;
|
||||||
|
|
||||||
|
virtual void Sleep() = 0;
|
||||||
|
|
||||||
|
virtual void Update() {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Size const& getSize()
|
||||||
|
{
|
||||||
|
return mSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isOpen() const
|
||||||
|
{
|
||||||
|
return mIsOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close()
|
||||||
|
{
|
||||||
|
mIsOpen = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace frame::display
|
||||||
77
frame/src/display/VirtualDisplay.cpp
Normal file
77
frame/src/display/VirtualDisplay.cpp
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
#include "VirtualDisplay.hpp"
|
||||||
|
|
||||||
|
#include "../size.hpp"
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
namespace frame::display
|
||||||
|
{
|
||||||
|
constexpr std::string_view title = "Virtual Display";
|
||||||
|
|
||||||
|
VirtualDisplay::VirtualDisplay()
|
||||||
|
: IDisplay(title, {800, 480})
|
||||||
|
, size(getSize())
|
||||||
|
, window(sf::VideoMode(size.width, size.height), std::string(title))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VirtualDisplay::Init()
|
||||||
|
{
|
||||||
|
renderTarget.create(size.width, size.height, sf::Color::White);
|
||||||
|
Draw();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDisplay::Clear(Color color)
|
||||||
|
{
|
||||||
|
renderTarget.create(size.width,
|
||||||
|
size.height,
|
||||||
|
color == Color::WHITE ? sf::Color::White
|
||||||
|
: sf::Color::Black);
|
||||||
|
Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDisplay::Display(Image const& image, bool invert)
|
||||||
|
{
|
||||||
|
|
||||||
|
for(auto y = 0; y < size.height; ++y)
|
||||||
|
{
|
||||||
|
for(auto x = 0; x < size.width; ++x)
|
||||||
|
{
|
||||||
|
renderTarget.setPixel(x,
|
||||||
|
y,
|
||||||
|
(image.at(x, y) > 265 / 2)
|
||||||
|
? sf::Color::Black
|
||||||
|
: sf::Color::White);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDisplay::Sleep() {}
|
||||||
|
|
||||||
|
void VirtualDisplay::Update()
|
||||||
|
{
|
||||||
|
sf::Event ev;
|
||||||
|
while(window.pollEvent(ev))
|
||||||
|
{
|
||||||
|
if(ev.type == sf::Event::Closed)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualDisplay::Draw()
|
||||||
|
{
|
||||||
|
sf::Sprite sprite;
|
||||||
|
sf::Texture texture;
|
||||||
|
texture.loadFromImage(renderTarget);
|
||||||
|
sprite.setTexture(texture);
|
||||||
|
|
||||||
|
window.clear(sf::Color::White);
|
||||||
|
window.draw(sprite);
|
||||||
|
window.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace frame::display
|
||||||
33
frame/src/display/VirtualDisplay.hpp
Normal file
33
frame/src/display/VirtualDisplay.hpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "IDisplay.hpp"
|
||||||
|
|
||||||
|
#include <sfml/Graphics.hpp>
|
||||||
|
|
||||||
|
namespace frame::display
|
||||||
|
{
|
||||||
|
|
||||||
|
class VirtualDisplay : public IDisplay
|
||||||
|
{
|
||||||
|
Size size;
|
||||||
|
sf::RenderWindow window;
|
||||||
|
sf::Image renderTarget;
|
||||||
|
|
||||||
|
public:
|
||||||
|
VirtualDisplay();
|
||||||
|
~VirtualDisplay() = default;
|
||||||
|
|
||||||
|
bool Init() override;
|
||||||
|
|
||||||
|
void Clear(Color color) override;
|
||||||
|
|
||||||
|
void Display(Image const& image, bool invert = false) override;
|
||||||
|
|
||||||
|
void Sleep() override;
|
||||||
|
|
||||||
|
void Update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame::display
|
||||||
107
frame/src/font/Font.cpp
Normal file
107
frame/src/font/Font.cpp
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#include "Font.hpp"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
namespace frame::font
|
||||||
|
{
|
||||||
|
|
||||||
|
std::shared_ptr<Font> Font::LoadFromFile(std::string_view file)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::fstream file_data(std::string{file}, std::ios::in);
|
||||||
|
|
||||||
|
auto out = std::make_shared<Font>();
|
||||||
|
out->LoadFromStream(file_data);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
catch(std::exception const& e)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Glyph const& Font::getGlyph(uint32_t size, char c) const
|
||||||
|
{
|
||||||
|
return sizes.at(size).at(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Font::getLength(std::string_view text, uint32_t size) const
|
||||||
|
{
|
||||||
|
uint32_t length = 0;
|
||||||
|
|
||||||
|
for(auto c : text)
|
||||||
|
{
|
||||||
|
auto const& g = getGlyph(size, c);
|
||||||
|
length += g.advance;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Font::getHeight(std::string_view text, uint32_t size) const
|
||||||
|
{
|
||||||
|
uint32_t height = 0;
|
||||||
|
|
||||||
|
for(auto c : text)
|
||||||
|
{
|
||||||
|
auto const& g = getGlyph(size, c);
|
||||||
|
height = std::max((uint32_t)g.height, height);
|
||||||
|
}
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t Font::getMaxYOffset(std::string_view text, uint32_t size) const
|
||||||
|
{
|
||||||
|
int32_t y_offset = 0;
|
||||||
|
|
||||||
|
for(auto c : text)
|
||||||
|
{
|
||||||
|
auto const& g = getGlyph(size, c);
|
||||||
|
y_offset = std::min(g.y_offset, 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)
|
||||||
|
{
|
||||||
|
json file_data = json::parse(os);
|
||||||
|
|
||||||
|
name = file_data["name"];
|
||||||
|
|
||||||
|
for(auto& [key, el] : file_data["sizes"].items())
|
||||||
|
{
|
||||||
|
auto size = std::atoi(key.c_str());
|
||||||
|
|
||||||
|
Glyphs curren_glyphs;
|
||||||
|
lineSpacing[size] = el["LineSpacing"];
|
||||||
|
|
||||||
|
for(auto& [glyph_c, glyph_d] : el["Glyphs"].items())
|
||||||
|
{
|
||||||
|
curren_glyphs[glyph_c[0]] = std::move(Glyph{glyph_d});
|
||||||
|
}
|
||||||
|
|
||||||
|
sizes[size] = std::move(curren_glyphs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::font
|
||||||
42
frame/src/font/Font.hpp
Normal file
42
frame/src/font/Font.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Rect.hpp"
|
||||||
|
#include "Glyph.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
|
||||||
|
namespace frame::font
|
||||||
|
{
|
||||||
|
using Glyphs = std::map<char, Glyph>;
|
||||||
|
using LineSpacing = std::map<uint32_t, uint32_t>;
|
||||||
|
|
||||||
|
class Font
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::map<uint32_t, Glyphs> sizes;
|
||||||
|
LineSpacing lineSpacing;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Font() = default;
|
||||||
|
static std::shared_ptr<Font> LoadFromFile(std::string_view file);
|
||||||
|
|
||||||
|
Glyph const& getGlyph(uint32_t size, char c) const;
|
||||||
|
|
||||||
|
uint32_t getLength(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;
|
||||||
|
|
||||||
|
uint32_t getOptimalSize(std::string_view text, Rect rect) const;
|
||||||
|
|
||||||
|
uint32_t getLineSpacing(uint32_t size) const
|
||||||
|
{
|
||||||
|
return lineSpacing.at(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void LoadFromStream(std::istream& os);
|
||||||
|
};
|
||||||
|
} // namespace frame::font
|
||||||
98
frame/src/font/FontRegistry.cpp
Normal file
98
frame/src/font/FontRegistry.cpp
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
#include "FontRegistry.hpp"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
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& LocateRegistry()
|
||||||
|
{
|
||||||
|
return *Service::get<FontRegistry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
FontRegistry::FontRegistry()
|
||||||
|
: IService("FontRegistry")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FontRegistry::LoadFromConfig(FontConfig const& config)
|
||||||
|
{
|
||||||
|
fs::path base{config.base_path};
|
||||||
|
|
||||||
|
for(auto const& [name, file] : config.fonts)
|
||||||
|
{
|
||||||
|
Load(name, (base / file).string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FontRegistry::Load(std::string_view name, std::string_view path)
|
||||||
|
{
|
||||||
|
if(fonts.find(std::string{name}) != fonts.end())
|
||||||
|
{
|
||||||
|
fmt::print("Font {} allready loaded!\n", name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt::print("Loading font \"{}\": ", name);
|
||||||
|
auto ptr = Font::LoadFromFile(path);
|
||||||
|
|
||||||
|
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
|
||||||
31
frame/src/font/FontRegistry.hpp
Normal file
31
frame/src/font/FontRegistry.hpp
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Config.hpp"
|
||||||
|
#include "../ServiceLocator.hpp"
|
||||||
|
#include "Font.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace frame::font
|
||||||
|
{
|
||||||
|
class FontRegistry;
|
||||||
|
|
||||||
|
std::shared_ptr<Font> GetFont(std::string_view name);
|
||||||
|
bool LoadFont(std::string_view name);
|
||||||
|
FontRegistry& LocateRegistry();
|
||||||
|
|
||||||
|
class FontRegistry : public IService
|
||||||
|
{
|
||||||
|
std::unordered_map<std::string, std::shared_ptr<Font>> fonts;
|
||||||
|
|
||||||
|
public:
|
||||||
|
FontRegistry();
|
||||||
|
|
||||||
|
void LoadFromConfig(FontConfig const& config);
|
||||||
|
bool Load(std::string_view name);
|
||||||
|
bool Load(std::string_view name, std::string_view path);
|
||||||
|
std::shared_ptr<Font> Get(std::string_view name);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame::font
|
||||||
39
frame/src/font/Glyph.cpp
Normal file
39
frame/src/font/Glyph.cpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include "Glyph.hpp"
|
||||||
|
|
||||||
|
namespace frame::font
|
||||||
|
{
|
||||||
|
Glyph::Glyph(json const& data)
|
||||||
|
{
|
||||||
|
height = data["height"];
|
||||||
|
width = data["width"];
|
||||||
|
x_offset = data["x_offset"];
|
||||||
|
y_offset = data["y_offset"];
|
||||||
|
advance = data["advance"];
|
||||||
|
|
||||||
|
image.Create(width, height);
|
||||||
|
|
||||||
|
auto& image_data = data["data"];
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for(auto y = 0; y < height; ++y)
|
||||||
|
{
|
||||||
|
for(auto x = 0; x < width; ++x)
|
||||||
|
{
|
||||||
|
uint8_t i = image_data[index];
|
||||||
|
image.at(x, y) = i * 0xFF;
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Glyph::operator=(Glyph const& glyph)
|
||||||
|
{
|
||||||
|
image = glyph.image;
|
||||||
|
height = glyph.height;
|
||||||
|
width = glyph.width;
|
||||||
|
x_offset = glyph.x_offset;
|
||||||
|
y_offset = glyph.y_offset;
|
||||||
|
advance = glyph.advance;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::font
|
||||||
28
frame/src/font/Glyph.hpp
Normal file
28
frame/src/font/Glyph.hpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Image.hpp"
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
namespace frame::font
|
||||||
|
{
|
||||||
|
struct Glyph
|
||||||
|
{
|
||||||
|
Image image;
|
||||||
|
uint8_t height;
|
||||||
|
uint8_t width;
|
||||||
|
int32_t x_offset;
|
||||||
|
int32_t y_offset;
|
||||||
|
int32_t advance;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Glyph() = default;
|
||||||
|
Glyph(json const& data);
|
||||||
|
Glyph(Glyph const&) = default;
|
||||||
|
Glyph(Glyph&&) = default;
|
||||||
|
|
||||||
|
void operator=(Glyph const& glyph);
|
||||||
|
};
|
||||||
|
} // namespace frame::font
|
||||||
255
frame/src/main.cpp
Normal file
255
frame/src/main.cpp
Normal file
@@ -0,0 +1,255 @@
|
|||||||
|
#include <chrono>
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
#include "Config.hpp"
|
||||||
|
#include "ScreenManager.hpp"
|
||||||
|
#include "display/Display.hpp"
|
||||||
|
#include "font/FontRegistry.hpp"
|
||||||
|
//#include "render/RenderTarget.hpp"
|
||||||
|
//#include "widgets/clock/Analog.hpp"
|
||||||
|
#include "widgets/ContainerWidget.hpp"
|
||||||
|
#include "widgets/WidgetRegistry.hpp"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// == == Config == ==
|
||||||
|
auto config = Config::Load();
|
||||||
|
|
||||||
|
// == == Display == ==
|
||||||
|
auto display = frame::display::Create();
|
||||||
|
|
||||||
|
if(!display)
|
||||||
|
{
|
||||||
|
fmt::print("Error: Not display driver!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
display->Init();
|
||||||
|
|
||||||
|
// frame::font::LoadFont("Fira Code");
|
||||||
|
frame::font::LocateRegistry().LoadFromConfig(config.font);
|
||||||
|
|
||||||
|
frame::ScreenManager screen(std::move(display));
|
||||||
|
|
||||||
|
auto const& widgets = frame::Service::get<frame::widgets::WidgetRegistry>();
|
||||||
|
|
||||||
|
// std::shared_ptr<frame::widgets::ContainerWidget> con =
|
||||||
|
// std::static_pointer_cast<frame::widgets::ContainerWidget>(
|
||||||
|
// widgets->Create("AnalogClock"));
|
||||||
|
|
||||||
|
// con->setSlot(0, widgets->Create("DigitalClock"));
|
||||||
|
|
||||||
|
// con->setSlot(1, widgets->Create("Date"));
|
||||||
|
|
||||||
|
auto con = frame::widgets::LocateRegistry().BuildFromConfig(config.root);
|
||||||
|
screen.setRoot(con);
|
||||||
|
|
||||||
|
screen.MainLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
constexpr double pi = 3.14159;
|
||||||
|
|
||||||
|
auto font = frame::font::Font::LoadFromFile("Fira Code.json");
|
||||||
|
|
||||||
|
auto display = frame::display::Create();
|
||||||
|
|
||||||
|
if(!display)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
display->Init();
|
||||||
|
|
||||||
|
display->Clear(frame::display::Color::WHITE);
|
||||||
|
|
||||||
|
frame::render::RenderTarget target(display->getSize());
|
||||||
|
|
||||||
|
frame::Vector const center = (display->getSize() / 2);
|
||||||
|
|
||||||
|
target.DrawPixel({10, 10}, frame::BLACK);
|
||||||
|
target.DrawLine({10, 12}, {100, 12}, frame::BLACK);
|
||||||
|
|
||||||
|
for(int i = 0; i < 360; i += 15)
|
||||||
|
{
|
||||||
|
auto end = center;
|
||||||
|
|
||||||
|
double const x = std::cos(i * pi / 180.f) * 200.f;
|
||||||
|
double const y = std::sin(i * pi / 180.f) * 200.f;
|
||||||
|
|
||||||
|
end.x += (int)x;
|
||||||
|
end.y += (int)y;
|
||||||
|
|
||||||
|
target.DrawLine(center, end);
|
||||||
|
}
|
||||||
|
target.DrawCircle(center, 200);
|
||||||
|
target.DrawCircle(center, 210);
|
||||||
|
target.DrawCircle(center, 220);
|
||||||
|
|
||||||
|
target.DrawCircle(center, 230);
|
||||||
|
target.DrawCircle(center, 231);
|
||||||
|
|
||||||
|
target.DrawRectFilled({100, 100}, {202, 202});
|
||||||
|
target.DrawCircle({151, 151}, 50, frame::WHITE);
|
||||||
|
target.DrawCircle({151, 151}, 40, frame::WHITE);
|
||||||
|
target.DrawCircle({151, 151}, 30, frame::WHITE);
|
||||||
|
target.DrawCircle({151, 151}, 20, frame::WHITE);
|
||||||
|
target.DrawCircle({151, 151}, 10, frame::WHITE);
|
||||||
|
target.DrawCircle({151, 151}, 1, frame::WHITE);
|
||||||
|
|
||||||
|
target.DrawRect({10, (int)display->getSize().height - 110},
|
||||||
|
{110, (int)display->getSize().height - 10},
|
||||||
|
5);
|
||||||
|
|
||||||
|
target.DrawText("Hallo Welt!", {100, 50}, *font, 14);
|
||||||
|
target.DrawText("Hallo Welt!", {50, 100}, *font, 30);
|
||||||
|
|
||||||
|
display->Display(target.getImage());
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(10s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
|
||||||
|
frame::Vector pos = display->getSize() / 2;
|
||||||
|
|
||||||
|
auto text = "10:30";
|
||||||
|
|
||||||
|
pos.x -= font->getLength(text, 250) / 2;
|
||||||
|
pos.y += font->getHeight(text, 250) / 2;
|
||||||
|
pos.y -= font->getMaxYOffset(text, 250) + font->getHeight(text, 250);
|
||||||
|
|
||||||
|
// target.DrawTextGlyphBounds(text, pos, *font, 250);
|
||||||
|
// target.DrawLine({0, (int32_t)pos.y},
|
||||||
|
// {(int32_t)display->getSize().width, pos.y});
|
||||||
|
|
||||||
|
auto rect = frame::Rect{0,
|
||||||
|
0,
|
||||||
|
(int)display->getSize().width,
|
||||||
|
(int)display->getSize().height};
|
||||||
|
|
||||||
|
target.DrawText(rect, text, *font, 250);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
target.DrawText(rect, text, *font, 250, frame::AlignHorizontal::CENTER);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
target.DrawText(rect, text, *font, 250, frame::AlignHorizontal::RIGHT);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
target.DrawText(rect,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
250,
|
||||||
|
frame::AlignHorizontal::LEFT,
|
||||||
|
frame::AlignVertical::CENTER);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
target.DrawText(rect,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
250,
|
||||||
|
frame::AlignHorizontal::CENTER,
|
||||||
|
frame::AlignVertical::CENTER);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
target.DrawText(rect,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
250,
|
||||||
|
frame::AlignHorizontal::RIGHT,
|
||||||
|
frame::AlignVertical::CENTER);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
target.DrawText(rect,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
250,
|
||||||
|
frame::AlignHorizontal::LEFT,
|
||||||
|
frame::AlignVertical::BOTTOM);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
target.DrawText(rect,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
250,
|
||||||
|
frame::AlignHorizontal::CENTER,
|
||||||
|
frame::AlignVertical::BOTTOM);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
target.Clear();
|
||||||
|
target.DrawText(rect,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
250,
|
||||||
|
frame::AlignHorizontal::RIGHT,
|
||||||
|
frame::AlignVertical::BOTTOM);
|
||||||
|
display->Display(target.getImage());
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
display->Clear(frame::display::Color::WHITE);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
#include <EPD_7in5_V2.h>
|
||||||
|
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
std::cout << "Hallo Welt" << std::endl;
|
||||||
|
|
||||||
|
EPD_7IN5_V2_Init();
|
||||||
|
|
||||||
|
EPD_7IN5_V2_ClearBlack();
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
EPD_7IN5_V2_Clear();
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(2s);
|
||||||
|
|
||||||
|
std::vector<uint8_t> image;
|
||||||
|
image.resize(EPD_7IN5_V2_HEIGHT * EPD_7IN5_V2_WIDTH);
|
||||||
|
|
||||||
|
uint8_t color = 0;
|
||||||
|
for(int x = 0; x < EPD_7IN5_V2_WIDTH; ++x)
|
||||||
|
{
|
||||||
|
for(int y = 0; y < EPD_7IN5_V2_HEIGHT; ++y)
|
||||||
|
{
|
||||||
|
image[EPD_7IN5_V2_WIDTH * y + x] = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = ~color;
|
||||||
|
}
|
||||||
|
|
||||||
|
EPD_7IN5_V2_Display(image.data());
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(10s);
|
||||||
|
|
||||||
|
EPD_7IN5_V2_Clear();
|
||||||
|
EPD_7IN5_V2_Sleep();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
317
frame/src/render/RenderTarget.cpp
Normal file
317
frame/src/render/RenderTarget.cpp
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
#include "RenderTarget.hpp"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace frame::render
|
||||||
|
{
|
||||||
|
|
||||||
|
RenderTarget::RenderTarget(Size size)
|
||||||
|
: image(size)
|
||||||
|
, root_size{0, 0, (int)size.width, (int)size.height}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawPixel(Vector const& position, Color color)
|
||||||
|
{
|
||||||
|
auto current = getCurrentSize();
|
||||||
|
|
||||||
|
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;
|
||||||
|
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,
|
||||||
|
Vector const& end,
|
||||||
|
Color color)
|
||||||
|
{
|
||||||
|
auto deltaX = std::abs(start.x - end.x);
|
||||||
|
auto deltaY = std::abs(start.y - end.y);
|
||||||
|
|
||||||
|
auto rX = start.x < end.x ? 1 : -1;
|
||||||
|
auto rY = start.y < end.y ? 1 : -1;
|
||||||
|
|
||||||
|
bool swap = false;
|
||||||
|
|
||||||
|
if(deltaX < deltaY)
|
||||||
|
{
|
||||||
|
swap = true;
|
||||||
|
std::swap(deltaX, deltaY);
|
||||||
|
std::swap(rX, rY);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pos = start;
|
||||||
|
auto E = 2 * deltaY - deltaX;
|
||||||
|
|
||||||
|
DrawPixel(pos, color);
|
||||||
|
|
||||||
|
while(pos != end)
|
||||||
|
{
|
||||||
|
if(E <= 0)
|
||||||
|
{
|
||||||
|
if(!swap)
|
||||||
|
pos.x += rX;
|
||||||
|
else
|
||||||
|
pos.y += rX;
|
||||||
|
|
||||||
|
E += 2 * deltaY;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
if(!swap)
|
||||||
|
{
|
||||||
|
pos.x += rX;
|
||||||
|
pos.y += rY;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
pos.y += rX;
|
||||||
|
pos.x += rY;
|
||||||
|
}
|
||||||
|
|
||||||
|
E += 2 * deltaY - 2 * deltaX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pos.x < 0 || pos.y < 0 || pos.x >= image.getWidth()
|
||||||
|
|| pos.y >= image.getHeight())
|
||||||
|
break;
|
||||||
|
|
||||||
|
DrawPixel(pos, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawCircle(Vector const& center,
|
||||||
|
int32_t radius,
|
||||||
|
int32_t line,
|
||||||
|
Color color)
|
||||||
|
{
|
||||||
|
int32_t const r_2 = radius * radius;
|
||||||
|
Vector pos{0, -radius};
|
||||||
|
|
||||||
|
for(auto i = 0; i < line; ++i)
|
||||||
|
{
|
||||||
|
DrawPointsMirrorCircle(center, {pos.x, pos.y + i}, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(pos.x <= radius / std::sqrt(2.f))
|
||||||
|
{
|
||||||
|
float E = pos.x * pos.x
|
||||||
|
+ ((float)pos.y + 0.5f) * ((float)pos.y + 0.5f) - r_2;
|
||||||
|
|
||||||
|
if(E <= 0)
|
||||||
|
{
|
||||||
|
pos.x += 1;
|
||||||
|
|
||||||
|
E += 2 * pos.x + 3;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
pos.x += 1;
|
||||||
|
pos.y += 1;
|
||||||
|
|
||||||
|
E += 2 * pos.x - 2 * pos.y + 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto i = 0; i < line; ++i)
|
||||||
|
{
|
||||||
|
DrawPointsMirrorCircle(center, {pos.x, pos.y + i}, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawRectFilled(Vector const& LeftTop,
|
||||||
|
Vector const& BottomRight,
|
||||||
|
Color color)
|
||||||
|
{
|
||||||
|
auto pos = LeftTop;
|
||||||
|
|
||||||
|
while(pos.y <= BottomRight.y)
|
||||||
|
{
|
||||||
|
while(pos.x <= BottomRight.x)
|
||||||
|
{
|
||||||
|
DrawPixel(pos, color);
|
||||||
|
pos.x++;
|
||||||
|
}
|
||||||
|
pos.x = LeftTop.x;
|
||||||
|
pos.y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawRect(Vector const& TopLeft,
|
||||||
|
Vector const& BottomRight,
|
||||||
|
uint8_t LineWidth,
|
||||||
|
Color color)
|
||||||
|
{
|
||||||
|
auto pos = TopLeft;
|
||||||
|
|
||||||
|
auto const lw = LineWidth - 1;
|
||||||
|
|
||||||
|
DrawRectFilled(TopLeft, {BottomRight.x, TopLeft.y + lw}, color);
|
||||||
|
DrawRectFilled({TopLeft.x, BottomRight.y - lw}, BottomRight);
|
||||||
|
|
||||||
|
DrawRectFilled({TopLeft.x, TopLeft.y + lw},
|
||||||
|
{TopLeft.x + lw, BottomRight.y - lw});
|
||||||
|
DrawRectFilled({BottomRight.x - lw, TopLeft.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)
|
||||||
|
{
|
||||||
|
auto pos = topLeft;
|
||||||
|
|
||||||
|
for(auto y = 0; y < image.getHeight(); ++y)
|
||||||
|
{
|
||||||
|
for(auto x = 0; x < image.getWidth(); ++x)
|
||||||
|
{
|
||||||
|
DrawPixel({pos.x + x, pos.y + y}, (Color)image.at(x, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector RenderTarget::DrawGlyph(Vector centerLine,
|
||||||
|
font::Glyph const& g,
|
||||||
|
Color color)
|
||||||
|
{
|
||||||
|
auto const& height = g.height;
|
||||||
|
|
||||||
|
Vector topleft = centerLine;
|
||||||
|
topleft.x += g.x_offset;
|
||||||
|
topleft.y += g.y_offset;
|
||||||
|
|
||||||
|
DrawImage(topleft, g.image);
|
||||||
|
centerLine.x += g.advance;
|
||||||
|
return centerLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawText(std::string_view pText,
|
||||||
|
Vector pCenterLineStart,
|
||||||
|
font::Font const& pFont,
|
||||||
|
uint32_t size)
|
||||||
|
{
|
||||||
|
auto pos = pCenterLineStart;
|
||||||
|
for(auto c : pText)
|
||||||
|
{
|
||||||
|
pos = DrawGlyph(pos, pFont.getGlyph(size, c));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawText(Rect rect,
|
||||||
|
std::string pText,
|
||||||
|
font::Font const& pFont,
|
||||||
|
uint32_t size,
|
||||||
|
AlignHorizontal alignHorizontal,
|
||||||
|
AlignVertical alignVertical)
|
||||||
|
{
|
||||||
|
auto const lineSpacing = pFont.getLineSpacing(size);
|
||||||
|
auto const lineSpacing_3 = lineSpacing / 3;
|
||||||
|
|
||||||
|
Vector start{rect.left, rect.top};
|
||||||
|
auto text_height = pFont.getHeight(pText, size);
|
||||||
|
auto length = pFont.getLength(pText, size);
|
||||||
|
auto y_offset = pFont.getMaxYOffset(pText, size);
|
||||||
|
|
||||||
|
switch(alignVertical)
|
||||||
|
{
|
||||||
|
case AlignVertical::TOP: start.y -= y_offset; break;
|
||||||
|
case AlignVertical::CENTER:
|
||||||
|
start.y += rect.height / 2;
|
||||||
|
start.y += text_height / 2;
|
||||||
|
start.y -= y_offset + text_height;
|
||||||
|
break;
|
||||||
|
case AlignVertical::BOTTOM:
|
||||||
|
start.y += rect.height;
|
||||||
|
start.y -= text_height + y_offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(alignHorizontal)
|
||||||
|
{
|
||||||
|
case AlignHorizontal::CENTER:
|
||||||
|
start.x += rect.width / 2;
|
||||||
|
start.x -= length / 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AlignHorizontal::RIGHT: start.x += rect.width - length; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawText(pText, start, pFont, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::DrawTextGlyphBounds(std::string_view pText,
|
||||||
|
Vector pCenterLineStart,
|
||||||
|
font::Font const& pFont,
|
||||||
|
uint32_t size)
|
||||||
|
{
|
||||||
|
auto pos = pCenterLineStart;
|
||||||
|
|
||||||
|
auto lineSpacing = pFont.getLineSpacing(size);
|
||||||
|
auto _3 = lineSpacing / 3;
|
||||||
|
for(auto c : pText)
|
||||||
|
{
|
||||||
|
auto const& g = pFont.getGlyph(size, c);
|
||||||
|
DrawRect({int32_t(pos.x), int32_t(pos.y - _3 * 2)},
|
||||||
|
{int32_t(pos.x + g.advance), int32_t(pos.y + _3)},
|
||||||
|
1);
|
||||||
|
|
||||||
|
pos.x += g.advance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTarget::Clear(Color 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,
|
||||||
|
Vector const& pos,
|
||||||
|
Color color)
|
||||||
|
{
|
||||||
|
DrawPixel(center + pos, color);
|
||||||
|
DrawPixel(center + Vector{pos.x, pos.y * -1}, color);
|
||||||
|
DrawPixel(center + Vector{pos.x * -1, pos.y * -1}, color);
|
||||||
|
DrawPixel(center + Vector{pos.x * -1, pos.y}, color);
|
||||||
|
|
||||||
|
DrawPixel(center + Vector{pos.y, pos.x}, color);
|
||||||
|
DrawPixel(center + Vector{pos.y, pos.x * -1}, color);
|
||||||
|
DrawPixel(center + Vector{pos.y * -1, pos.x * -1}, color);
|
||||||
|
DrawPixel(center + Vector{pos.y * -1, pos.x}, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::render
|
||||||
99
frame/src/render/RenderTarget.hpp
Normal file
99
frame/src/render/RenderTarget.hpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Color.hpp"
|
||||||
|
#include "../Image.hpp"
|
||||||
|
#include "../Rect.hpp"
|
||||||
|
#include "../Vector.hpp"
|
||||||
|
#include "../font/Font.hpp"
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
namespace frame
|
||||||
|
{
|
||||||
|
enum class AlignVertical { TOP, CENTER, BOTTOM };
|
||||||
|
enum class AlignHorizontal { LEFT, CENTER, RIGHT };
|
||||||
|
} // namespace frame
|
||||||
|
|
||||||
|
namespace frame::render
|
||||||
|
{
|
||||||
|
|
||||||
|
class RenderTarget
|
||||||
|
{
|
||||||
|
Image image;
|
||||||
|
|
||||||
|
Rect root_size;
|
||||||
|
std::stack<Rect> Scissor;
|
||||||
|
|
||||||
|
bool invert = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RenderTarget(Size size);
|
||||||
|
|
||||||
|
void DrawPixel(Vector const& position, Color color);
|
||||||
|
|
||||||
|
void DrawLine(Vector const& start,
|
||||||
|
Vector const& end,
|
||||||
|
Color color = BLACK);
|
||||||
|
|
||||||
|
void DrawCircle(Vector const& center,
|
||||||
|
int32_t radius,
|
||||||
|
int32_t line,
|
||||||
|
Color color = BLACK);
|
||||||
|
|
||||||
|
void DrawRectFilled(Vector const& TopLeft,
|
||||||
|
Vector const& BottomRight,
|
||||||
|
Color color = BLACK);
|
||||||
|
|
||||||
|
void DrawRect(Vector const& TopLeft,
|
||||||
|
Vector const& BottomRight,
|
||||||
|
uint8_t LineWidth,
|
||||||
|
Color color = BLACK);
|
||||||
|
|
||||||
|
void DrawRect(Rect const& rect, uint8_t LineWidth, Color color = BLACK);
|
||||||
|
|
||||||
|
void DrawImage(Vector topLeft, Image const& image);
|
||||||
|
|
||||||
|
Vector DrawGlyph(Vector centerLine,
|
||||||
|
font::Glyph const& g,
|
||||||
|
Color color = BLACK);
|
||||||
|
|
||||||
|
void DrawText(std::string_view pText,
|
||||||
|
Vector pCenterLineStart,
|
||||||
|
font::Font const& pFont,
|
||||||
|
uint32_t size);
|
||||||
|
|
||||||
|
void DrawText(Rect rect,
|
||||||
|
std::string pText,
|
||||||
|
font::Font const& pFont,
|
||||||
|
uint32_t size,
|
||||||
|
AlignHorizontal alignHorizontal = AlignHorizontal::LEFT,
|
||||||
|
AlignVertical alignVertical = AlignVertical::TOP);
|
||||||
|
|
||||||
|
void DrawTextGlyphBounds(std::string_view pText,
|
||||||
|
Vector pCenterLineStart,
|
||||||
|
font::Font const& pFont,
|
||||||
|
uint32_t size);
|
||||||
|
|
||||||
|
void Clear(Color color = WHITE);
|
||||||
|
|
||||||
|
Image const& getImage()
|
||||||
|
{
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect getCurrentSize() const;
|
||||||
|
void pushViewport(Rect rect);
|
||||||
|
void popViewport();
|
||||||
|
|
||||||
|
void setInvert(bool pInvert)
|
||||||
|
{
|
||||||
|
invert = pInvert;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DrawPointsMirrorCircle(Vector const& center,
|
||||||
|
Vector const& pos,
|
||||||
|
Color color);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame::render
|
||||||
35
frame/src/widgets/ContainerWidget.cpp
Normal file
35
frame/src/widgets/ContainerWidget.cpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#include "ContainerWidget.hpp"
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
ContainerWidget::ContainerWidget(size_t slots)
|
||||||
|
{
|
||||||
|
widgets.resize(slots);
|
||||||
|
maxSlots = slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::shared_ptr ContainerWidget::getSlot(size_t slot) const
|
||||||
|
{
|
||||||
|
if(slot >= maxSlots)
|
||||||
|
return nullptr;
|
||||||
|
return widgets[slot];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContainerWidget::setSlot(size_t slot, Widget::shared_ptr ptr)
|
||||||
|
{
|
||||||
|
ptr->setParent(this);
|
||||||
|
widgets[slot] = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContainerWidget::UpdateWidgets()
|
||||||
|
{
|
||||||
|
for(auto& el : widgets)
|
||||||
|
{
|
||||||
|
if(el)
|
||||||
|
{
|
||||||
|
el->Update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
23
frame/src/widgets/ContainerWidget.hpp
Normal file
23
frame/src/widgets/ContainerWidget.hpp
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Widget.hpp"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
class ContainerWidget : public Widget
|
||||||
|
{
|
||||||
|
std::vector<Widget::shared_ptr> widgets;
|
||||||
|
size_t maxSlots = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ContainerWidget(size_t slots);
|
||||||
|
|
||||||
|
Widget::shared_ptr getSlot(size_t slot) const;
|
||||||
|
void setSlot(size_t slot, Widget::shared_ptr);
|
||||||
|
|
||||||
|
void UpdateWidgets();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
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::week_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 = Widget*;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Widget() = default;
|
||||||
|
|
||||||
|
virtual void Update() = 0;
|
||||||
|
virtual void Render(render::RenderTarget& rt) = 0;
|
||||||
|
virtual void ComputeChildSize(Vector size){};
|
||||||
|
|
||||||
|
week_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 = nullptr;
|
||||||
|
bool mDirty = true;
|
||||||
|
|
||||||
|
Vector mRelativePosition;
|
||||||
|
Vector mSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
43
frame/src/widgets/WidgetRegistry.cpp
Normal file
43
frame/src/widgets/WidgetRegistry.cpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#include "WidgetRegistry.hpp"
|
||||||
|
|
||||||
|
#include "ContainerWidget.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget::shared_ptr WidgetRegistry::BuildFromConfig(WidgetConfig const& w)
|
||||||
|
{
|
||||||
|
fmt::print("INFO: Creating widget {} \n", w.name);
|
||||||
|
auto widget = Create(w.name);
|
||||||
|
|
||||||
|
auto container = std::dynamic_pointer_cast<ContainerWidget>(widget);
|
||||||
|
if(container)
|
||||||
|
{
|
||||||
|
int counter = 0;
|
||||||
|
for(auto const& el : w.widgets)
|
||||||
|
{
|
||||||
|
int slot = el.slot ? el.slot.value() : counter;
|
||||||
|
|
||||||
|
container->setSlot(slot, BuildFromConfig(el));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
59
frame/src/widgets/WidgetRegistry.hpp
Normal file
59
frame/src/widgets/WidgetRegistry.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../Config.hpp"
|
||||||
|
#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;
|
||||||
|
|
||||||
|
Widget::shared_ptr BuildFromConfig(WidgetConfig const& w);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline WidgetRegistry& LocateRegistry()
|
||||||
|
{
|
||||||
|
return *Service::get<frame::widgets::WidgetRegistry>();
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
180
frame/src/widgets/clock/Analog.cpp
Normal file
180
frame/src/widgets/clock/Analog.cpp
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
#include "Analog.hpp"
|
||||||
|
|
||||||
|
#include "../../font/FontRegistry.hpp"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
constexpr double pi = 3.14159;
|
||||||
|
|
||||||
|
#include "../WidgetRegistry.hpp"
|
||||||
|
|
||||||
|
REGISTER_WIDGET(frame::widgets::AnalogClock, "AnalogClock");
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
Widget::shared_ptr AnalogClock::Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<AnalogClock>();
|
||||||
|
}
|
||||||
|
|
||||||
|
AnalogClock::AnalogClock()
|
||||||
|
: ContainerWidget(2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateWidgets();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 * 0.8),
|
||||||
|
center.y + int32_t(std::sin(min_rad) * radius * 0.8)});
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
// == Widgets ==
|
||||||
|
|
||||||
|
auto widget_center_1 = center;
|
||||||
|
widget_center_1.y -= radius / 2;
|
||||||
|
|
||||||
|
auto widget_center_2 = center;
|
||||||
|
widget_center_2.y += radius / 2;
|
||||||
|
|
||||||
|
auto const widget_height_h = radius / 4;
|
||||||
|
auto const widget_width_h = radius / 2;
|
||||||
|
|
||||||
|
Rect widget_box_1{widget_center_1.y - widget_height_h,
|
||||||
|
widget_center_1.x - widget_width_h,
|
||||||
|
widget_width_h * 2,
|
||||||
|
widget_height_h * 2};
|
||||||
|
|
||||||
|
Rect widget_box_2{widget_center_2.y - widget_height_h,
|
||||||
|
widget_center_2.x - widget_width_h,
|
||||||
|
widget_width_h * 2,
|
||||||
|
widget_height_h * 2};
|
||||||
|
|
||||||
|
// Top
|
||||||
|
|
||||||
|
auto top = getSlot(0);
|
||||||
|
if(top)
|
||||||
|
{
|
||||||
|
top->setSize({widget_box_1.width, widget_box_1.height});
|
||||||
|
rt.pushViewport(widget_box_1);
|
||||||
|
top->Render(rt);
|
||||||
|
rt.popViewport();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bottom = getSlot(1);
|
||||||
|
if(bottom)
|
||||||
|
{
|
||||||
|
bottom->setSize({widget_box_2.width, widget_box_2.height});
|
||||||
|
rt.pushViewport(widget_box_2);
|
||||||
|
bottom->Render(rt);
|
||||||
|
rt.popViewport();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
24
frame/src/widgets/clock/Analog.hpp
Normal file
24
frame/src/widgets/clock/Analog.hpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../ContainerWidget.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
class AnalogClock : public ContainerWidget
|
||||||
|
{
|
||||||
|
using Time = std::chrono::time_point<std::chrono::system_clock>;
|
||||||
|
|
||||||
|
Time last_time;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Widget::shared_ptr Create();
|
||||||
|
|
||||||
|
AnalogClock();
|
||||||
|
|
||||||
|
void Update() override;
|
||||||
|
void Render(render::RenderTarget& rt) override;
|
||||||
|
};
|
||||||
|
} // namespace frame::widgets
|
||||||
56
frame/src/widgets/clock/Date.cpp
Normal file
56
frame/src/widgets/clock/Date.cpp
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#include "Date.hpp"
|
||||||
|
|
||||||
|
REGISTER_WIDGET(frame::widgets::Date, "Date");
|
||||||
|
|
||||||
|
#include "../../font/FontRegistry.hpp"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
Widget::shared_ptr Date::Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<Date>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Date::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 Date::Render(render::RenderTarget& rt)
|
||||||
|
{
|
||||||
|
std::time_t t = std::chrono::system_clock::to_time_t(last_time);
|
||||||
|
|
||||||
|
auto const& size = getSize();
|
||||||
|
Rect draw{0, 0, size.x, size.y};
|
||||||
|
|
||||||
|
auto text = fmt::format("{:%d.%m.%Y}", fmt::localtime(t));
|
||||||
|
|
||||||
|
auto font = font::GetFont("Fira Code");
|
||||||
|
|
||||||
|
auto font_size = font->getOptimalSize(text, draw);
|
||||||
|
|
||||||
|
rt.setInvert(true);
|
||||||
|
rt.DrawText(draw,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
font_size,
|
||||||
|
AlignHorizontal::CENTER,
|
||||||
|
AlignVertical::CENTER);
|
||||||
|
rt.setInvert(false);
|
||||||
|
|
||||||
|
setClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
22
frame/src/widgets/clock/Date.hpp
Normal file
22
frame/src/widgets/clock/Date.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../Widget.hpp"
|
||||||
|
#include "../WidgetRegistry.hpp"
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
class Date : 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
|
||||||
60
frame/src/widgets/clock/Digital.cpp
Normal file
60
frame/src/widgets/clock/Digital.cpp
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
#include "Digital.hpp"
|
||||||
|
|
||||||
|
REGISTER_WIDGET(frame::widgets::DigitalClock, "DigitalClock");
|
||||||
|
|
||||||
|
#include "../../font/FontRegistry.hpp"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
Widget::shared_ptr DigitalClock::Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<DigitalClock>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DigitalClock::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 DigitalClock::Render(render::RenderTarget& rt)
|
||||||
|
{
|
||||||
|
std::time_t t = std::chrono::system_clock::to_time_t(last_time);
|
||||||
|
auto c_time = std::localtime(&t);
|
||||||
|
|
||||||
|
auto const& size = getSize();
|
||||||
|
Rect draw{0, 0, size.x, size.y};
|
||||||
|
|
||||||
|
auto text =
|
||||||
|
fmt::format("{:0>2}:{:0>2}", c_time->tm_hour, c_time->tm_min);
|
||||||
|
|
||||||
|
auto font = font::GetFont("Fira Code");
|
||||||
|
|
||||||
|
auto font_size = font->getOptimalSize(text, draw);
|
||||||
|
|
||||||
|
rt.setInvert(true);
|
||||||
|
|
||||||
|
rt.DrawText(draw,
|
||||||
|
text,
|
||||||
|
*font,
|
||||||
|
font_size,
|
||||||
|
AlignHorizontal::CENTER,
|
||||||
|
AlignVertical::CENTER);
|
||||||
|
|
||||||
|
rt.setInvert(false);
|
||||||
|
|
||||||
|
setClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace frame::widgets
|
||||||
24
frame/src/widgets/clock/Digital.hpp
Normal file
24
frame/src/widgets/clock/Digital.hpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include "../Widget.hpp"
|
||||||
|
#include "../WidgetRegistry.hpp"
|
||||||
|
|
||||||
|
namespace frame::widgets
|
||||||
|
{
|
||||||
|
|
||||||
|
class DigitalClock : 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
|
||||||
11
vcpkg.json
Normal file
11
vcpkg.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "frame",
|
||||||
|
"version": "1.0",
|
||||||
|
"dependencies": ["fmt", "nlohmann-json"],
|
||||||
|
"features": {
|
||||||
|
"virtual": {
|
||||||
|
"description": "Build Virtual Display",
|
||||||
|
"dependencies": ["sfml"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
waveshare/CMakeLists.txt
Normal file
13
waveshare/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
set(target waveshare)
|
||||||
|
|
||||||
|
set(src
|
||||||
|
include/DEV_Config.h
|
||||||
|
include/EPD_7in5_V2.h
|
||||||
|
src/DEV_Config.c
|
||||||
|
src/EPD_7in5_V2.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(${target} STATIC ${src})
|
||||||
|
target_include_directories(${target} PUBLIC include/)
|
||||||
|
target_link_libraries(${target} PUBLIC bcm2835)
|
||||||
111
waveshare/include/DEV_Config.h
Normal file
111
waveshare/include/DEV_Config.h
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* | File : DEV_Config.h
|
||||||
|
* | Author : Waveshare team
|
||||||
|
* | Function : Hardware underlying interface
|
||||||
|
* | Info :
|
||||||
|
* Used to shield the underlying layers of each master
|
||||||
|
* and enhance portability
|
||||||
|
*----------------
|
||||||
|
* | This version: V2.0
|
||||||
|
* | Date : 2018-10-30
|
||||||
|
* | Info :
|
||||||
|
* 1.add:
|
||||||
|
* UBYTE\UWORD\UDOUBLE
|
||||||
|
* 2.Change:
|
||||||
|
* EPD_RST -> EPD_RST_PIN
|
||||||
|
* EPD_DC -> EPD_DC_PIN
|
||||||
|
* EPD_CS -> EPD_CS_PIN
|
||||||
|
* EPD_BUSY -> EPD_BUSY_PIN
|
||||||
|
* 3.Remote:
|
||||||
|
* EPD_RST_1\EPD_RST_0
|
||||||
|
* EPD_DC_1\EPD_DC_0
|
||||||
|
* EPD_CS_1\EPD_CS_0
|
||||||
|
* EPD_BUSY_1\EPD_BUSY_0
|
||||||
|
* 3.add:
|
||||||
|
* #define DEV_Digital_Write(_pin, _value) bcm2835_GPIOI_write(_pin, _value)
|
||||||
|
* #define DEV_Digital_Read(_pin) bcm2835_GPIOI_lev(_pin)
|
||||||
|
* #define DEV_SPI_WriteByte(__value) bcm2835_spi_transfer(__value)
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documnetation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
#
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef _DEV_CONFIG_H_
|
||||||
|
#define _DEV_CONFIG_H_
|
||||||
|
|
||||||
|
#define RPI
|
||||||
|
#define USE_BCM2835_LIB
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "Debug.h"
|
||||||
|
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
#include <bcm2835.h>
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
#include <wiringPi.h>
|
||||||
|
#include <wiringPiSPI.h>
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
#include "RPI_sysfs_gpio.h"
|
||||||
|
#include "dev_hardware_SPI.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JETSON
|
||||||
|
#ifdef USE_DEV_LIB
|
||||||
|
#include "sysfs_gpio.h"
|
||||||
|
#include "sysfs_software_spi.h"
|
||||||
|
#elif USE_HARDWARE_LIB
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* data
|
||||||
|
**/
|
||||||
|
#define UBYTE uint8_t
|
||||||
|
#define UWORD uint16_t
|
||||||
|
#define UDOUBLE uint32_t
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPIOI config
|
||||||
|
**/
|
||||||
|
extern int EPD_RST_PIN;
|
||||||
|
extern int EPD_DC_PIN;
|
||||||
|
extern int EPD_CS_PIN;
|
||||||
|
extern int EPD_BUSY_PIN;
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------------------------------------------*/
|
||||||
|
void DEV_Digital_Write(UWORD Pin, UBYTE Value);
|
||||||
|
UBYTE DEV_Digital_Read(UWORD Pin);
|
||||||
|
|
||||||
|
void DEV_SPI_WriteByte(UBYTE Value);
|
||||||
|
void DEV_SPI_Write_nByte(uint8_t *pData, uint32_t Len);
|
||||||
|
void DEV_Delay_ms(UDOUBLE xms);
|
||||||
|
|
||||||
|
UBYTE DEV_Module_Init(void);
|
||||||
|
void DEV_Module_Exit(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
47
waveshare/include/Debug.h
Normal file
47
waveshare/include/Debug.h
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* | File : Debug.h
|
||||||
|
* | Author : Waveshare team
|
||||||
|
* | Function : debug with printf
|
||||||
|
* | Info :
|
||||||
|
* Image scanning
|
||||||
|
* Please use progressive scanning to generate images or fonts
|
||||||
|
*----------------
|
||||||
|
* | This version: V2.0
|
||||||
|
* | Date : 2018-10-30
|
||||||
|
* | Info :
|
||||||
|
* 1.USE_DEBUG -> DEBUG, If you need to see the debug information,
|
||||||
|
* clear the execution: make DEBUG=-DDEBUG
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documnetation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
#
|
||||||
|
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef __DEBUG_H
|
||||||
|
#define __DEBUG_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
#define Debug(__info,...) printf("Debug: " __info,##__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define Debug(__info,...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
57
waveshare/include/EPD_7in5_V2.h
Normal file
57
waveshare/include/EPD_7in5_V2.h
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* | File : EPD_7in5_V2.h
|
||||||
|
* | Author : Waveshare team
|
||||||
|
* | Function : Electronic paper driver
|
||||||
|
* | Info :
|
||||||
|
*----------------
|
||||||
|
* | This version: V2.0
|
||||||
|
* | Date : 2018-11-09
|
||||||
|
* | Info :
|
||||||
|
* 1.Remove:ImageBuff[EPD_HEIGHT * EPD_WIDTH / 8]
|
||||||
|
* 2.Change:EPD_Display(UBYTE *Image)
|
||||||
|
* Need to pass parameters: pointer to cached data
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documnetation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
#
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef _EPD_7IN5_V2_H_
|
||||||
|
#define _EPD_7IN5_V2_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "DEV_Config.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Display resolution
|
||||||
|
#define EPD_7IN5_V2_WIDTH 800
|
||||||
|
#define EPD_7IN5_V2_HEIGHT 480
|
||||||
|
|
||||||
|
UBYTE EPD_7IN5_V2_Init(void);
|
||||||
|
void EPD_7IN5_V2_Clear(void);
|
||||||
|
void EPD_7IN5_V2_ClearBlack(void);
|
||||||
|
void EPD_7IN5_V2_Display(const UBYTE *blackimage);
|
||||||
|
void EPD_7IN5_V2_Sleep(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
385
waveshare/src/DEV_Config.c
Normal file
385
waveshare/src/DEV_Config.c
Normal file
@@ -0,0 +1,385 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* | File : DEV_Config.c
|
||||||
|
* | Author : Waveshare team
|
||||||
|
* | Function : Hardware underlying interface
|
||||||
|
* | Info :
|
||||||
|
*----------------
|
||||||
|
* | This version: V3.0
|
||||||
|
* | Date : 2019-07-31
|
||||||
|
* | Info :
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documnetation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of theex Software, and to permit persons to whom the Software is
|
||||||
|
# furished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
#
|
||||||
|
******************************************************************************/
|
||||||
|
#include "DEV_Config.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPIO
|
||||||
|
**/
|
||||||
|
int EPD_RST_PIN;
|
||||||
|
int EPD_DC_PIN;
|
||||||
|
int EPD_CS_PIN;
|
||||||
|
int EPD_BUSY_PIN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPIO read and write
|
||||||
|
**/
|
||||||
|
void DEV_Digital_Write(UWORD Pin, UBYTE Value)
|
||||||
|
{
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
bcm2835_gpio_write(Pin, Value);
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
digitalWrite(Pin, Value);
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
SYSFS_GPIO_Write(Pin, Value);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JETSON
|
||||||
|
#ifdef USE_DEV_LIB
|
||||||
|
SYSFS_GPIO_Write(Pin, Value);
|
||||||
|
#elif USE_HARDWARE_LIB
|
||||||
|
Debug("not support");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
UBYTE DEV_Digital_Read(UWORD Pin)
|
||||||
|
{
|
||||||
|
UBYTE Read_value = 0;
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
Read_value = bcm2835_gpio_lev(Pin);
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
Read_value = digitalRead(Pin);
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
Read_value = SYSFS_GPIO_Read(Pin);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JETSON
|
||||||
|
#ifdef USE_DEV_LIB
|
||||||
|
Read_value = SYSFS_GPIO_Read(Pin);
|
||||||
|
#elif USE_HARDWARE_LIB
|
||||||
|
Debug("not support");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return Read_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SPI
|
||||||
|
**/
|
||||||
|
void DEV_SPI_WriteByte(uint8_t Value)
|
||||||
|
{
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
bcm2835_spi_transfer(Value);
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
wiringPiSPIDataRW(0,&Value,1);
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
DEV_HARDWARE_SPI_TransferByte(Value);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JETSON
|
||||||
|
#ifdef USE_DEV_LIB
|
||||||
|
SYSFS_software_spi_transfer(Value);
|
||||||
|
#elif USE_HARDWARE_LIB
|
||||||
|
Debug("not support");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DEV_SPI_Write_nByte(uint8_t *pData, uint32_t Len)
|
||||||
|
{
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
char rData[Len];
|
||||||
|
bcm2835_spi_transfernb((char *)pData,rData,Len);
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
wiringPiSPIDataRW(0, pData, Len);
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
DEV_HARDWARE_SPI_Transfer(pData, Len);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JETSON
|
||||||
|
#ifdef USE_DEV_LIB
|
||||||
|
//JETSON nano waits for hardware SPI
|
||||||
|
Debug("not support");
|
||||||
|
#elif USE_HARDWARE_LIB
|
||||||
|
Debug("not support");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GPIO Mode
|
||||||
|
**/
|
||||||
|
void DEV_GPIO_Mode(UWORD Pin, UWORD Mode)
|
||||||
|
{
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
if(Mode == 0 || Mode == BCM2835_GPIO_FSEL_INPT) {
|
||||||
|
bcm2835_gpio_fsel(Pin, BCM2835_GPIO_FSEL_INPT);
|
||||||
|
} else {
|
||||||
|
bcm2835_gpio_fsel(Pin, BCM2835_GPIO_FSEL_OUTP);
|
||||||
|
}
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
if(Mode == 0 || Mode == INPUT) {
|
||||||
|
pinMode(Pin, INPUT);
|
||||||
|
pullUpDnControl(Pin, PUD_UP);
|
||||||
|
} else {
|
||||||
|
pinMode(Pin, OUTPUT);
|
||||||
|
// Debug (" %d OUT \r\n",Pin);
|
||||||
|
}
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
SYSFS_GPIO_Export(Pin);
|
||||||
|
if(Mode == 0 || Mode == SYSFS_GPIO_IN) {
|
||||||
|
SYSFS_GPIO_Direction(Pin, SYSFS_GPIO_IN);
|
||||||
|
// Debug("IN Pin = %d\r\n",Pin);
|
||||||
|
} else {
|
||||||
|
SYSFS_GPIO_Direction(Pin, SYSFS_GPIO_OUT);
|
||||||
|
// Debug("OUT Pin = %d\r\n",Pin);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JETSON
|
||||||
|
#ifdef USE_DEV_LIB
|
||||||
|
SYSFS_GPIO_Export(Pin);
|
||||||
|
SYSFS_GPIO_Direction(Pin, Mode);
|
||||||
|
#elif USE_HARDWARE_LIB
|
||||||
|
Debug("not support");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delay x ms
|
||||||
|
**/
|
||||||
|
void DEV_Delay_ms(UDOUBLE xms)
|
||||||
|
{
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
bcm2835_delay(xms);
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
delay(xms);
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
UDOUBLE i;
|
||||||
|
for(i=0; i < xms; i++) {
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef JETSON
|
||||||
|
UDOUBLE i;
|
||||||
|
for(i=0; i < xms; i++) {
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int DEV_Equipment_Testing(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int fd;
|
||||||
|
char value_str[20];
|
||||||
|
fd = open("/etc/issue", O_RDONLY);
|
||||||
|
printf("Current environment: ");
|
||||||
|
while(1) {
|
||||||
|
if (fd < 0) {
|
||||||
|
Debug( "Read failed Pin\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
for(i=0;; i++) {
|
||||||
|
if (read(fd, &value_str[i], 1) < 0) {
|
||||||
|
Debug( "failed to read value!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(value_str[i] ==32) {
|
||||||
|
printf("\r\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("%c",value_str[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#ifdef RPI
|
||||||
|
if(i<5) {
|
||||||
|
printf("Unrecognizable\r\n");
|
||||||
|
} else {
|
||||||
|
char RPI_System[10] = {"Raspbian"};
|
||||||
|
for(i=0; i<6; i++) {
|
||||||
|
if(RPI_System[i]!= value_str[i]) {
|
||||||
|
printf("Please make JETSON !!!!!!!!!!\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef JETSON
|
||||||
|
if(i<5) {
|
||||||
|
Debug("Unrecognizable\r\n");
|
||||||
|
} else {
|
||||||
|
char JETSON_System[10]= {"Ubuntu"};
|
||||||
|
for(i=0; i<6; i++) {
|
||||||
|
if(JETSON_System[i]!= value_str[i] ) {
|
||||||
|
printf("Please make RPI !!!!!!!!!!\r\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void DEV_GPIO_Init(void)
|
||||||
|
{
|
||||||
|
#ifdef RPI
|
||||||
|
EPD_RST_PIN = 17;
|
||||||
|
EPD_DC_PIN = 25;
|
||||||
|
EPD_CS_PIN = 8;
|
||||||
|
EPD_BUSY_PIN = 24;
|
||||||
|
#elif JETSON
|
||||||
|
EPD_RST_PIN = GPIO17;
|
||||||
|
EPD_DC_PIN = GPIO25;
|
||||||
|
EPD_CS_PIN = SPI0_CS0;
|
||||||
|
EPD_BUSY_PIN = GPIO24;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEV_GPIO_Mode(EPD_RST_PIN, 1);
|
||||||
|
DEV_GPIO_Mode(EPD_DC_PIN, 1);
|
||||||
|
DEV_GPIO_Mode(EPD_CS_PIN, 1);
|
||||||
|
DEV_GPIO_Mode(EPD_BUSY_PIN, 0);
|
||||||
|
|
||||||
|
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||||
|
}
|
||||||
|
/******************************************************************************
|
||||||
|
function: Module Initialize, the library and initialize the pins, SPI protocol
|
||||||
|
parameter:
|
||||||
|
Info:
|
||||||
|
******************************************************************************/
|
||||||
|
UBYTE DEV_Module_Init(void)
|
||||||
|
{
|
||||||
|
printf("/***********************************/ \r\n");
|
||||||
|
if(DEV_Equipment_Testing() < 0) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
if(!bcm2835_init()) {
|
||||||
|
printf("bcm2835 init failed !!! \r\n");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
printf("bcm2835 init success !!! \r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// GPIO Config
|
||||||
|
DEV_GPIO_Init();
|
||||||
|
|
||||||
|
bcm2835_spi_begin(); //Start spi interface, set spi pin for the reuse function
|
||||||
|
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST); //High first transmission
|
||||||
|
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0); //spi mode 0
|
||||||
|
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_128); //Frequency
|
||||||
|
bcm2835_spi_chipSelect(BCM2835_SPI_CS0); //set CE0
|
||||||
|
bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW); //enable cs0
|
||||||
|
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
//if(wiringPiSetup() < 0)//use wiringpi Pin number table
|
||||||
|
if(wiringPiSetupGpio() < 0) { //use BCM2835 Pin number table
|
||||||
|
printf("set wiringPi lib failed !!! \r\n");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
printf("set wiringPi lib success !!! \r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// GPIO Config
|
||||||
|
DEV_GPIO_Init();
|
||||||
|
wiringPiSPISetup(0,10000000);
|
||||||
|
// wiringPiSPISetupMode(0, 32000000, 0);
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
printf("Write and read /dev/spidev0.0 \r\n");
|
||||||
|
DEV_GPIO_Init();
|
||||||
|
DEV_HARDWARE_SPI_begin("/dev/spidev0.0");
|
||||||
|
DEV_HARDWARE_SPI_setSpeed(10000000);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif JETSON
|
||||||
|
#ifdef USE_DEV_LIB
|
||||||
|
DEV_GPIO_Init();
|
||||||
|
printf("Software spi\r\n");
|
||||||
|
SYSFS_software_spi_begin();
|
||||||
|
SYSFS_software_spi_setBitOrder(SOFTWARE_SPI_MSBFIRST);
|
||||||
|
SYSFS_software_spi_setDataMode(SOFTWARE_SPI_Mode0);
|
||||||
|
SYSFS_software_spi_setClockDivider(SOFTWARE_SPI_CLOCK_DIV4);
|
||||||
|
#elif USE_HARDWARE_LIB
|
||||||
|
printf("Write and read /dev/spidev0.0 \r\n");
|
||||||
|
DEV_GPIO_Init();
|
||||||
|
DEV_HARDWARE_SPI_begin("/dev/spidev0.0");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
printf("/***********************************/ \r\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function: Module exits, closes SPI and BCM2835 library
|
||||||
|
parameter:
|
||||||
|
Info:
|
||||||
|
******************************************************************************/
|
||||||
|
void DEV_Module_Exit(void)
|
||||||
|
{
|
||||||
|
#ifdef RPI
|
||||||
|
#ifdef USE_BCM2835_LIB
|
||||||
|
DEV_Digital_Write(EPD_CS_PIN, LOW);
|
||||||
|
DEV_Digital_Write(EPD_DC_PIN, LOW);
|
||||||
|
DEV_Digital_Write(EPD_RST_PIN, LOW);
|
||||||
|
|
||||||
|
bcm2835_spi_end();
|
||||||
|
bcm2835_close();
|
||||||
|
#elif USE_WIRINGPI_LIB
|
||||||
|
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||||
|
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||||
|
DEV_Digital_Write(EPD_RST_PIN, 0);
|
||||||
|
#elif USE_DEV_LIB
|
||||||
|
DEV_HARDWARE_SPI_end();
|
||||||
|
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||||
|
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||||
|
DEV_Digital_Write(EPD_RST_PIN, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif JETSON
|
||||||
|
#ifdef USE_DEV_LIB
|
||||||
|
SYSFS_GPIO_Unexport(EPD_CS_PIN);
|
||||||
|
SYSFS_GPIO_Unexport(EPD_DC_PIN);
|
||||||
|
SYSFS_GPIO_Unexport(EPD_RST_PIN);
|
||||||
|
SYSFS_GPIO_Unexport(EPD_BUSY_PIN);
|
||||||
|
#elif USE_HARDWARE_LIB
|
||||||
|
Debug("not support");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
321
waveshare/src/EPD_7in5_V2.c
Normal file
321
waveshare/src/EPD_7in5_V2.c
Normal file
@@ -0,0 +1,321 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* | File : EPD_7in5.c
|
||||||
|
* | Author : Waveshare team
|
||||||
|
* | Function : Electronic paper driver
|
||||||
|
* | Info :
|
||||||
|
*----------------
|
||||||
|
* | This version: V2.0
|
||||||
|
* | Date : 2018-11-09
|
||||||
|
* | Info :
|
||||||
|
*****************************************************************************
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documnetation files(the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in
|
||||||
|
# all copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
# THE SOFTWARE.
|
||||||
|
#
|
||||||
|
******************************************************************************/
|
||||||
|
#include "EPD_7in5_V2.h"
|
||||||
|
#include "Debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
UBYTE Voltage_Frame_7IN5_V2[]={
|
||||||
|
0x6, 0x3F, 0x3F, 0x11, 0x24, 0x7, 0x17,
|
||||||
|
};
|
||||||
|
|
||||||
|
UBYTE LUT_VCOM_7IN5_V2[]={
|
||||||
|
0x0, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x0, 0xF, 0x1, 0xF, 0x1, 0x2,
|
||||||
|
0x0, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
};
|
||||||
|
|
||||||
|
UBYTE LUT_WW_7IN5_V2[]={
|
||||||
|
0x10, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
|
||||||
|
0x20, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
};
|
||||||
|
|
||||||
|
UBYTE LUT_BW_7IN5_V2[]={
|
||||||
|
0x10, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
|
||||||
|
0x20, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
};
|
||||||
|
|
||||||
|
UBYTE LUT_WB_7IN5_V2[]={
|
||||||
|
0x80, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
|
||||||
|
0x40, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
};
|
||||||
|
|
||||||
|
UBYTE LUT_BB_7IN5_V2[]={
|
||||||
|
0x80, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x84, 0xF, 0x1, 0xF, 0x1, 0x2,
|
||||||
|
0x40, 0xF, 0xF, 0x0, 0x0, 0x1,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : Software reset
|
||||||
|
parameter:
|
||||||
|
******************************************************************************/
|
||||||
|
static void EPD_Reset(void)
|
||||||
|
{
|
||||||
|
DEV_Digital_Write(EPD_RST_PIN, 1);
|
||||||
|
DEV_Delay_ms(20);
|
||||||
|
DEV_Digital_Write(EPD_RST_PIN, 0);
|
||||||
|
DEV_Delay_ms(2);
|
||||||
|
DEV_Digital_Write(EPD_RST_PIN, 1);
|
||||||
|
DEV_Delay_ms(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : send command
|
||||||
|
parameter:
|
||||||
|
Reg : Command register
|
||||||
|
******************************************************************************/
|
||||||
|
static void EPD_SendCommand(UBYTE Reg)
|
||||||
|
{
|
||||||
|
DEV_Digital_Write(EPD_DC_PIN, 0);
|
||||||
|
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||||
|
DEV_SPI_WriteByte(Reg);
|
||||||
|
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : send data
|
||||||
|
parameter:
|
||||||
|
Data : Write data
|
||||||
|
******************************************************************************/
|
||||||
|
static void EPD_SendData(UBYTE Data)
|
||||||
|
{
|
||||||
|
DEV_Digital_Write(EPD_DC_PIN, 1);
|
||||||
|
DEV_Digital_Write(EPD_CS_PIN, 0);
|
||||||
|
DEV_SPI_WriteByte(Data);
|
||||||
|
DEV_Digital_Write(EPD_CS_PIN, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : Wait until the busy_pin goes LOW
|
||||||
|
parameter:
|
||||||
|
******************************************************************************/
|
||||||
|
static void EPD_WaitUntilIdle(void)
|
||||||
|
{
|
||||||
|
Debug("e-Paper busy\r\n");
|
||||||
|
do{
|
||||||
|
DEV_Delay_ms(5);
|
||||||
|
}while(!(DEV_Digital_Read(EPD_BUSY_PIN)));
|
||||||
|
DEV_Delay_ms(5);
|
||||||
|
Debug("e-Paper busy release\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EPD_7IN5_V2_LUT(UBYTE* lut_vcom, UBYTE* lut_ww, UBYTE* lut_bw, UBYTE* lut_wb, UBYTE* lut_bb)
|
||||||
|
{
|
||||||
|
UBYTE count;
|
||||||
|
|
||||||
|
EPD_SendCommand(0x20); //VCOM
|
||||||
|
for(count=0; count<42; count++)
|
||||||
|
EPD_SendData(lut_vcom[count]);
|
||||||
|
|
||||||
|
EPD_SendCommand(0x21); //LUTBW
|
||||||
|
for(count=0; count<42; count++)
|
||||||
|
EPD_SendData(lut_ww[count]);
|
||||||
|
|
||||||
|
EPD_SendCommand(0x22); //LUTBW
|
||||||
|
for(count=0; count<42; count++)
|
||||||
|
EPD_SendData(lut_bw[count]);
|
||||||
|
|
||||||
|
EPD_SendCommand(0x23); //LUTWB
|
||||||
|
for(count=0; count<42; count++)
|
||||||
|
EPD_SendData(lut_wb[count]);
|
||||||
|
|
||||||
|
EPD_SendCommand(0x24); //LUTBB
|
||||||
|
for(count=0; count<42; count++)
|
||||||
|
EPD_SendData(lut_bb[count]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : Turn On Display
|
||||||
|
parameter:
|
||||||
|
******************************************************************************/
|
||||||
|
static void EPD_7IN5_V2_TurnOnDisplay(void)
|
||||||
|
{
|
||||||
|
EPD_SendCommand(0x12); //DISPLAY REFRESH
|
||||||
|
DEV_Delay_ms(100); //!!!The delay here is necessary, 200uS at least!!!
|
||||||
|
EPD_WaitUntilIdle();
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : Initialize the e-Paper register
|
||||||
|
parameter:
|
||||||
|
******************************************************************************/
|
||||||
|
UBYTE EPD_7IN5_V2_Init(void)
|
||||||
|
{
|
||||||
|
EPD_Reset();
|
||||||
|
|
||||||
|
// EPD_SendCommand(0x01); //POWER SETTING
|
||||||
|
// EPD_SendData(0x07);
|
||||||
|
// EPD_SendData(0x07); //VGH=20V,VGL=-20V
|
||||||
|
// EPD_SendData(0x3f); //VDH=15V
|
||||||
|
// EPD_SendData(0x3f); //VDL=-15V
|
||||||
|
|
||||||
|
EPD_SendCommand(0x01); // power setting
|
||||||
|
EPD_SendData(0x17); // 1-0=11: internal power
|
||||||
|
EPD_SendData(*(Voltage_Frame_7IN5_V2+6)); // VGH&VGL
|
||||||
|
EPD_SendData(*(Voltage_Frame_7IN5_V2+1)); // VSH
|
||||||
|
EPD_SendData(*(Voltage_Frame_7IN5_V2+2)); // VSL
|
||||||
|
EPD_SendData(*(Voltage_Frame_7IN5_V2+3)); // VSHR
|
||||||
|
|
||||||
|
EPD_SendCommand(0x82); // VCOM DC Setting
|
||||||
|
EPD_SendData(*(Voltage_Frame_7IN5_V2+4)); // VCOM
|
||||||
|
|
||||||
|
EPD_SendCommand(0x06); // Booster Setting
|
||||||
|
EPD_SendData(0x27);
|
||||||
|
EPD_SendData(0x27);
|
||||||
|
EPD_SendData(0x2F);
|
||||||
|
EPD_SendData(0x17);
|
||||||
|
|
||||||
|
EPD_SendCommand(0x30); // OSC Setting
|
||||||
|
EPD_SendData(*(Voltage_Frame_7IN5_V2+0)); // 2-0=100: N=4 ; 5-3=111: M=7 ; 3C=50Hz 3A=100HZ
|
||||||
|
|
||||||
|
EPD_SendCommand(0x04); //POWER ON
|
||||||
|
DEV_Delay_ms(100);
|
||||||
|
EPD_WaitUntilIdle();
|
||||||
|
|
||||||
|
EPD_SendCommand(0X00); //PANNEL SETTING
|
||||||
|
EPD_SendData(0x3F); //KW-3f KWR-2F BWROTP 0f BWOTP 1f
|
||||||
|
|
||||||
|
EPD_SendCommand(0x61); //tres
|
||||||
|
EPD_SendData(0x03); //source 800
|
||||||
|
EPD_SendData(0x20);
|
||||||
|
EPD_SendData(0x01); //gate 480
|
||||||
|
EPD_SendData(0xE0);
|
||||||
|
|
||||||
|
EPD_SendCommand(0X15);
|
||||||
|
EPD_SendData(0x00);
|
||||||
|
|
||||||
|
EPD_SendCommand(0X50); //VCOM AND DATA INTERVAL SETTING
|
||||||
|
EPD_SendData(0x10);
|
||||||
|
EPD_SendData(0x00);
|
||||||
|
|
||||||
|
EPD_SendCommand(0X60); //TCON SETTING
|
||||||
|
EPD_SendData(0x22);
|
||||||
|
|
||||||
|
EPD_SendCommand(0x65); // Resolution setting
|
||||||
|
EPD_SendData(0x00);
|
||||||
|
EPD_SendData(0x00);//800*480
|
||||||
|
EPD_SendData(0x00);
|
||||||
|
EPD_SendData(0x00);
|
||||||
|
|
||||||
|
EPD_7IN5_V2_LUT(LUT_VCOM_7IN5_V2, LUT_WW_7IN5_V2, LUT_BW_7IN5_V2, LUT_WB_7IN5_V2, LUT_BB_7IN5_V2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : Clear screen
|
||||||
|
parameter:
|
||||||
|
******************************************************************************/
|
||||||
|
void EPD_7IN5_V2_Clear(void)
|
||||||
|
{
|
||||||
|
UWORD Width, Height;
|
||||||
|
Width =(EPD_7IN5_V2_WIDTH % 8 == 0)?(EPD_7IN5_V2_WIDTH / 8 ):(EPD_7IN5_V2_WIDTH / 8 + 1);
|
||||||
|
Height = EPD_7IN5_V2_HEIGHT;
|
||||||
|
|
||||||
|
UWORD i;
|
||||||
|
EPD_SendCommand(0x10);
|
||||||
|
for(i=0; i<Height*Width; i++) {
|
||||||
|
EPD_SendData(0xFF);
|
||||||
|
}
|
||||||
|
EPD_SendCommand(0x13);
|
||||||
|
for(i=0; i<Height*Width; i++) {
|
||||||
|
EPD_SendData(0x00);
|
||||||
|
}
|
||||||
|
EPD_7IN5_V2_TurnOnDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EPD_7IN5_V2_ClearBlack(void)
|
||||||
|
{
|
||||||
|
UWORD Width, Height;
|
||||||
|
Width =(EPD_7IN5_V2_WIDTH % 8 == 0)?(EPD_7IN5_V2_WIDTH / 8 ):(EPD_7IN5_V2_WIDTH / 8 + 1);
|
||||||
|
Height = EPD_7IN5_V2_HEIGHT;
|
||||||
|
|
||||||
|
UWORD i;
|
||||||
|
EPD_SendCommand(0x10);
|
||||||
|
for(i=0; i<Height*Width; i++) {
|
||||||
|
EPD_SendData(0x00);
|
||||||
|
}
|
||||||
|
EPD_SendCommand(0x13);
|
||||||
|
for(i=0; i<Height*Width; i++) {
|
||||||
|
EPD_SendData(0xFF);
|
||||||
|
}
|
||||||
|
EPD_7IN5_V2_TurnOnDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : Sends the image buffer in RAM to e-Paper and displays
|
||||||
|
parameter:
|
||||||
|
******************************************************************************/
|
||||||
|
void EPD_7IN5_V2_Display(const UBYTE *blackimage)
|
||||||
|
{
|
||||||
|
UDOUBLE Width, Height;
|
||||||
|
Width =(EPD_7IN5_V2_WIDTH % 8 == 0)?(EPD_7IN5_V2_WIDTH / 8 ):(EPD_7IN5_V2_WIDTH / 8 + 1);
|
||||||
|
Height = EPD_7IN5_V2_HEIGHT;
|
||||||
|
|
||||||
|
// EPD_SendCommand(0x10);
|
||||||
|
// for (UDOUBLE j = 0; j < Height; j++) {
|
||||||
|
// for (UDOUBLE i = 0; i < Width; i++) {
|
||||||
|
// EPD_SendData(blackimage[i + j * Width]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
EPD_SendCommand(0x13);
|
||||||
|
for (UDOUBLE j = 0; j < Height; j++) {
|
||||||
|
for (UDOUBLE i = 0; i < Width; i++) {
|
||||||
|
EPD_SendData(~blackimage[i + j * Width]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EPD_7IN5_V2_TurnOnDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
function : Enter sleep mode
|
||||||
|
parameter:
|
||||||
|
******************************************************************************/
|
||||||
|
void EPD_7IN5_V2_Sleep(void)
|
||||||
|
{
|
||||||
|
EPD_SendCommand(0X02); //power off
|
||||||
|
EPD_WaitUntilIdle();
|
||||||
|
EPD_SendCommand(0X07); //deep sleep
|
||||||
|
EPD_SendData(0xA5);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user