From 266114d0468845b90b28c9c654619607c8cd6ad7 Mon Sep 17 00:00:00 2001 From: Peter Siegmund Date: Mon, 9 Jun 2025 00:17:54 +0200 Subject: [PATCH] handle mouse events Signed-off-by: Peter Siegmund --- .clang-format | 247 +--------------- CMakeLists.txt | 170 ++++++----- components/CMakeLists.txt | 4 +- components/imgui/CMakeLists.txt | 4 +- components/justus/CMakeLists.txt | 26 +- components/justus/include/MenuOptions.h | 7 +- components/justus/include/common/PSMenu.h | 15 +- components/justus/include/common/ScrollBar.h | 7 +- components/justus/include/common/Widget.h | 11 +- components/justus/include/data/MenuItem.h | 13 +- components/justus/include/ui/LightMenu.h | 4 +- components/justus/include/ui/MainMenu.h | 11 +- components/justus/include/ui/SettingsMenu.h | 4 +- components/justus/include/ui/SplashScreen.h | 11 +- components/justus/src/common/PSMenu.cpp | 101 ++++--- components/justus/src/common/ScrollBar.cpp | 36 +-- components/justus/src/common/Widget.cpp | 13 +- components/justus/src/data/MenuItem.cpp | 20 +- components/justus/src/ui/LightMenu.cpp | 2 +- components/justus/src/ui/MainMenu.cpp | 14 +- components/justus/src/ui/SettingsMenu.cpp | 2 +- components/justus/src/ui/SplashScreen.cpp | 17 +- components/peter/CMakeLists.txt | 12 +- main/button_handling.c | 49 ++-- main/button_handling.h | 5 +- main/common.h | 10 +- main/main.c | 18 +- main/setup.c | 49 ++-- main/setup.h | 7 +- src/Common.cpp | 9 +- src/Common.h | 2 +- src/ResourceManager.cpp | 94 +++++-- src/ResourceManager.h | 54 +++- src/debug/DebugOverlay.cpp | 57 ++-- src/debug/DebugOverlay.h | 15 +- src/hal/u8g2_hal_sdl.h | 10 +- src/hal/u8x8_hal_sdl.cpp | 12 +- src/main.cc | 160 ----------- src/main.cpp | 180 ++++++++++++ src/model/AppContext.cpp | 35 ++- src/model/AppContext.h | 42 +-- src/model/Window.cpp | 6 +- src/model/Window.h | 17 +- src/ui/Device.cpp | 280 ++++++++++++------- src/ui/Device.h | 40 +-- src/ui/Matrix.cpp | 27 +- src/ui/Matrix.h | 17 +- src/ui/UIWidget.cpp | 6 +- src/ui/UIWidget.h | 13 +- src/ui/widgets/Button.cpp | 57 ++-- src/ui/widgets/Button.h | 16 +- src/ui/widgets/D_Pad.cpp | 88 +++++- src/ui/widgets/D_Pad.h | 26 +- 53 files changed, 1144 insertions(+), 1008 deletions(-) delete mode 100644 src/main.cc create mode 100644 src/main.cpp diff --git a/.clang-format b/.clang-format index 8d1d1c0..515162e 100644 --- a/.clang-format +++ b/.clang-format @@ -1,247 +1,2 @@ --- -BasedOnStyle: Chromium -Language: Cpp -AccessModifierOffset: -4 -AlignAfterOpenBracket: AlwaysBreak -AlignArrayOfStructures: None -AlignConsecutiveAssignments: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - AlignFunctionPointers: false - PadOperators: true -AlignConsecutiveBitFields: - Enabled: true - AcrossEmptyLines: true - AcrossComments: true - AlignCompound: false - AlignFunctionPointers: false - PadOperators: true -AlignConsecutiveDeclarations: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - AlignFunctionPointers: false - PadOperators: true -AlignConsecutiveMacros: - Enabled: true - AcrossEmptyLines: false - AcrossComments: true - AlignCompound: true - AlignFunctionPointers: false - PadOperators: true -AlignConsecutiveShortCaseStatements: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCaseColons: false -AlignEscapedNewlines: Left -AlignOperands: Align -AlignTrailingComments: - Kind: Never - OverEmptyLines: 0 -AllowAllArgumentsOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: false -AllowBreakBeforeNoexceptSpecifier: Never -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false -AllowShortCompoundRequirementOnASingleLine: true -AllowShortEnumsOnASingleLine: false -AllowShortFunctionsOnASingleLine: None -AllowShortIfStatementsOnASingleLine: WithoutElse -AllowShortLambdasOnASingleLine: All -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -AttributeMacros: - - __capability -BinPackArguments: false -BinPackParameters: false -BitFieldColonSpacing: Both -BraceWrapping: - AfterCaseLabel: false - AfterClass: false - AfterControlStatement: Never - AfterEnum: false - AfterExternBlock: false - AfterFunction: false - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: false - AfterUnion: false - BeforeCatch: false - BeforeElse: false - BeforeLambdaBody: false - BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: true - SplitEmptyRecord: true - SplitEmptyNamespace: true -BreakAdjacentStringLiterals: true -BreakAfterAttributes: Leave -BreakAfterJavaFieldAnnotations: false -BreakArrays: true -BreakBeforeBinaryOperators: None -BreakBeforeConceptDeclarations: Always -BreakBeforeBraces: Attach -BreakBeforeInlineASMColon: OnlyMultiline -BreakBeforeTernaryOperators: false -BreakConstructorInitializers: BeforeComma -BreakInheritanceList: BeforeColon -BreakStringLiterals: false -ColumnLimit: 99 -CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false -EmptyLineAfterAccessModifier: Never -EmptyLineBeforeAccessModifier: LogicalBlock -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: false -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH - - M_EACH -IfMacros: - - KJ_IF_MAYBE -IncludeBlocks: Preserve -IncludeCategories: - - Regex: '.*' - Priority: 1 - SortPriority: 0 - CaseSensitive: false - - Regex: '^(<|"(gtest|gmock|isl|json)/)' - Priority: 3 - SortPriority: 0 - CaseSensitive: false - - Regex: '.*' - Priority: 1 - SortPriority: 0 - CaseSensitive: false -IncludeIsMainRegex: '(Test)?$' -IncludeIsMainSourceRegex: '' -IndentAccessModifiers: false -IndentCaseBlocks: false -IndentCaseLabels: false -IndentExternBlock: AfterExternBlock -IndentGotoLabels: true -IndentPPDirectives: None -IndentRequiresClause: false -IndentWidth: 4 -IndentWrappedFunctionNames: true -InsertBraces: false -InsertNewlineAtEOF: true -InsertTrailingCommas: None -IntegerLiteralSeparator: - Binary: 0 - BinaryMinDigits: 0 - Decimal: 0 - DecimalMinDigits: 0 - Hex: 0 - HexMinDigits: 0 -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: false -KeepEmptyLinesAtEOF: false -LambdaBodyIndentation: Signature -LineEnding: DeriveLF -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 4 -ObjCBreakBeforeNestedBlockParam: true -ObjCSpaceAfterProperty: true -ObjCSpaceBeforeProtocolList: true -PackConstructorInitializers: BinPack -PenaltyBreakAssignment: 10 -PenaltyBreakBeforeFirstCallParameter: 30 -PenaltyBreakComment: 10 -PenaltyBreakFirstLessLess: 0 -PenaltyBreakOpenParenthesis: 0 -PenaltyBreakScopeResolution: 500 -PenaltyBreakString: 10 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 100 -PenaltyIndentedWhitespace: 0 -PenaltyReturnTypeOnItsOwnLine: 60 -PointerAlignment: Left -PPIndentWidth: -1 -QualifierAlignment: Leave -ReferenceAlignment: Pointer -ReflowComments: false -RemoveBracesLLVM: false -RemoveParentheses: Leave -RemoveSemicolon: true -RequiresClausePosition: OwnLine -RequiresExpressionIndentation: OuterScope -SeparateDefinitionBlocks: Leave -ShortNamespaceLines: 1 -SkipMacroDefinitionBody: false -SortIncludes: Never -SortJavaStaticImport: Before -SortUsingDeclarations: Never -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceAroundPointerQualifiers: Default -SpaceBeforeAssignmentOperators: true -SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeJsonColon: false -SpaceBeforeParens: Never -SpaceBeforeParensOptions: - AfterControlStatements: false - AfterForeachMacros: false - AfterFunctionDefinitionName: false - AfterFunctionDeclarationName: false - AfterIfMacros: false - AfterOverloadedOperator: false - AfterPlacementOperator: true - AfterRequiresInClause: false - AfterRequiresInExpression: false - BeforeNonEmptyParentheses: false -SpaceBeforeRangeBasedForLoopColon: true -SpaceBeforeSquareBrackets: false -SpaceInEmptyBlock: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: Never -SpacesInContainerLiterals: false -SpacesInLineCommentPrefix: - Minimum: 1 - Maximum: -1 -SpacesInParens: Never -SpacesInParensOptions: - InCStyleCasts: false - InConditionalStatements: false - InEmptyParentheses: false - Other: false -SpacesInSquareBrackets: false -Standard: c++20 -StatementAttributeLikeMacros: - - Q_EMIT -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 4 -UseTab: Never -VerilogBreakBetweenInstancePorts: true -WhitespaceSensitiveMacros: - - STRINGIZE - - PP_STRINGIZE - - BOOST_PP_STRINGIZE - - NS_SWIFT_NAME - - CF_SWIFT_NAME -... - +BasedOnStyle: Microsoft diff --git a/CMakeLists.txt b/CMakeLists.txt index 1cdb311..4ea0597 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,90 +1,106 @@ cmake_minimum_required(VERSION 3.30) if (DEFINED ENV{IDF_PATH}) -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(espidf_system_control) -return() -else() + include($ENV{IDF_PATH}/tools/cmake/project.cmake) + project(espidf_system_control) + return() +else () + set(MAJOR_VERSION 0) + set(MINOR_VERSION 0) + set(MICRO_VERSION 1) -set(MAJOR_VERSION 0) -set(MINOR_VERSION 0) -set(MICRO_VERSION 1) - -project( - system_control - LANGUAGES CXX C - VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}" -) - -set(CMAKE_C_STANDARD 23) -set(CMAKE_CXX_STANDARD 23) -set(CMAKE_CXX_STANDARD_REQUIRED YES) -set(CMAKE_CXX_EXTENSIONS YES) - -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_INCLUDE_PATH include) -set(CMAKE_SOURCE_DIR src) -set(CMAKE_MODULE_PATH cmake) - -include(FetchContent) -function(include_dependency libName gitURL gitTag) - FetchContent_Declare(${libName} - GIT_REPOSITORY ${gitURL} - GIT_TAG ${gitTag} - GIT_SHALLOW TRUE - GIT_PROGRESS FALSE + project( + SystemControl + LANGUAGES CXX C + VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}" ) - FetchContent_MakeAvailable(${libName}) -endfunction() -include_dependency(SDL3 https://github.com/libsdl-org/SDL release-3.2.8) -include_dependency(SDL_image https://github.com/libsdl-org/SDL_image release-3.2.4) -include_dependency(SDL_ttf https://github.com/libsdl-org/SDL_ttf release-3.2.0) -include_dependency(u8g2 https://github.com/olikraus/u8g2 master) + set(CMAKE_C_STANDARD 23) + set(CMAKE_CXX_STANDARD 23) + set(CMAKE_CXX_STANDARD_REQUIRED YES) + set(CMAKE_CXX_EXTENSIONS YES) -add_subdirectory(components) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) + set(CMAKE_INCLUDE_PATH include) + set(CMAKE_SOURCE_DIR src) + set(CMAKE_MODULE_PATH cmake) -configure_file( - "${CMAKE_SOURCE_DIR}/Version.h.in" - "${CMAKE_SOURCE_DIR}/Version.h" -) + include(FetchContent) + function(include_dependency libName gitURL gitTag) + FetchContent_Declare(${libName} + GIT_REPOSITORY ${gitURL} + GIT_TAG ${gitTag} + GIT_SHALLOW TRUE + GIT_PROGRESS FALSE + ) + FetchContent_MakeAvailable(${libName}) + endfunction() -include_directories( - ${CMAKE_INCLUDE_PATH} - ${CMAKE_SOURCE_DIR} - ${PROJECT_BINARY_DIR}/src -) + include_dependency(SDL3 https://github.com/libsdl-org/SDL release-3.2.x) + include_dependency(SDL_image https://github.com/libsdl-org/SDL_image release-3.2.x) + include_dependency(SDL_ttf https://github.com/libsdl-org/SDL_ttf release-3.2.x) + include_dependency(u8g2 https://github.com/olikraus/u8g2 master) -add_executable(${PROJECT_NAME} - ${CMAKE_SOURCE_DIR}/main.cc - ${CMAKE_SOURCE_DIR}/Common.cpp - ${CMAKE_SOURCE_DIR}/ResourceManager.cpp - ${CMAKE_SOURCE_DIR}/debug/DebugOverlay.cpp - ${CMAKE_SOURCE_DIR}/hal/u8x8_hal_sdl.cpp - ${CMAKE_SOURCE_DIR}/model/AppContext.cpp - ${CMAKE_SOURCE_DIR}/model/Window.cpp - ${CMAKE_SOURCE_DIR}/ui/Device.cpp - ${CMAKE_SOURCE_DIR}/ui/Matrix.cpp - ${CMAKE_SOURCE_DIR}/ui/UIWidget.cpp - ${CMAKE_SOURCE_DIR}/ui/widgets/Button.cpp - ${CMAKE_SOURCE_DIR}/ui/widgets/D_Pad.cpp -) + add_subdirectory(components) -target_compile_definitions(${PROJECT_NAME} PRIVATE SDL_MAIN_USE_CALLBACKS) + configure_file( + "${CMAKE_SOURCE_DIR}/Version.h.in" + "${CMAKE_SOURCE_DIR}/Version.h" + ) -target_link_libraries(${PROJECT_NAME} PRIVATE - ImGui - justus - peter - SDL3::SDL3 - SDL3_image::SDL3_image - SDL3_ttf::SDL3_ttf - u8g2 -) + include_directories( + ${CMAKE_INCLUDE_PATH} + ${CMAKE_SOURCE_DIR} + ${PROJECT_BINARY_DIR}/src + ) -add_custom_command( - TARGET ${PROJECT_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${PROJECT_SOURCE_DIR}/assets ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/assets -) -endif() + add_executable(${PROJECT_NAME} + WIN32 MACOSX_BUNDLE + ${CMAKE_SOURCE_DIR}/main.cpp + ${CMAKE_SOURCE_DIR}/Common.cpp + ${CMAKE_SOURCE_DIR}/ResourceManager.cpp + ${CMAKE_SOURCE_DIR}/debug/DebugOverlay.cpp + ${CMAKE_SOURCE_DIR}/hal/u8x8_hal_sdl.cpp + ${CMAKE_SOURCE_DIR}/model/AppContext.cpp + ${CMAKE_SOURCE_DIR}/model/Window.cpp + ${CMAKE_SOURCE_DIR}/ui/Device.cpp + ${CMAKE_SOURCE_DIR}/ui/Matrix.cpp + ${CMAKE_SOURCE_DIR}/ui/UIWidget.cpp + ${CMAKE_SOURCE_DIR}/ui/widgets/Button.cpp + ${CMAKE_SOURCE_DIR}/ui/widgets/D_Pad.cpp + ) + + if (APPLE) + # copy assets to bundle directory + set(ASSETS_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/assets) + set(ASSETS_DEST_DIR $/Contents/Resources) + + if (EXISTS ${ASSETS_SRC_DIR}) + add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${ASSETS_SRC_DIR} ${ASSETS_DEST_DIR} + COMMENT "Copying assets to bundle via custom command" + VERBATIM + ) + else () + message(WARNING "Assets source directory ${ASSETS_SRC_DIR} does not exist. Skipping custom command.") + endif () + elseif (WINDOWS) + add_custom_command( + TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${PROJECT_SOURCE_DIR}/assets ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/assets + ) + endif () + target_compile_definitions(${PROJECT_NAME} PRIVATE SDL_MAIN_USE_CALLBACKS) + + target_link_libraries(${PROJECT_NAME} PRIVATE + ImGui + justus + peter + SDL3::SDL3 + SDL3_image::SDL3_image + SDL3_ttf::SDL3_ttf + u8g2 + ) +endif () diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 5eedb52..4d0a668 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -1,6 +1,6 @@ if (DEFINED ENV{IDF_PATH}) -return() -endif() + return() +endif () add_library(components INTERFACE) diff --git a/components/imgui/CMakeLists.txt b/components/imgui/CMakeLists.txt index 58d2de2..de3037f 100644 --- a/components/imgui/CMakeLists.txt +++ b/components/imgui/CMakeLists.txt @@ -1,6 +1,6 @@ if (DEFINED ENV{IDF_PATH}) -return() -endif() + return() +endif () cmake_minimum_required(VERSION 3.30) project(ImGui) diff --git a/components/justus/CMakeLists.txt b/components/justus/CMakeLists.txt index 8758e74..3583ce1 100644 --- a/components/justus/CMakeLists.txt +++ b/components/justus/CMakeLists.txt @@ -1,17 +1,17 @@ if (DEFINED ENV{IDF_PATH}) -idf_component_register(SRCS - src/common/PSMenu.cpp - src/common/ScrollBar.cpp - src/common/Widget.cpp - src/data/MenuItem.cpp - src/ui/LightMenu.cpp - src/ui/MainMenu.cpp - src/ui/SettingsMenu.cpp - src/ui/SplashScreen.cpp - INCLUDE_DIRS "include" -) -return() -endif() + idf_component_register(SRCS + src/common/PSMenu.cpp + src/common/ScrollBar.cpp + src/common/Widget.cpp + src/data/MenuItem.cpp + src/ui/LightMenu.cpp + src/ui/MainMenu.cpp + src/ui/SettingsMenu.cpp + src/ui/SplashScreen.cpp + INCLUDE_DIRS "include" + ) + return() +endif () cmake_minimum_required(VERSION 3.30) project(justus) diff --git a/components/justus/include/MenuOptions.h b/components/justus/include/MenuOptions.h index 76a6d1a..e5a683d 100644 --- a/components/justus/include/MenuOptions.h +++ b/components/justus/include/MenuOptions.h @@ -3,13 +3,14 @@ #include #include -#include "u8g2.h" #include "common/Widget.h" +#include "u8g2.h" class Widget; -typedef struct { - u8g2_t* u8g2; +typedef struct +{ + u8g2_t *u8g2; std::function)> setScreen; std::function)> pushScreen; diff --git a/components/justus/include/common/PSMenu.h b/components/justus/include/common/PSMenu.h index 267b277..135b266 100644 --- a/components/justus/include/common/PSMenu.h +++ b/components/justus/include/common/PSMenu.h @@ -8,19 +8,20 @@ typedef std::function MenuCallback; -class PSMenu : public Widget { -public: - explicit PSMenu(menu_options_t* options); +class PSMenu : public Widget +{ + public: + explicit PSMenu(menu_options_t *options); ~PSMenu() override; void render() override; void onButtonClicked(uint8_t button) override; - void addText(const std::string& text, const MenuCallback& callback); - void addSwitch(const std::string& text, std::string& value, const MenuCallback& callback); - void addNumber(const std::string& text, std::string& value, const MenuCallback& callback); + void addText(const std::string &text, const MenuCallback &callback); + void addSwitch(const std::string &text, std::string &value, const MenuCallback &callback); + void addNumber(const std::string &text, std::string &value, const MenuCallback &callback); -private: + private: void onPressedDown(); void onPressedUp(); void onPressedLeft(); diff --git a/components/justus/include/common/ScrollBar.h b/components/justus/include/common/ScrollBar.h index 9d23f68..9292d67 100644 --- a/components/justus/include/common/ScrollBar.h +++ b/components/justus/include/common/ScrollBar.h @@ -3,13 +3,14 @@ #include "MenuOptions.h" #include "Widget.h" -class ScrollBar final : public Widget { -public: +class ScrollBar final : public Widget +{ + public: ScrollBar(const menu_options_t *options, size_t x, size_t y, size_t width, size_t height); void render() override; void refresh(size_t value, size_t max, size_t min = 0); -private: + private: size_t m_x; size_t m_y; size_t m_width; diff --git a/components/justus/include/common/Widget.h b/components/justus/include/common/Widget.h index f23db32..2f9e58b 100644 --- a/components/justus/include/common/Widget.h +++ b/components/justus/include/common/Widget.h @@ -4,9 +4,10 @@ #include "u8g2.h" -class Widget { -public: - explicit Widget(u8g2_t* u8g2); +class Widget +{ + public: + explicit Widget(u8g2_t *u8g2); virtual ~Widget() = default; @@ -16,6 +17,6 @@ public: virtual void onButtonClicked(uint8_t button); -protected: - u8g2_t* u8g2; + protected: + u8g2_t *u8g2; }; diff --git a/components/justus/include/data/MenuItem.h b/components/justus/include/data/MenuItem.h index 7ee797d..7ad0afe 100644 --- a/components/justus/include/data/MenuItem.h +++ b/components/justus/include/data/MenuItem.h @@ -4,14 +4,11 @@ #include #include -class MenuItem { -public: +class MenuItem +{ + public: MenuItem(uint8_t type, std::string text, std::function callback); - MenuItem( - uint8_t type, - std::string text, - std::string value, - std::function callback); + MenuItem(uint8_t type, std::string text, std::string value, std::function callback); [[nodiscard]] uint8_t getType() const; [[nodiscard]] const std::string &getText() const; [[nodiscard]] const std::string &getValue() const; @@ -19,7 +16,7 @@ public: void callback(uint8_t id) const; [[nodiscard]] bool hasCallback() const; -private: + private: uint8_t m_type; std::string m_text; std::string m_value; diff --git a/components/justus/include/ui/LightMenu.h b/components/justus/include/ui/LightMenu.h index 987f38c..4432703 100644 --- a/components/justus/include/ui/LightMenu.h +++ b/components/justus/include/ui/LightMenu.h @@ -4,6 +4,6 @@ class LightMenu : public PSMenu { -public: - explicit LightMenu(menu_options_t* options); + public: + explicit LightMenu(menu_options_t *options); }; diff --git a/components/justus/include/ui/MainMenu.h b/components/justus/include/ui/MainMenu.h index a53cb32..883aa27 100644 --- a/components/justus/include/ui/MainMenu.h +++ b/components/justus/include/ui/MainMenu.h @@ -2,12 +2,13 @@ #include "common/PSMenu.h" -class MainMenu final : public PSMenu { -public: - explicit MainMenu(menu_options_t* options); +class MainMenu final : public PSMenu +{ + public: + explicit MainMenu(menu_options_t *options); -private: + private: void onSelect(uint8_t id) const; - menu_options_t* m_options; + menu_options_t *m_options; }; diff --git a/components/justus/include/ui/SettingsMenu.h b/components/justus/include/ui/SettingsMenu.h index ef19bfd..79ca2e4 100644 --- a/components/justus/include/ui/SettingsMenu.h +++ b/components/justus/include/ui/SettingsMenu.h @@ -4,6 +4,6 @@ class SettingsMenu : public PSMenu { -public: - explicit SettingsMenu(menu_options_t* options) ; + public: + explicit SettingsMenu(menu_options_t *options); }; diff --git a/components/justus/include/ui/SplashScreen.h b/components/justus/include/ui/SplashScreen.h index 405b2b1..672c424 100644 --- a/components/justus/include/ui/SplashScreen.h +++ b/components/justus/include/ui/SplashScreen.h @@ -3,12 +3,13 @@ #include "MenuOptions.h" #include "common/Widget.h" -class SplashScreen final : public Widget { -public: - explicit SplashScreen(menu_options_t* options); +class SplashScreen final : public Widget +{ + public: + explicit SplashScreen(menu_options_t *options); void update(uint64_t dt) override; void render() override; -private: - menu_options_t* m_options; + private: + menu_options_t *m_options; }; diff --git a/components/justus/src/common/PSMenu.cpp b/components/justus/src/common/PSMenu.cpp index 06e80d7..7ecb784 100644 --- a/components/justus/src/common/PSMenu.cpp +++ b/components/justus/src/common/PSMenu.cpp @@ -1,21 +1,23 @@ #include "common/PSMenu.h" -#include "u8g2.h" -#include "common/ScrollBar.h" #include "PushButton.h" +#include "common/ScrollBar.h" +#include "u8g2.h" -PSMenu::PSMenu(menu_options_t* options) - : Widget(options->u8g2) - , m_options(options) { +PSMenu::PSMenu(menu_options_t *options) : Widget(options->u8g2), m_options(options) +{ m_options->onButtonClicked = [this](const uint8_t button) { onButtonClicked(button); }; } -PSMenu::~PSMenu() { +PSMenu::~PSMenu() +{ m_options->onButtonClicked = nullptr; } -void PSMenu::render() { - if(m_selected_item < 0) { +void PSMenu::render() +{ + if (m_selected_item < 0) + { onPressedDown(); } @@ -29,31 +31,24 @@ void PSMenu::render() { int x = 8; // sure? auto widget = m_items.at(m_selected_item); - renderWidget( - widget.getType(), u8g2_font_helvB08_tr, x, u8g2->height / 2 + 3, widget.getText().c_str()); + renderWidget(widget.getType(), u8g2_font_helvB08_tr, x, u8g2->height / 2 + 3, widget.getText().c_str()); - if(m_selected_item > 0) { + if (m_selected_item > 0) + { auto item = m_items.at(m_selected_item - 1); renderWidget(item.getType(), u8g2_font_haxrcorp4089_tr, x, 14, item.getText().c_str()); } - if(m_selected_item < m_items.size() - 1) { + if (m_selected_item < m_items.size() - 1) + { auto item = m_items.at(m_selected_item + 1); - renderWidget( - item.getType(), - u8g2_font_haxrcorp4089_tr, - x, - u8g2->height - 10, - item.getText().c_str()); + renderWidget(item.getType(), u8g2_font_haxrcorp4089_tr, x, u8g2->height - 10, item.getText().c_str()); } } -void PSMenu::renderWidget( - const uint8_t type, - const uint8_t* font, - const int x, - const int y, - const char* text) const { - switch(type) { +void PSMenu::renderWidget(const uint8_t type, const uint8_t *font, const int x, const int y, const char *text) const +{ + switch (type) + { case 0: // text u8g2_SetFont(u8g2, font); u8g2_DrawStr(u8g2, x, y, text); @@ -64,8 +59,10 @@ void PSMenu::renderWidget( } } -void PSMenu::onButtonClicked(uint8_t button) { - switch(button) { +void PSMenu::onButtonClicked(uint8_t button) +{ + switch (button) + { case BUTTON_UP: onPressedUp(); break; @@ -95,59 +92,77 @@ void PSMenu::onButtonClicked(uint8_t button) { } } -void PSMenu::onPressedDown() { - if(m_selected_item == m_items.size() - 1) { +void PSMenu::onPressedDown() +{ + if (m_selected_item == m_items.size() - 1) + { m_selected_item = 0; - } else { + } + else + { m_selected_item++; } } -void PSMenu::onPressedUp() { - if(m_selected_item == 0) { +void PSMenu::onPressedUp() +{ + if (m_selected_item == 0) + { m_selected_item = m_items.size() - 1; - } else { + } + else + { m_selected_item--; } } -void PSMenu::onPressedLeft() { +void PSMenu::onPressedLeft() +{ // } -void PSMenu::onPressedRight() { +void PSMenu::onPressedRight() +{ /// } -void PSMenu::onPressedSelect() const { +void PSMenu::onPressedSelect() const +{ m_items.at(m_selected_item).callback(m_selected_item); } -void PSMenu::onPressedBack() const { - if(m_options && m_options->popScreen) { +void PSMenu::onPressedBack() const +{ + if (m_options && m_options->popScreen) + { m_options->popScreen(); } } -void PSMenu::addText(const std::string& text, const MenuCallback& callback) { +void PSMenu::addText(const std::string &text, const MenuCallback &callback) +{ m_items.emplace_back(0, text, callback); } -void PSMenu::addSwitch(const std::string& text, std::string& value, const MenuCallback& callback) { +void PSMenu::addSwitch(const std::string &text, std::string &value, const MenuCallback &callback) +{ m_items.emplace_back(1, text, value, callback); } -void PSMenu::addNumber(const std::string& text, std::string& value, const MenuCallback& callback) { +void PSMenu::addNumber(const std::string &text, std::string &value, const MenuCallback &callback) +{ m_items.emplace_back(2, text, value, callback); } -void PSMenu::drawScrollBar() const { +void PSMenu::drawScrollBar() const +{ ScrollBar scrollBar(m_options, u8g2->width - 3, 3, 1, u8g2->height - 6); scrollBar.refresh(m_selected_item, m_items.size()); scrollBar.render(); } -void PSMenu::drawSelectionBox() const { +void PSMenu::drawSelectionBox() const +{ const auto displayHeight = u8g2->height; const auto displayWidth = u8g2->width; constexpr auto rightPadding = 8; diff --git a/components/justus/src/common/ScrollBar.cpp b/components/justus/src/common/ScrollBar.cpp index c770c88..73b1681 100644 --- a/components/justus/src/common/ScrollBar.cpp +++ b/components/justus/src/common/ScrollBar.cpp @@ -1,29 +1,22 @@ #include "common/ScrollBar.h" -ScrollBar::ScrollBar( - const menu_options_t* options, - const size_t x, - const size_t y, - const size_t width, - const size_t height) - : Widget(options->u8g2) - , m_x(x) - , m_y(y) - , m_width(width) - , m_height(height) - , m_value(0) - , m_max(0) - , m_min(0) - , m_thumbHeight(0) - , m_thumbY(0) { +ScrollBar::ScrollBar(const menu_options_t *options, const size_t x, const size_t y, const size_t width, + const size_t height) + : Widget(options->u8g2), m_x(x), m_y(y), m_width(width), m_height(height), m_value(0), m_max(0), m_min(0), + m_thumbHeight(0), m_thumbY(0) +{ } -void ScrollBar::render() { - if(1 == m_max) return; +void ScrollBar::render() +{ + if (1 == m_max) + return; // draw dotted line - for(size_t y = m_y; y < m_y + m_height; y++) { - if(y % 2 == 0) { + for (size_t y = m_y; y < m_y + m_height; y++) + { + if (y % 2 == 0) + { u8g2_DrawPixel(u8g2, m_x, y); } } @@ -32,7 +25,8 @@ void ScrollBar::render() { u8g2_DrawBox(u8g2, u8g2->width - 4, m_thumbY, 3, m_thumbHeight); } -void ScrollBar::refresh(const size_t value, const size_t max, const size_t min) { +void ScrollBar::refresh(const size_t value, const size_t max, const size_t min) +{ m_value = value; m_max = max; m_min = min; diff --git a/components/justus/src/common/Widget.cpp b/components/justus/src/common/Widget.cpp index 0172aa0..0dcef9c 100644 --- a/components/justus/src/common/Widget.cpp +++ b/components/justus/src/common/Widget.cpp @@ -1,14 +1,17 @@ #include "common/Widget.h" -Widget::Widget(u8g2_t* u8g2) - : u8g2(u8g2) { +Widget::Widget(u8g2_t *u8g2) : u8g2(u8g2) +{ } -void Widget::update(uint64_t dt) { +void Widget::update(uint64_t dt) +{ } -void Widget::render() { +void Widget::render() +{ } -void Widget::onButtonClicked(uint8_t button) { +void Widget::onButtonClicked(uint8_t button) +{ } diff --git a/components/justus/src/data/MenuItem.cpp b/components/justus/src/data/MenuItem.cpp index 7ec0211..544a176 100644 --- a/components/justus/src/data/MenuItem.cpp +++ b/components/justus/src/data/MenuItem.cpp @@ -1,23 +1,17 @@ #include "data/MenuItem.h" MenuItem::MenuItem(const uint8_t type, std::string text, std::function callback) - : m_type(type) - , m_text(std::move(text)) - , m_callback(std::move(callback)) { + : m_type(type), m_text(std::move(text)), m_callback(std::move(callback)) +{ } -MenuItem::MenuItem( - const uint8_t type, - std::string text, - std::string value, - std::function callback) - : m_type(type) - , m_text(std::move(text)) - , m_value(std::move(value)) - , m_callback(std::move(callback)) { +MenuItem::MenuItem(const uint8_t type, std::string text, std::string value, std::function callback) + : m_type(type), m_text(std::move(text)), m_value(std::move(value)), m_callback(std::move(callback)) +{ } -uint8_t MenuItem::getType() const { +uint8_t MenuItem::getType() const +{ return m_type; } diff --git a/components/justus/src/ui/LightMenu.cpp b/components/justus/src/ui/LightMenu.cpp index d844307..117f266 100644 --- a/components/justus/src/ui/LightMenu.cpp +++ b/components/justus/src/ui/LightMenu.cpp @@ -5,7 +5,7 @@ void demoL(uint8_t id) // } -LightMenu::LightMenu(menu_options_t* options) : PSMenu(options) +LightMenu::LightMenu(menu_options_t *options) : PSMenu(options) { addText("Tag/Nacht", nullptr); addText("LED Einstellungen", demoL); diff --git a/components/justus/src/ui/MainMenu.cpp b/components/justus/src/ui/MainMenu.cpp index 50c50f9..4bae077 100644 --- a/components/justus/src/ui/MainMenu.cpp +++ b/components/justus/src/ui/MainMenu.cpp @@ -4,16 +4,17 @@ #include "ui/LightMenu.h" #include "ui/SettingsMenu.h" -MainMenu::MainMenu(menu_options_t* options) - : PSMenu(options) - , m_options(options) { +MainMenu::MainMenu(menu_options_t *options) : PSMenu(options), m_options(options) +{ addText("Lichtsteuerung", [this](const uint8_t button) { onSelect(button); }); addText("Einstellungen", [this](const uint8_t button) { onSelect(button); }); } -void MainMenu::onSelect(const uint8_t id) const { +void MainMenu::onSelect(const uint8_t id) const +{ std::shared_ptr widget; - switch(id) { + switch (id) + { case 0: widget = std::make_shared(m_options); break; @@ -21,7 +22,8 @@ void MainMenu::onSelect(const uint8_t id) const { widget = std::make_shared(m_options); break; } - if(m_options && m_options->pushScreen) { + if (m_options && m_options->pushScreen) + { m_options->pushScreen(widget); } } diff --git a/components/justus/src/ui/SettingsMenu.cpp b/components/justus/src/ui/SettingsMenu.cpp index 8c76bc6..ae273b0 100644 --- a/components/justus/src/ui/SettingsMenu.cpp +++ b/components/justus/src/ui/SettingsMenu.cpp @@ -5,7 +5,7 @@ void demo(uint8_t id) /// } -SettingsMenu::SettingsMenu(menu_options_t* options) : PSMenu(options) +SettingsMenu::SettingsMenu(menu_options_t *options) : PSMenu(options) { addText("OTA Einspielen", demo); } diff --git a/components/justus/src/ui/SplashScreen.cpp b/components/justus/src/ui/SplashScreen.cpp index a38a427..0ba45db 100644 --- a/components/justus/src/ui/SplashScreen.cpp +++ b/components/justus/src/ui/SplashScreen.cpp @@ -10,16 +10,18 @@ uint64_t counter = 0; -SplashScreen::SplashScreen(menu_options_t* options) - : Widget(options->u8g2) - , m_options(options) { +SplashScreen::SplashScreen(menu_options_t *options) : Widget(options->u8g2), m_options(options) +{ } -void SplashScreen::update(const uint64_t dt) { +void SplashScreen::update(const uint64_t dt) +{ counter += dt; - if(counter > 200000) { + if (counter > 200000) + { counter = 0; - if(m_options && m_options->setScreen) { + if (m_options && m_options->setScreen) + { m_options->setScreen(std::make_shared(m_options)); } } @@ -28,7 +30,8 @@ void SplashScreen::update(const uint64_t dt) { #endif } -void SplashScreen::render() { +void SplashScreen::render() +{ u8g2_SetFont(u8g2, u8g2_font_DigitalDisco_tr); u8g2_DrawStr(u8g2, 28, u8g2->height / 2 - 10, "HO Anlage"); u8g2_DrawStr(u8g2, 30, u8g2->height / 2 + 5, "Axel Janz"); diff --git a/components/peter/CMakeLists.txt b/components/peter/CMakeLists.txt index 34645a8..c7366b8 100644 --- a/components/peter/CMakeLists.txt +++ b/components/peter/CMakeLists.txt @@ -1,10 +1,10 @@ if (DEFINED ENV{IDF_PATH}) -idf_component_register(SRCS - PushButton.cpp - INCLUDE_DIRS "include" -) -return() -endif() + idf_component_register(SRCS + PushButton.cpp + INCLUDE_DIRS "include" + ) + return() +endif () cmake_minimum_required(VERSION 3.30) project(peter) diff --git a/main/button_handling.c b/main/button_handling.c index 068248d..76dbad5 100644 --- a/main/button_handling.c +++ b/main/button_handling.c @@ -1,42 +1,43 @@ #include "button_handling.h" -#include "sdkconfig.h" -#include -#include #include "driver/gpio.h" #include "driver/i2c.h" #include "esp_err.h" #include "esp_log.h" -#include "esp_timer.h" #include "esp_mac.h" +#include "esp_timer.h" #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "freertos/task.h" +#include "sdkconfig.h" +#include +#include #include "common.h" -static const char* TAG = "button_handling"; +static const char *TAG = "button_handling"; #define DEBOUNCE_TIME_MS (500) -#define BUTTON_QUEUE_LENGTH 5 +#define BUTTON_QUEUE_LENGTH 5 #define BUTTON_QUEUE_ITEM_SIZE sizeof(uint8_t) -#define WLED_GPIO GPIO_NUM_47 -#define WLED_RMT_CHANNEL RMT_CHANNEL_0 -#define WLED_RESOLUTION_HZ (10000000) +#define WLED_GPIO GPIO_NUM_47 +#define WLED_RMT_CHANNEL RMT_CHANNEL_0 +#define WLED_RESOLUTION_HZ (10000000) #define WLED_ON_DURATION_MS (100) -#define NUM_LEDS (1) +#define NUM_LEDS (1) -const uint8_t pins[] = - {BUTTON_DOWN, BUTTON_UP, BUTTON_LEFT, BUTTON_RIGHT, BUTTON_SELECT, BUTTON_BACK}; +const uint8_t pins[] = {BUTTON_DOWN, BUTTON_UP, BUTTON_LEFT, BUTTON_RIGHT, BUTTON_SELECT, BUTTON_BACK}; QueueHandle_t buttonQueue = NULL; volatile int64_t last_interrupt_time = 0; -void IRAM_ATTR button_isr_handler(void* arg) { +void IRAM_ATTR button_isr_handler(void *arg) +{ int64_t now = esp_timer_get_time(); - if((now - last_interrupt_time) > (DEBOUNCE_TIME_MS * 1000)) { + if ((now - last_interrupt_time) > (DEBOUNCE_TIME_MS * 1000)) + { last_interrupt_time = now; uintptr_t pin_value = (uintptr_t)arg; @@ -45,26 +46,31 @@ void IRAM_ATTR button_isr_handler(void* arg) { xQueueSendFromISR(buttonQueue, &press_signal, &higherPriorityTaskWoken); - if(higherPriorityTaskWoken) { + if (higherPriorityTaskWoken) + { portYIELD_FROM_ISR(); } } } -void setupButtons(void) { +void setupButtons(void) +{ buttonQueue = xQueueCreate(BUTTON_QUEUE_LENGTH, BUTTON_QUEUE_ITEM_SIZE); - if(buttonQueue == NULL) { + if (buttonQueue == NULL) + { ESP_LOGE(TAG, "Error while Queue creation!"); return; } ESP_LOGI(TAG, "Button Queue created."); esp_err_t isr_service_err = gpio_install_isr_service(ESP_INTR_FLAG_IRAM); - if(isr_service_err != ESP_OK && isr_service_err != ESP_ERR_INVALID_STATE) { + if (isr_service_err != ESP_OK && isr_service_err != ESP_ERR_INVALID_STATE) + { ESP_LOGE(TAG, "Error in gpio_install_isr_service: %s", esp_err_to_name(isr_service_err)); } - for(int i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) { + for (int i = 0; i < sizeof(pins) / sizeof(pins[0]); i++) + { const uint8_t pin = pins[i]; gpio_config_t io_conf; io_conf.intr_type = GPIO_INTR_NEGEDGE; @@ -75,8 +81,9 @@ void setupButtons(void) { gpio_config(&io_conf); uintptr_t pin_as_arg = (uintptr_t)pin; - esp_err_t add_isr_err = gpio_isr_handler_add(pin, button_isr_handler, (void*)pin_as_arg); - if(add_isr_err != ESP_OK) { + esp_err_t add_isr_err = gpio_isr_handler_add(pin, button_isr_handler, (void *)pin_as_arg); + if (add_isr_err != ESP_OK) + { ESP_LOGE(TAG, "Error in gpio_isr_handler_add: %s", esp_err_to_name(add_isr_err)); } diff --git a/main/button_handling.h b/main/button_handling.h index 02fb7b2..918a65c 100644 --- a/main/button_handling.h +++ b/main/button_handling.h @@ -1,9 +1,10 @@ #pragma once #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -void setupButtons(void); + void setupButtons(void); #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/main/common.h b/main/common.h index 7176640..70635a4 100644 --- a/main/common.h +++ b/main/common.h @@ -1,8 +1,8 @@ #pragma once -#define BUTTON_UP GPIO_NUM_1 -#define BUTTON_DOWN GPIO_NUM_6 -#define BUTTON_LEFT GPIO_NUM_3 -#define BUTTON_RIGHT GPIO_NUM_5 +#define BUTTON_UP GPIO_NUM_1 +#define BUTTON_DOWN GPIO_NUM_6 +#define BUTTON_LEFT GPIO_NUM_3 +#define BUTTON_RIGHT GPIO_NUM_5 #define BUTTON_SELECT GPIO_NUM_18 -#define BUTTON_BACK GPIO_NUM_16 \ No newline at end of file +#define BUTTON_BACK GPIO_NUM_16 \ No newline at end of file diff --git a/main/main.c b/main/main.c index 1c19740..a4ef2ee 100644 --- a/main/main.c +++ b/main/main.c @@ -1,19 +1,23 @@ -#include "setup.h" #include "freertos/idf_additions.h" +#include "setup.h" -void app_task(void* param) { +void app_task(void *param) +{ setup(); - while(1) { + while (1) + { loop(); } } #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -void app_main(void) { - xTaskCreatePinnedToCore(app_task, "main_loop", 4096, NULL, 5, NULL, tskIDLE_PRIORITY + 1); -} + void app_main(void) + { + xTaskCreatePinnedToCore(app_task, "main_loop", 4096, NULL, 5, NULL, tskIDLE_PRIORITY + 1); + } #ifdef __cplusplus } #endif diff --git a/main/setup.c b/main/setup.c index bf9c4b2..1244d6d 100644 --- a/main/setup.c +++ b/main/setup.c @@ -1,7 +1,5 @@ #include "setup.h" -#include -#include #include "driver/gpio.h" #include "esp_err.h" #include "esp_log.h" @@ -9,6 +7,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/queue.h" #include "freertos/task.h" +#include +#include #include "driver/rmt_encoder.h" #include "driver/rmt_tx.h" @@ -16,22 +16,22 @@ #include "u8g2.h" #include "u8g2_esp32_hal.h" -#include "common.h" #include "button_handling.h" +#include "common.h" #define PIN_SDA GPIO_NUM_35 #define PIN_SCL GPIO_NUM_36 #define PIN_RST GPIO_NUM_NC -#define WLED_GPIO GPIO_NUM_47 -#define WLED_RMT_CHANNEL RMT_CHANNEL_0 -#define WLED_RESOLUTION_HZ (10000000) +#define WLED_GPIO GPIO_NUM_47 +#define WLED_RMT_CHANNEL RMT_CHANNEL_0 +#define WLED_RESOLUTION_HZ (10000000) #define WLED_ON_DURATION_MS (100) -#define NUM_LEDS (1) +#define NUM_LEDS (1) uint8_t last_value = 0; -static const char* TAG = "main"; +static const char *TAG = "main"; extern QueueHandle_t buttonQueue; @@ -43,7 +43,8 @@ int64_t wled_turn_off_time = 0; u8g2_t u8g2; uint8_t received_signal; -static void init_rmt_ws2812b(void) { +static void init_rmt_ws2812b(void) +{ ESP_LOGI(TAG, "Initialize RMT TX Channel for WS2812B on GPIO %d", WLED_GPIO); rmt_tx_channel_config_t tx_chan_config = { .gpio_num = WLED_GPIO, @@ -66,15 +67,18 @@ static void init_rmt_ws2812b(void) { ESP_ERROR_CHECK(rmt_enable(rmt_led_chan)); } -static void set_wled_color(uint8_t r, uint8_t g, uint8_t b) { - if(!rmt_led_chan || !rmt_led_encoder) { +static void set_wled_color(uint8_t r, uint8_t g, uint8_t b) +{ + if (!rmt_led_chan || !rmt_led_encoder) + { ESP_LOGE(TAG, "RMT Channel or Encoder not initialized!"); return; } size_t buffer_size = 3 * NUM_LEDS; uint8_t led_data[buffer_size]; - for(int i = 0; i < NUM_LEDS; i++) { + for (int i = 0; i < NUM_LEDS; i++) + { led_data[i * 3 + 0] = g; led_data[i * 3 + 1] = r; led_data[i * 3 + 2] = b; @@ -82,15 +86,16 @@ static void set_wled_color(uint8_t r, uint8_t g, uint8_t b) { rmt_transmit_config_t tx_config = { .loop_count = 0, }; - esp_err_t ret = - rmt_transmit(rmt_led_chan, rmt_led_encoder, led_data, sizeof(led_data), &tx_config); - if(ret != ESP_OK) { + esp_err_t ret = rmt_transmit(rmt_led_chan, rmt_led_encoder, led_data, sizeof(led_data), &tx_config); + if (ret != ESP_OK) + { ESP_LOGE(TAG, "RMT Transmit failed: %s", esp_err_to_name(ret)); } ESP_ERROR_CHECK(rmt_tx_wait_all_done(rmt_led_chan, pdMS_TO_TICKS(100))); } -void setup(void) { +void setup(void) +{ setupButtons(); u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT; @@ -99,8 +104,7 @@ void setup(void) { u8g2_esp32_hal.reset = PIN_RST; u8g2_esp32_hal_init(u8g2_esp32_hal); - u8g2_Setup_sh1106_i2c_128x64_noname_f( - &u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); + u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb); u8x8_SetI2CAddress(&u8g2.u8x8, 0x3C * 2); ESP_LOGI(TAG, "u8g2_InitDisplay"); @@ -115,7 +119,8 @@ void setup(void) { ESP_LOGI(TAG, "Start of main loop. Waiting for button press..."); } -void loop(void) { +void loop(void) +{ u8g2_ClearBuffer(&u8g2); u8g2_SetFont(&u8g2, u8g2_font_ncenB10_tr); u8g2_DrawStr(&u8g2, 5, 20, "Ready!"); @@ -124,7 +129,8 @@ void loop(void) { u8g2_DrawStr(&u8g2, 5, 45, count_str); u8g2_SendBuffer(&u8g2); - if(xQueueReceive(buttonQueue, &received_signal, pdMS_TO_TICKS(10)) == pdTRUE) { + if (xQueueReceive(buttonQueue, &received_signal, pdMS_TO_TICKS(10)) == pdTRUE) + { ESP_LOGI(TAG, "Button event from Queue received!"); last_value = received_signal; @@ -143,7 +149,8 @@ void loop(void) { wled_turn_off_time = esp_timer_get_time() + (WLED_ON_DURATION_MS * 1000); } - if(wled_is_on && esp_timer_get_time() >= wled_turn_off_time) { + if (wled_is_on && esp_timer_get_time() >= wled_turn_off_time) + { ESP_LOGD(TAG, "Switch WLED OFF"); set_wled_color(0, 0, 0); wled_is_on = false; diff --git a/main/setup.h b/main/setup.h index d5a7192..04434e0 100644 --- a/main/setup.h +++ b/main/setup.h @@ -1,10 +1,11 @@ #pragma once #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif -void setup(void); -void loop(void); + void setup(void); + void loop(void); #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/src/Common.cpp b/src/Common.cpp index c8a9c6e..196abe5 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -2,11 +2,13 @@ #include -auto createWindow(const char *title, const int width, const int height) -> Window * { +auto CreateWindow(const char *title, const int width, const int height) -> Window * +{ constexpr uint32_t window_flag = SDL_WINDOW_HIDDEN; const auto window = SDL_CreateWindow(title, width, height, window_flag); - if (window == nullptr) { + if (window == nullptr) + { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window", SDL_GetError(), nullptr); return nullptr; } @@ -14,7 +16,8 @@ auto createWindow(const char *title, const int width, const int height) -> Windo const SDL_PropertiesID props = SDL_CreateProperties(); SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window); SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB_LINEAR); - if (const auto renderer = SDL_CreateRendererWithProperties(props); renderer == nullptr) { + if (const auto renderer = SDL_CreateRendererWithProperties(props); renderer == nullptr) + { SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create renderer", SDL_GetError(), nullptr); return nullptr; } diff --git a/src/Common.h b/src/Common.h index b9ac3f5..dc10420 100644 --- a/src/Common.h +++ b/src/Common.h @@ -2,4 +2,4 @@ #include "model/Window.h" -auto createWindow(const char *title, int width, int height) -> Window *; +auto CreateWindow(const char *title, int width, int height) -> Window *; diff --git a/src/ResourceManager.cpp b/src/ResourceManager.cpp index 3c31e48..c8e9f4c 100644 --- a/src/ResourceManager.cpp +++ b/src/ResourceManager.cpp @@ -1,46 +1,108 @@ #include "ResourceManager.h" -#include -#include #include +#include #include -ResourceManager& ResourceManager::getInstance() { +ResourceManager &ResourceManager::Instance() +{ static ResourceManager instance; return instance; } -ResourceManager::ResourceManager() { +ResourceManager::ResourceManager() +{ SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "ResourceManager instance created."); } -ResourceManager::~ResourceManager() { - for(const auto& texture : m_textures | std::views::values) { - if(texture != nullptr) { +/** + * @brief Destructor for the ResourceManager + * Cleans up all loaded textures and frees memory + */ +ResourceManager::~ResourceManager() +{ + for (const auto &texture : m_textures | std::views::values) + { + if (texture != nullptr) + { SDL_DestroyTexture(texture); } } m_textures.clear(); } -SDL_Texture* ResourceManager::get_texture(SDL_Renderer* renderer, const std::string& path) { +std::string ResourceManager::GetResourcePath(const std::string &fileName) +{ + const auto basePath_c = SDL_GetBasePath(); + if (!basePath_c) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error retrieving base path: %s", SDL_GetError()); + // Fallback to relative path as a last resort + // Warning: This only works reliably if the working directory is correct + // (e.g., when debugging from IDE) + return fileName; // Fallback (unsafe) + } + + const std::string basePath(basePath_c); + + std::string fullPath = basePath; +#ifdef __APPLE__ + // Special handling for macOS bundle structure + // Navigate from /Contents/MacOS/ to /Contents/Resources/ + size_t lastSlash = fullPath.find_last_of('/'); + if (lastSlash != std::string::npos) + { + fullPath = fullPath.substr(0, lastSlash); // Remove executable name + lastSlash = fullPath.find_last_of('/'); + if (lastSlash != std::string::npos) + { + fullPath = fullPath.substr(0, lastSlash + 1); // Go to Contents folder + fullPath += "Resources/"; + } + else + { + // Fallback if structure is unexpected + fullPath = basePath; // Use original base path + fullPath += "Resources/"; // And try with this + } + } + else + { + // Fallback for unexpected path structure + fullPath = basePath; + fullPath += "Resources/"; + } +#else + // For other platforms (Windows, Linux, etc.) + // Use standard assets folder + fullPath += "assets/"; +#endif + + return fullPath + fileName; +} + + +SDL_Texture *ResourceManager::GetTextureByName(SDL_Renderer *renderer, const std::string &path) +{ std::lock_guard lock(m_mutex); - if(const auto search = m_textures.find(path); search != m_textures.end()) { + // Check if texture is already in cache + if (const auto search = m_textures.find(GetResourcePath(path)); search != m_textures.end()) + { return search->second; } - SDL_Texture* texture = IMG_LoadTexture(renderer, path.c_str()); + // Load new texture + SDL_Texture *texture = IMG_LoadTexture(renderer, GetResourcePath(path).c_str()); - if(!texture) { - SDL_LogError( - SDL_LOG_CATEGORY_APPLICATION, - "Could not load %s -> %s", - path.c_str(), - SDL_GetError()); + if (!texture) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not load %s -> %s", GetResourcePath(path).c_str(), + SDL_GetError()); return nullptr; } + // Store texture in cache m_textures[path] = texture; return texture; } diff --git a/src/ResourceManager.h b/src/ResourceManager.h index 0da6147..beade5c 100644 --- a/src/ResourceManager.h +++ b/src/ResourceManager.h @@ -1,27 +1,59 @@ #pragma once -#include -#include + #include +#include +#include #include -class ResourceManager { +class ResourceManager +{ public: - static ResourceManager& getInstance(); + /** + * @brief Returns the singleton instance of the ResourceManager + * @return Reference to the ResourceManager instance + */ + static ResourceManager &Instance(); - ResourceManager(const ResourceManager&) = delete; - ResourceManager& operator=(const ResourceManager&) = delete; - ResourceManager(ResourceManager&&) = delete; - ResourceManager& operator=(ResourceManager&&) = delete; + ResourceManager(const ResourceManager &) = delete; + ResourceManager &operator=(const ResourceManager &) = delete; + ResourceManager(ResourceManager &&) = delete; + ResourceManager &operator=(ResourceManager &&) = delete; ~ResourceManager(); - SDL_Texture* get_texture(SDL_Renderer* renderer, const std::string& path); + /** + * @brief Loads a texture or returns an already loaded texture + * @param renderer The SDL_Renderer used to load the texture + * @param path Path to the texture file (relative to resource directory) + * @return Pointer to the loaded SDL_Texture or nullptr on error + * + * This function implements a caching system for textures. If a texture + * has already been loaded, it returns it from the cache. Otherwise, + * it loads the texture and stores it in the cache. Access is thread-safe + * through mutex protection. + */ + SDL_Texture *GetTextureByName(SDL_Renderer *renderer, const std::string &path); private: + /** + * @brief Constructor for the ResourceManager + * Initializes a new instance and logs its creation + */ ResourceManager(); - std::unordered_map m_textures; + /** + * @brief Determines the full resource path for a file + * @param fileName Name of the resource file + * @return Complete path to the resource + * + * This function handles platform-specific paths (especially macOS) and + * constructs the correct path to resources. For macOS, it considers the + * bundle structure (.app/Contents/Resources/). + */ + static std::string GetResourcePath(const std::string &fileName); + + std::unordered_map m_textures; mutable std::mutex m_mutex; -}; +}; \ No newline at end of file diff --git a/src/debug/DebugOverlay.cpp b/src/debug/DebugOverlay.cpp index be6a964..d2fd4a8 100644 --- a/src/debug/DebugOverlay.cpp +++ b/src/debug/DebugOverlay.cpp @@ -1,61 +1,73 @@ #include "debug/DebugOverlay.h" -#include #include "Common.h" #include "Version.h" #include "imgui.h" #include "imgui_impl_sdl3.h" #include "ui/Matrix.h" +#include -namespace DebugOverlay { -void init(const AppContext* context) { +namespace DebugOverlay +{ +void Init(const AppContext *context) +{ IMGUI_CHECKVERSION(); ImGui::CreateContext(); - ImGuiIO& io{ImGui::GetIO()}; + ImGuiIO &io{ImGui::GetIO()}; io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; ImGui::StyleColorsDark(); - ImGui_ImplSDL3_InitForSDLRenderer(context->window(), context->renderer()); - ImGui_ImplSDLRenderer3_Init(context->renderer()); + ImGui_ImplSDL3_InitForSDLRenderer(context->MainWindow(), context->MainRenderer()); + ImGui_ImplSDLRenderer3_Init(context->MainRenderer()); } -void update(AppContext* context, const SDL_Event* event) { +void Update(AppContext *context, const SDL_Event *event) +{ ImGui_ImplSDL3_ProcessEvent(event); - if(show_led_matrix) { - if(context->matrix_window() == nullptr) { - const auto win = createWindow("LED Matrix", 32 * 50, 8 * 50); + if (show_led_matrix) + { + if (context->LedMatrixWindow() == nullptr) + { + const auto win = CreateWindow("LED Matrix", 32 * 50, 8 * 50); SDL_SetWindowFocusable(win->window(), false); SDL_SetRenderVSync(win->renderer(), SDL_RENDERER_VSYNC_ADAPTIVE); SDL_SetWindowPosition(win->window(), 0, 0); SDL_ShowWindow(win->window()); - context->setMatrix(new Matrix(win)); + context->SetMatrix(new Matrix(win)); } - } else { - if(context->matrix_window() != nullptr) { - SDL_DestroyWindow(context->matrix_window()); + } + else + { + if (context->LedMatrixWindow() != nullptr) + { + SDL_DestroyWindow(context->LedMatrixWindow()); - context->setMatrix(nullptr); + context->SetMatrix(nullptr); } } } -void render(const AppContext* context) { +void Render(const AppContext *context) +{ ImGui_ImplSDLRenderer3_NewFrame(); ImGui_ImplSDL3_NewFrame(); ImGui::NewFrame(); - if(show_debug_window && ImGui::BeginMainMenuBar()) { - if(ImGui::BeginMenu("Config")) { + if (show_debug_window && ImGui::BeginMainMenuBar()) + { + if (ImGui::BeginMenu("Config")) + { ImGui::Checkbox("Show LED Matrix", &show_led_matrix); ImGui::Checkbox("Show Unhandled Events", &show_unhandled_events); ImGui::EndMenu(); } - if(ImGui::BeginMenu("Help")) { + if (ImGui::BeginMenu("Help")) + { ImGui::Text("FPS: %.2f", ImGui::GetIO().Framerate); ImGui::SeparatorText("App Info"); ImGui::Text("Project: %s", MyProject.c_str()); @@ -70,12 +82,13 @@ void render(const AppContext* context) { // Rendering ImGui::Render(); - ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), context->renderer()); + ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), context->MainRenderer()); } -void cleanup() { +void Cleanup() +{ ImGui_ImplSDLRenderer3_Shutdown(); ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); } -} // namespace DebugOverlay +} // namespace DebugOverlay \ No newline at end of file diff --git a/src/debug/DebugOverlay.h b/src/debug/DebugOverlay.h index 2ca4d6f..bfac0fe 100644 --- a/src/debug/DebugOverlay.h +++ b/src/debug/DebugOverlay.h @@ -4,16 +4,17 @@ #include "model/AppContext.h" -namespace DebugOverlay { +namespace DebugOverlay +{ inline bool show_debug_window = false; inline bool show_unhandled_events = false; -inline bool show_led_matrix = true; +inline bool show_led_matrix = false; -void init(const AppContext* context); +void Init(const AppContext *context); -void update(AppContext* context, const SDL_Event* event); +void Update(AppContext *context, const SDL_Event *event); -void render(const AppContext* context); +void Render(const AppContext *context); -void cleanup(); -} +void Cleanup(); +} \ No newline at end of file diff --git a/src/hal/u8g2_hal_sdl.h b/src/hal/u8g2_hal_sdl.h index 8667488..9c5a050 100644 --- a/src/hal/u8g2_hal_sdl.h +++ b/src/hal/u8g2_hal_sdl.h @@ -2,10 +2,10 @@ #include "u8g2.h" -#define U8G2_SCREEN_WIDTH (128) -#define U8G2_SCREEN_HEIGHT (64) -#define U8G2_SCREEN_FACTOR (3) +#define U8G2_SCREEN_WIDTH (128) +#define U8G2_SCREEN_HEIGHT (64) +#define U8G2_SCREEN_FACTOR (3) #define U8G2_SCREEN_PADDING (25) -uint8_t u8x8_byte_sdl_hw_spi(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); -uint8_t u8x8_gpio_and_delay_sdl(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); +uint8_t u8x8_byte_sdl_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); +uint8_t u8x8_gpio_and_delay_sdl(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr); diff --git a/src/hal/u8x8_hal_sdl.cpp b/src/hal/u8x8_hal_sdl.cpp index bd22784..e161f4c 100644 --- a/src/hal/u8x8_hal_sdl.cpp +++ b/src/hal/u8x8_hal_sdl.cpp @@ -3,8 +3,10 @@ #include #include -uint8_t u8x8_byte_sdl_hw_spi(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { - switch(msg) { +uint8_t u8x8_byte_sdl_hw_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) +{ + switch (msg) + { case U8X8_MSG_BYTE_SEND: case U8X8_MSG_BYTE_INIT: case U8X8_MSG_BYTE_SET_DC: @@ -18,8 +20,10 @@ uint8_t u8x8_byte_sdl_hw_spi(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* a return 1; } -uint8_t u8x8_gpio_and_delay_sdl(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) { - switch(msg) { +uint8_t u8x8_gpio_and_delay_sdl(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) +{ + switch (msg) + { case U8X8_MSG_DELAY_MILLI: SDL_Delay(arg_int); break; diff --git a/src/main.cc b/src/main.cc deleted file mode 100644 index e7a8190..0000000 --- a/src/main.cc +++ /dev/null @@ -1,160 +0,0 @@ -#include -#include -#include -#include - -#include "Common.h" -#include "debug/DebugOverlay.h" -#include "hal/u8g2_hal_sdl.h" -#include "model/AppContext.h" -#include "ui/Device.h" -#include "ui/UIWidget.h" - -#include "u8g2.h" - -#include "PushButton.h" - -#include "ui/widgets/Button.h" -#include "ui/widgets/D_Pad.h" - -constexpr unsigned int WINDOW_WIDTH = - (U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + 2 * BUTTON_WIDTH + - DPAD_WIDTH + 2 * U8G2_SCREEN_PADDING); -constexpr unsigned int WINDOW_HEIGHT = (U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + 50); - -std::shared_ptr device; -std::vector> widgets; - -SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) { - if(SDL_Init(SDL_INIT_VIDEO) == false) { - SDL_LogError( - SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL! -> %s", SDL_GetError()); - return SDL_APP_FAILURE; - } - - if(TTF_Init() == false) { - SDL_LogError( - SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize TTF! -> %s", SDL_GetError()); - return SDL_APP_FAILURE; - } - - const auto win = createWindow("System Control (Simulator)", WINDOW_WIDTH, WINDOW_HEIGHT); - if(!win) { - SDL_LogError( - SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window! -> %s", SDL_GetError()); - return SDL_APP_FAILURE; - } - SDL_SetRenderVSync(win->renderer(), SDL_RENDERER_VSYNC_ADAPTIVE); - SDL_SetWindowPosition(win->window(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); - SDL_ShowWindow(win->window()); - - const auto context = new AppContext(win); - *appstate = context; - - device = std::make_shared(context); - widgets.push_back(device); - - DebugOverlay::init(context); - - return SDL_APP_CONTINUE; -} - -SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) { - const auto context = static_cast(appstate); - DebugOverlay::update(context, event); - - switch(event->type) { - case SDL_EVENT_WINDOW_CLOSE_REQUESTED: - /// multi window - if(SDL_GetWindowID(context->window()) == event->window.windowID) { - return SDL_APP_SUCCESS; - } - break; - - case SDL_EVENT_QUIT: - /// single window application - return SDL_APP_SUCCESS; - - case SDL_EVENT_KEY_DOWN: - switch(event->key.key) { - case SDLK_ESCAPE: - return SDL_APP_SUCCESS; - - case SDLK_UP: - device->onButtonClicked(BUTTON_UP); - break; - - case SDLK_DOWN: - device->onButtonClicked(BUTTON_DOWN); - break; - - case SDLK_LEFT: - device->onButtonClicked(BUTTON_LEFT); - break; - - case SDLK_RIGHT: - device->onButtonClicked(BUTTON_RIGHT); - break; - - case SDLK_RETURN: - device->onButtonClicked(BUTTON_SELECT); - break; - - case SDLK_BACKSPACE: - device->onButtonClicked(BUTTON_BACK); - break; - - default: - break; - } - break; - - case SDL_EVENT_KEY_UP: - if(event->key.key == SDLK_LSHIFT) { - DebugOverlay::show_debug_window = !DebugOverlay::show_debug_window; - } - break; - - case SDL_EVENT_MOUSE_MOTION: - //device->hitTest(&event->motion); - break; - - default: { - if(DebugOverlay::show_unhandled_events) { - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Unused event: %d", event->type); - } - } break; - } - - // return continue to continue - return SDL_APP_CONTINUE; -} - -SDL_AppResult SDL_AppIterate(void* appstate) { - const auto context = static_cast(appstate); - - /// render main window - SDL_SetRenderDrawColor(context->renderer(), 0, 0, 0, 255); - SDL_RenderClear(context->renderer()); - - for(const auto& widget : widgets) { - widget->render(); - } - DebugOverlay::render(context); - - SDL_RenderPresent(context->renderer()); - - /// render led matrix - context->matrix_render(); - - return SDL_APP_CONTINUE; -} - -void SDL_AppQuit(void* appstate, SDL_AppResult result) { - DebugOverlay::cleanup(); - - free(appstate); - - // SDL will clean up the window/renderer for us. - TTF_Quit(); -} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..10f0c57 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,180 @@ +#include +#include +#include +#include + +#include + +#include "Common.h" +#include "debug/DebugOverlay.h" +#include "hal/u8g2_hal_sdl.h" +#include "model/AppContext.h" +#include "PushButton.h" +#include "ui/Device.h" +#include "ui/UIWidget.h" +#include "ui/widgets/Button.h" +#include "ui/widgets/D_Pad.h" + +constexpr unsigned int WINDOW_WIDTH = (U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + + 2 * BUTTON_WIDTH + DPAD_WIDTH + 2 * U8G2_SCREEN_PADDING); +constexpr unsigned int WINDOW_HEIGHT = (U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + 50); + +std::shared_ptr device; +std::vector> widgets; + +SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[]) +{ + if (SDL_Init(SDL_INIT_VIDEO) == false) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize SDL! -> %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + if (TTF_Init() == false) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't initialize TTF! -> %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + + const auto win = CreateWindow("System Control (Simulator)", WINDOW_WIDTH, WINDOW_HEIGHT); + if (!win) + { + SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create window! -> %s", SDL_GetError()); + return SDL_APP_FAILURE; + } + SDL_SetRenderVSync(win->renderer(), SDL_RENDERER_VSYNC_ADAPTIVE); + SDL_SetWindowPosition(win->window(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + SDL_ShowWindow(win->window()); + + const auto context = new AppContext(win); + *appstate = context; + + device = std::make_shared(context); + widgets.push_back(device); + + DebugOverlay::Init(context); + + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event) +{ + const auto context = static_cast(appstate); + DebugOverlay::Update(context, event); + + switch (event->type) + { + case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + /// multi window + if (SDL_GetWindowID(context->MainWindow()) == event->window.windowID) + { + return SDL_APP_SUCCESS; + } + break; + + case SDL_EVENT_QUIT: + /// single window application + return SDL_APP_SUCCESS; + + case SDL_EVENT_KEY_DOWN: + switch (event->key.key) + { + case SDLK_ESCAPE: + return SDL_APP_SUCCESS; + + case SDLK_UP: + device->OnButtonClicked(BUTTON_UP); + break; + + case SDLK_DOWN: + device->OnButtonClicked(BUTTON_DOWN); + break; + + case SDLK_LEFT: + device->OnButtonClicked(BUTTON_LEFT); + break; + + case SDLK_RIGHT: + device->OnButtonClicked(BUTTON_RIGHT); + break; + + case SDLK_RETURN: + device->OnButtonClicked(BUTTON_SELECT); + break; + + case SDLK_BACKSPACE: + device->OnButtonClicked(BUTTON_BACK); + break; + + default: + break; + } + break; + + case SDL_EVENT_KEY_UP: + if (event->key.key == SDLK_LSHIFT) + { + DebugOverlay::show_debug_window = !DebugOverlay::show_debug_window; + } + break; + + case SDL_EVENT_MOUSE_MOTION: + break; + + case SDL_EVENT_MOUSE_BUTTON_DOWN: + if (event->button.button == SDL_BUTTON_LEFT) + { + device->HandleTap(&event->button); + } + break; + + case SDL_EVENT_MOUSE_BUTTON_UP: + if (event->button.button == SDL_BUTTON_LEFT) + { + device->ReleaseTap(&event->button); + } + + default: { + if (DebugOverlay::show_unhandled_events) + { + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "Unused event: %d", event->type); + } + } + break; + } + + // return continue to continue + return SDL_APP_CONTINUE; +} + +SDL_AppResult SDL_AppIterate(void *appstate) +{ + const auto context = static_cast(appstate); + + /// render main window + SDL_SetRenderDrawColor(context->MainRenderer(), 0, 0, 0, 255); + SDL_RenderClear(context->MainRenderer()); + + for (const auto &widget : widgets) + { + widget->Render(); + } + DebugOverlay::Render(context); + + SDL_RenderPresent(context->MainRenderer()); + + /// render led matrix + context->Render(); + + return SDL_APP_CONTINUE; +} + +void SDL_AppQuit(void *appstate, SDL_AppResult result) +{ + DebugOverlay::Cleanup(); + + free(appstate); + + // SDL will clean up the window/renderer for us. + TTF_Quit(); +} \ No newline at end of file diff --git a/src/model/AppContext.cpp b/src/model/AppContext.cpp index 9d33a6b..c78b9c8 100644 --- a/src/model/AppContext.cpp +++ b/src/model/AppContext.cpp @@ -2,42 +2,53 @@ #include "ui/Matrix.h" -auto AppContext::window() const -> SDL_Window* { +auto AppContext::MainWindow() const -> SDL_Window * +{ return m_window->window(); } -auto AppContext::renderer() const -> SDL_Renderer* { +auto AppContext::MainRenderer() const -> SDL_Renderer * +{ return m_window->renderer(); } -auto AppContext::surface() const -> SDL_Surface* { +auto AppContext::MainSurface() const -> SDL_Surface * +{ return SDL_GetWindowSurface(m_window->window()); } -void AppContext::setMatrix(Matrix* matrix) { +void AppContext::SetMatrix(Matrix *matrix) +{ m_matrix = matrix; } -auto AppContext::matrix() const -> Matrix* { +auto AppContext::LedMatrix() const -> Matrix * +{ return m_matrix; } -auto AppContext::matrix_window() const -> SDL_Window* { - if(m_matrix && m_matrix->window()) { +auto AppContext::LedMatrixWindow() const -> SDL_Window * +{ + if (m_matrix && m_matrix->window()) + { return m_matrix->window()->window(); } return nullptr; } -auto AppContext::matrix_renderer() const -> SDL_Renderer* { - if(m_matrix && m_matrix->window()) { +auto AppContext::LedMatrixRenderer() const -> SDL_Renderer * +{ + if (m_matrix && m_matrix->window()) + { return m_matrix->window()->renderer(); } return nullptr; } -void AppContext::matrix_render() const { - if(m_matrix && m_matrix->window()) { - m_matrix->render(); +void AppContext::Render() const +{ + if (m_matrix && m_matrix->window()) + { + m_matrix->Render(); } } diff --git a/src/model/AppContext.h b/src/model/AppContext.h index 272f927..0e65c21 100644 --- a/src/model/AppContext.h +++ b/src/model/AppContext.h @@ -5,39 +5,41 @@ class Matrix; -class AppContext { -public: - explicit AppContext(const Window* window) - : m_window(window) { - m_font_default = TTF_OpenFont("assets/haxrcorp-4089.otf", 21); - m_font_text = TTF_OpenFont("assets/Helvetica-Bold.otf", 21); +class AppContext +{ + public: + explicit AppContext(const Window *window) : m_window(window) + { + m_font_default = TTF_OpenFont("haxrcorp-4089.otf", 21); + m_font_text = TTF_OpenFont("Helvetica-Bold.otf", 21); } - ~AppContext() { + ~AppContext() + { TTF_CloseFont(m_font_default); TTF_CloseFont(m_font_text); } - [[nodiscard]] auto window() const -> SDL_Window*; + [[nodiscard]] auto MainWindow() const -> SDL_Window *; - [[nodiscard]] auto renderer() const -> SDL_Renderer*; + [[nodiscard]] auto MainRenderer() const -> SDL_Renderer *; - [[nodiscard]] auto surface() const -> SDL_Surface*; + [[nodiscard]] auto MainSurface() const -> SDL_Surface *; - void setMatrix(Matrix* matrix); + void SetMatrix(Matrix *matrix); - [[nodiscard]] auto matrix() const -> Matrix*; + [[nodiscard]] auto LedMatrix() const -> Matrix *; - [[nodiscard]] auto matrix_window() const -> SDL_Window*; + [[nodiscard]] auto LedMatrixWindow() const -> SDL_Window *; - [[nodiscard]] auto matrix_renderer() const -> SDL_Renderer*; + [[nodiscard]] auto LedMatrixRenderer() const -> SDL_Renderer *; - void matrix_render() const; + void Render() const; - TTF_Font* m_font_default = nullptr; + TTF_Font *m_font_default = nullptr; -private: - const Window* m_window; - Matrix* m_matrix = nullptr; - TTF_Font* m_font_text = nullptr; + private: + const Window *m_window; + Matrix *m_matrix = nullptr; + TTF_Font *m_font_text = nullptr; }; diff --git a/src/model/Window.cpp b/src/model/Window.cpp index baadbf1..9b9dc1d 100644 --- a/src/model/Window.cpp +++ b/src/model/Window.cpp @@ -1,9 +1,11 @@ #include "model/Window.h" -auto Window::window() const -> SDL_Window* { +auto Window::window() const -> SDL_Window * +{ return m_window; } -auto Window::renderer() const -> SDL_Renderer* { +auto Window::renderer() const -> SDL_Renderer * +{ return SDL_GetRenderer(m_window); } diff --git a/src/model/Window.h b/src/model/Window.h index 0ee46e4..e1b0084 100644 --- a/src/model/Window.h +++ b/src/model/Window.h @@ -2,16 +2,17 @@ #include "SDL3/SDL.h" -class Window { -public: - explicit Window(SDL_Window* window) - : m_window(window) { +class Window +{ + public: + explicit Window(SDL_Window *window) : m_window(window) + { } - [[nodiscard]] auto window() const -> SDL_Window*; + [[nodiscard]] auto window() const -> SDL_Window *; - [[nodiscard]] auto renderer() const -> SDL_Renderer*; + [[nodiscard]] auto renderer() const -> SDL_Renderer *; -private: - SDL_Window* m_window = nullptr; + private: + SDL_Window *m_window = nullptr; }; diff --git a/src/ui/Device.cpp b/src/ui/Device.cpp index 4eddae4..2de10e3 100644 --- a/src/ui/Device.cpp +++ b/src/ui/Device.cpp @@ -1,200 +1,264 @@ #include "ui/Device.h" -#include "SDL3_ttf/SDL_ttf.h" +#include +#include + +#include "MenuOptions.h" +#include "ui/SplashScreen.h" #include "ui/widgets/Button.h" #include "ui/widgets/D_Pad.h" -#include -#include - -#include "ui/SplashScreen.h" -#include "MenuOptions.h" - u8g2_t u8g2; menu_options_t options; -static void set_pixel_rgba( - const SDL_Surface* surface, - const int x, - const int y, - const uint32_t pixel_color) { - if(!surface || x < 0 || x >= surface->w || y < 0 || y >= surface->h) { +static void set_pixel_rgba(const SDL_Surface *surface, const int x, const int y, const uint32_t pixel_color) +{ + if (!surface || x < 0 || x >= surface->w || y < 0 || y >= surface->h) + { return; } - const auto p = - static_cast(surface->pixels) + y * surface->pitch + x * sizeof(uint32_t); - *reinterpret_cast(p) = pixel_color; + const auto p = static_cast(surface->pixels) + y * surface->pitch + x * sizeof(uint32_t); + *reinterpret_cast(p) = pixel_color; } -Device::Device(void* appstate) - : UIWidget(appstate) { - m_children.push_back( - std::make_shared