handle mouse events
Signed-off-by: Peter Siegmund <developer@mars3142.org>
This commit is contained in:
247
.clang-format
247
.clang-format
@@ -1,247 +1,2 @@
|
|||||||
---
|
---
|
||||||
BasedOnStyle: Chromium
|
BasedOnStyle: Microsoft
|
||||||
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
|
|
||||||
...
|
|
||||||
|
|
||||||
|
170
CMakeLists.txt
170
CMakeLists.txt
@@ -1,90 +1,106 @@
|
|||||||
cmake_minimum_required(VERSION 3.30)
|
cmake_minimum_required(VERSION 3.30)
|
||||||
|
|
||||||
if (DEFINED ENV{IDF_PATH})
|
if (DEFINED ENV{IDF_PATH})
|
||||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
project(espidf_system_control)
|
project(espidf_system_control)
|
||||||
return()
|
return()
|
||||||
else()
|
else ()
|
||||||
|
set(MAJOR_VERSION 0)
|
||||||
|
set(MINOR_VERSION 0)
|
||||||
|
set(MICRO_VERSION 1)
|
||||||
|
|
||||||
set(MAJOR_VERSION 0)
|
project(
|
||||||
set(MINOR_VERSION 0)
|
SystemControl
|
||||||
set(MICRO_VERSION 1)
|
LANGUAGES CXX C
|
||||||
|
VERSION "${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}"
|
||||||
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
|
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(${libName})
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
include_dependency(SDL3 https://github.com/libsdl-org/SDL release-3.2.8)
|
set(CMAKE_C_STANDARD 23)
|
||||||
include_dependency(SDL_image https://github.com/libsdl-org/SDL_image release-3.2.4)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
include_dependency(SDL_ttf https://github.com/libsdl-org/SDL_ttf release-3.2.0)
|
set(CMAKE_CXX_STANDARD_REQUIRED YES)
|
||||||
include_dependency(u8g2 https://github.com/olikraus/u8g2 master)
|
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(
|
include(FetchContent)
|
||||||
"${CMAKE_SOURCE_DIR}/Version.h.in"
|
function(include_dependency libName gitURL gitTag)
|
||||||
"${CMAKE_SOURCE_DIR}/Version.h"
|
FetchContent_Declare(${libName}
|
||||||
)
|
GIT_REPOSITORY ${gitURL}
|
||||||
|
GIT_TAG ${gitTag}
|
||||||
|
GIT_SHALLOW TRUE
|
||||||
|
GIT_PROGRESS FALSE
|
||||||
|
)
|
||||||
|
FetchContent_MakeAvailable(${libName})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
include_directories(
|
include_dependency(SDL3 https://github.com/libsdl-org/SDL release-3.2.x)
|
||||||
${CMAKE_INCLUDE_PATH}
|
include_dependency(SDL_image https://github.com/libsdl-org/SDL_image release-3.2.x)
|
||||||
${CMAKE_SOURCE_DIR}
|
include_dependency(SDL_ttf https://github.com/libsdl-org/SDL_ttf release-3.2.x)
|
||||||
${PROJECT_BINARY_DIR}/src
|
include_dependency(u8g2 https://github.com/olikraus/u8g2 master)
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME}
|
add_subdirectory(components)
|
||||||
${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
|
|
||||||
)
|
|
||||||
|
|
||||||
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
|
include_directories(
|
||||||
ImGui
|
${CMAKE_INCLUDE_PATH}
|
||||||
justus
|
${CMAKE_SOURCE_DIR}
|
||||||
peter
|
${PROJECT_BINARY_DIR}/src
|
||||||
SDL3::SDL3
|
)
|
||||||
SDL3_image::SDL3_image
|
|
||||||
SDL3_ttf::SDL3_ttf
|
|
||||||
u8g2
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_command(
|
add_executable(${PROJECT_NAME}
|
||||||
TARGET ${PROJECT_NAME} POST_BUILD
|
WIN32 MACOSX_BUNDLE
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
${CMAKE_SOURCE_DIR}/main.cpp
|
||||||
${PROJECT_SOURCE_DIR}/assets ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/assets
|
${CMAKE_SOURCE_DIR}/Common.cpp
|
||||||
)
|
${CMAKE_SOURCE_DIR}/ResourceManager.cpp
|
||||||
endif()
|
${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 $<TARGET_BUNDLE_DIR:${PROJECT_NAME}>/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 ()
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
if (DEFINED ENV{IDF_PATH})
|
if (DEFINED ENV{IDF_PATH})
|
||||||
return()
|
return()
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
add_library(components INTERFACE)
|
add_library(components INTERFACE)
|
||||||
|
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
if (DEFINED ENV{IDF_PATH})
|
if (DEFINED ENV{IDF_PATH})
|
||||||
return()
|
return()
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.30)
|
cmake_minimum_required(VERSION 3.30)
|
||||||
project(ImGui)
|
project(ImGui)
|
||||||
|
@@ -1,17 +1,17 @@
|
|||||||
if (DEFINED ENV{IDF_PATH})
|
if (DEFINED ENV{IDF_PATH})
|
||||||
idf_component_register(SRCS
|
idf_component_register(SRCS
|
||||||
src/common/PSMenu.cpp
|
src/common/PSMenu.cpp
|
||||||
src/common/ScrollBar.cpp
|
src/common/ScrollBar.cpp
|
||||||
src/common/Widget.cpp
|
src/common/Widget.cpp
|
||||||
src/data/MenuItem.cpp
|
src/data/MenuItem.cpp
|
||||||
src/ui/LightMenu.cpp
|
src/ui/LightMenu.cpp
|
||||||
src/ui/MainMenu.cpp
|
src/ui/MainMenu.cpp
|
||||||
src/ui/SettingsMenu.cpp
|
src/ui/SettingsMenu.cpp
|
||||||
src/ui/SplashScreen.cpp
|
src/ui/SplashScreen.cpp
|
||||||
INCLUDE_DIRS "include"
|
INCLUDE_DIRS "include"
|
||||||
)
|
)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.30)
|
cmake_minimum_required(VERSION 3.30)
|
||||||
project(justus)
|
project(justus)
|
||||||
|
@@ -3,13 +3,14 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "u8g2.h"
|
|
||||||
#include "common/Widget.h"
|
#include "common/Widget.h"
|
||||||
|
#include "u8g2.h"
|
||||||
|
|
||||||
class Widget;
|
class Widget;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
u8g2_t* u8g2;
|
{
|
||||||
|
u8g2_t *u8g2;
|
||||||
|
|
||||||
std::function<void(std::shared_ptr<Widget>)> setScreen;
|
std::function<void(std::shared_ptr<Widget>)> setScreen;
|
||||||
std::function<void(std::shared_ptr<Widget>)> pushScreen;
|
std::function<void(std::shared_ptr<Widget>)> pushScreen;
|
||||||
|
@@ -8,19 +8,20 @@
|
|||||||
|
|
||||||
typedef std::function<void(uint8_t)> MenuCallback;
|
typedef std::function<void(uint8_t)> MenuCallback;
|
||||||
|
|
||||||
class PSMenu : public Widget {
|
class PSMenu : public Widget
|
||||||
public:
|
{
|
||||||
explicit PSMenu(menu_options_t* options);
|
public:
|
||||||
|
explicit PSMenu(menu_options_t *options);
|
||||||
~PSMenu() override;
|
~PSMenu() override;
|
||||||
|
|
||||||
void render() override;
|
void render() override;
|
||||||
void onButtonClicked(uint8_t button) override;
|
void onButtonClicked(uint8_t button) override;
|
||||||
|
|
||||||
void addText(const std::string& text, 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 addSwitch(const std::string &text, std::string &value, const MenuCallback &callback);
|
||||||
void addNumber(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 onPressedDown();
|
||||||
void onPressedUp();
|
void onPressedUp();
|
||||||
void onPressedLeft();
|
void onPressedLeft();
|
||||||
|
@@ -3,13 +3,14 @@
|
|||||||
#include "MenuOptions.h"
|
#include "MenuOptions.h"
|
||||||
#include "Widget.h"
|
#include "Widget.h"
|
||||||
|
|
||||||
class ScrollBar final : public Widget {
|
class ScrollBar final : public Widget
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
ScrollBar(const menu_options_t *options, size_t x, size_t y, size_t width, size_t height);
|
ScrollBar(const menu_options_t *options, size_t x, size_t y, size_t width, size_t height);
|
||||||
void render() override;
|
void render() override;
|
||||||
void refresh(size_t value, size_t max, size_t min = 0);
|
void refresh(size_t value, size_t max, size_t min = 0);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t m_x;
|
size_t m_x;
|
||||||
size_t m_y;
|
size_t m_y;
|
||||||
size_t m_width;
|
size_t m_width;
|
||||||
|
@@ -4,9 +4,10 @@
|
|||||||
|
|
||||||
#include "u8g2.h"
|
#include "u8g2.h"
|
||||||
|
|
||||||
class Widget {
|
class Widget
|
||||||
public:
|
{
|
||||||
explicit Widget(u8g2_t* u8g2);
|
public:
|
||||||
|
explicit Widget(u8g2_t *u8g2);
|
||||||
|
|
||||||
virtual ~Widget() = default;
|
virtual ~Widget() = default;
|
||||||
|
|
||||||
@@ -16,6 +17,6 @@ public:
|
|||||||
|
|
||||||
virtual void onButtonClicked(uint8_t button);
|
virtual void onButtonClicked(uint8_t button);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
u8g2_t* u8g2;
|
u8g2_t *u8g2;
|
||||||
};
|
};
|
||||||
|
@@ -4,14 +4,11 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
class MenuItem {
|
class MenuItem
|
||||||
public:
|
{
|
||||||
|
public:
|
||||||
MenuItem(uint8_t type, std::string text, std::function<void(uint8_t)> callback);
|
MenuItem(uint8_t type, std::string text, std::function<void(uint8_t)> callback);
|
||||||
MenuItem(
|
MenuItem(uint8_t type, std::string text, std::string value, std::function<void(uint8_t)> callback);
|
||||||
uint8_t type,
|
|
||||||
std::string text,
|
|
||||||
std::string value,
|
|
||||||
std::function<void(uint8_t)> callback);
|
|
||||||
[[nodiscard]] uint8_t getType() const;
|
[[nodiscard]] uint8_t getType() const;
|
||||||
[[nodiscard]] const std::string &getText() const;
|
[[nodiscard]] const std::string &getText() const;
|
||||||
[[nodiscard]] const std::string &getValue() const;
|
[[nodiscard]] const std::string &getValue() const;
|
||||||
@@ -19,7 +16,7 @@ public:
|
|||||||
void callback(uint8_t id) const;
|
void callback(uint8_t id) const;
|
||||||
[[nodiscard]] bool hasCallback() const;
|
[[nodiscard]] bool hasCallback() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t m_type;
|
uint8_t m_type;
|
||||||
std::string m_text;
|
std::string m_text;
|
||||||
std::string m_value;
|
std::string m_value;
|
||||||
|
@@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
class LightMenu : public PSMenu
|
class LightMenu : public PSMenu
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit LightMenu(menu_options_t* options);
|
explicit LightMenu(menu_options_t *options);
|
||||||
};
|
};
|
||||||
|
@@ -2,12 +2,13 @@
|
|||||||
|
|
||||||
#include "common/PSMenu.h"
|
#include "common/PSMenu.h"
|
||||||
|
|
||||||
class MainMenu final : public PSMenu {
|
class MainMenu final : public PSMenu
|
||||||
public:
|
{
|
||||||
explicit MainMenu(menu_options_t* options);
|
public:
|
||||||
|
explicit MainMenu(menu_options_t *options);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void onSelect(uint8_t id) const;
|
void onSelect(uint8_t id) const;
|
||||||
|
|
||||||
menu_options_t* m_options;
|
menu_options_t *m_options;
|
||||||
};
|
};
|
||||||
|
@@ -4,6 +4,6 @@
|
|||||||
|
|
||||||
class SettingsMenu : public PSMenu
|
class SettingsMenu : public PSMenu
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SettingsMenu(menu_options_t* options) ;
|
explicit SettingsMenu(menu_options_t *options);
|
||||||
};
|
};
|
||||||
|
@@ -3,12 +3,13 @@
|
|||||||
#include "MenuOptions.h"
|
#include "MenuOptions.h"
|
||||||
#include "common/Widget.h"
|
#include "common/Widget.h"
|
||||||
|
|
||||||
class SplashScreen final : public Widget {
|
class SplashScreen final : public Widget
|
||||||
public:
|
{
|
||||||
explicit SplashScreen(menu_options_t* options);
|
public:
|
||||||
|
explicit SplashScreen(menu_options_t *options);
|
||||||
void update(uint64_t dt) override;
|
void update(uint64_t dt) override;
|
||||||
void render() override;
|
void render() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
menu_options_t* m_options;
|
menu_options_t *m_options;
|
||||||
};
|
};
|
||||||
|
@@ -1,21 +1,23 @@
|
|||||||
#include "common/PSMenu.h"
|
#include "common/PSMenu.h"
|
||||||
|
|
||||||
#include "u8g2.h"
|
|
||||||
#include "common/ScrollBar.h"
|
|
||||||
#include "PushButton.h"
|
#include "PushButton.h"
|
||||||
|
#include "common/ScrollBar.h"
|
||||||
|
#include "u8g2.h"
|
||||||
|
|
||||||
PSMenu::PSMenu(menu_options_t* options)
|
PSMenu::PSMenu(menu_options_t *options) : Widget(options->u8g2), m_options(options)
|
||||||
: Widget(options->u8g2)
|
{
|
||||||
, m_options(options) {
|
|
||||||
m_options->onButtonClicked = [this](const uint8_t button) { onButtonClicked(button); };
|
m_options->onButtonClicked = [this](const uint8_t button) { onButtonClicked(button); };
|
||||||
}
|
}
|
||||||
|
|
||||||
PSMenu::~PSMenu() {
|
PSMenu::~PSMenu()
|
||||||
|
{
|
||||||
m_options->onButtonClicked = nullptr;
|
m_options->onButtonClicked = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSMenu::render() {
|
void PSMenu::render()
|
||||||
if(m_selected_item < 0) {
|
{
|
||||||
|
if (m_selected_item < 0)
|
||||||
|
{
|
||||||
onPressedDown();
|
onPressedDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,31 +31,24 @@ void PSMenu::render() {
|
|||||||
|
|
||||||
int x = 8; // sure?
|
int x = 8; // sure?
|
||||||
auto widget = m_items.at(m_selected_item);
|
auto widget = m_items.at(m_selected_item);
|
||||||
renderWidget(
|
renderWidget(widget.getType(), u8g2_font_helvB08_tr, x, u8g2->height / 2 + 3, widget.getText().c_str());
|
||||||
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);
|
auto item = m_items.at(m_selected_item - 1);
|
||||||
renderWidget(item.getType(), u8g2_font_haxrcorp4089_tr, x, 14, item.getText().c_str());
|
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);
|
auto item = m_items.at(m_selected_item + 1);
|
||||||
renderWidget(
|
renderWidget(item.getType(), u8g2_font_haxrcorp4089_tr, x, u8g2->height - 10, item.getText().c_str());
|
||||||
item.getType(),
|
|
||||||
u8g2_font_haxrcorp4089_tr,
|
|
||||||
x,
|
|
||||||
u8g2->height - 10,
|
|
||||||
item.getText().c_str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSMenu::renderWidget(
|
void PSMenu::renderWidget(const uint8_t type, const uint8_t *font, const int x, const int y, const char *text) const
|
||||||
const uint8_t type,
|
{
|
||||||
const uint8_t* font,
|
switch (type)
|
||||||
const int x,
|
{
|
||||||
const int y,
|
|
||||||
const char* text) const {
|
|
||||||
switch(type) {
|
|
||||||
case 0: // text
|
case 0: // text
|
||||||
u8g2_SetFont(u8g2, font);
|
u8g2_SetFont(u8g2, font);
|
||||||
u8g2_DrawStr(u8g2, x, y, text);
|
u8g2_DrawStr(u8g2, x, y, text);
|
||||||
@@ -64,8 +59,10 @@ void PSMenu::renderWidget(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSMenu::onButtonClicked(uint8_t button) {
|
void PSMenu::onButtonClicked(uint8_t button)
|
||||||
switch(button) {
|
{
|
||||||
|
switch (button)
|
||||||
|
{
|
||||||
case BUTTON_UP:
|
case BUTTON_UP:
|
||||||
onPressedUp();
|
onPressedUp();
|
||||||
break;
|
break;
|
||||||
@@ -95,59 +92,77 @@ void PSMenu::onButtonClicked(uint8_t button) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSMenu::onPressedDown() {
|
void PSMenu::onPressedDown()
|
||||||
if(m_selected_item == m_items.size() - 1) {
|
{
|
||||||
|
if (m_selected_item == m_items.size() - 1)
|
||||||
|
{
|
||||||
m_selected_item = 0;
|
m_selected_item = 0;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_selected_item++;
|
m_selected_item++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSMenu::onPressedUp() {
|
void PSMenu::onPressedUp()
|
||||||
if(m_selected_item == 0) {
|
{
|
||||||
|
if (m_selected_item == 0)
|
||||||
|
{
|
||||||
m_selected_item = m_items.size() - 1;
|
m_selected_item = m_items.size() - 1;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
m_selected_item--;
|
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);
|
m_items.at(m_selected_item).callback(m_selected_item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSMenu::onPressedBack() const {
|
void PSMenu::onPressedBack() const
|
||||||
if(m_options && m_options->popScreen) {
|
{
|
||||||
|
if (m_options && m_options->popScreen)
|
||||||
|
{
|
||||||
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);
|
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);
|
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);
|
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 scrollBar(m_options, u8g2->width - 3, 3, 1, u8g2->height - 6);
|
||||||
scrollBar.refresh(m_selected_item, m_items.size());
|
scrollBar.refresh(m_selected_item, m_items.size());
|
||||||
scrollBar.render();
|
scrollBar.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PSMenu::drawSelectionBox() const {
|
void PSMenu::drawSelectionBox() const
|
||||||
|
{
|
||||||
const auto displayHeight = u8g2->height;
|
const auto displayHeight = u8g2->height;
|
||||||
const auto displayWidth = u8g2->width;
|
const auto displayWidth = u8g2->width;
|
||||||
constexpr auto rightPadding = 8;
|
constexpr auto rightPadding = 8;
|
||||||
|
@@ -1,29 +1,22 @@
|
|||||||
#include "common/ScrollBar.h"
|
#include "common/ScrollBar.h"
|
||||||
|
|
||||||
ScrollBar::ScrollBar(
|
ScrollBar::ScrollBar(const menu_options_t *options, const size_t x, const size_t y, const size_t width,
|
||||||
const menu_options_t* options,
|
const size_t height)
|
||||||
const size_t x,
|
: Widget(options->u8g2), m_x(x), m_y(y), m_width(width), m_height(height), m_value(0), m_max(0), m_min(0),
|
||||||
const size_t y,
|
m_thumbHeight(0), m_thumbY(0)
|
||||||
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() {
|
void ScrollBar::render()
|
||||||
if(1 == m_max) return;
|
{
|
||||||
|
if (1 == m_max)
|
||||||
|
return;
|
||||||
|
|
||||||
// draw dotted line
|
// draw dotted line
|
||||||
for(size_t y = m_y; y < m_y + m_height; y++) {
|
for (size_t y = m_y; y < m_y + m_height; y++)
|
||||||
if(y % 2 == 0) {
|
{
|
||||||
|
if (y % 2 == 0)
|
||||||
|
{
|
||||||
u8g2_DrawPixel(u8g2, m_x, y);
|
u8g2_DrawPixel(u8g2, m_x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,7 +25,8 @@ void ScrollBar::render() {
|
|||||||
u8g2_DrawBox(u8g2, u8g2->width - 4, m_thumbY, 3, m_thumbHeight);
|
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_value = value;
|
||||||
m_max = max;
|
m_max = max;
|
||||||
m_min = min;
|
m_min = min;
|
||||||
|
@@ -1,14 +1,17 @@
|
|||||||
#include "common/Widget.h"
|
#include "common/Widget.h"
|
||||||
|
|
||||||
Widget::Widget(u8g2_t* u8g2)
|
Widget::Widget(u8g2_t *u8g2) : u8g2(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)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,17 @@
|
|||||||
#include "data/MenuItem.h"
|
#include "data/MenuItem.h"
|
||||||
|
|
||||||
MenuItem::MenuItem(const uint8_t type, std::string text, std::function<void(uint8_t)> callback)
|
MenuItem::MenuItem(const uint8_t type, std::string text, std::function<void(uint8_t)> callback)
|
||||||
: m_type(type)
|
: m_type(type), m_text(std::move(text)), m_callback(std::move(callback))
|
||||||
, m_text(std::move(text))
|
{
|
||||||
, m_callback(std::move(callback)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem::MenuItem(
|
MenuItem::MenuItem(const uint8_t type, std::string text, std::string value, std::function<void(uint8_t)> callback)
|
||||||
const uint8_t type,
|
: m_type(type), m_text(std::move(text)), m_value(std::move(value)), m_callback(std::move(callback))
|
||||||
std::string text,
|
{
|
||||||
std::string value,
|
|
||||||
std::function<void(uint8_t)> 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;
|
return m_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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("Tag/Nacht", nullptr);
|
||||||
addText("LED Einstellungen", demoL);
|
addText("LED Einstellungen", demoL);
|
||||||
|
@@ -4,16 +4,17 @@
|
|||||||
#include "ui/LightMenu.h"
|
#include "ui/LightMenu.h"
|
||||||
#include "ui/SettingsMenu.h"
|
#include "ui/SettingsMenu.h"
|
||||||
|
|
||||||
MainMenu::MainMenu(menu_options_t* options)
|
MainMenu::MainMenu(menu_options_t *options) : PSMenu(options), m_options(options)
|
||||||
: PSMenu(options)
|
{
|
||||||
, m_options(options) {
|
|
||||||
addText("Lichtsteuerung", [this](const uint8_t button) { onSelect(button); });
|
addText("Lichtsteuerung", [this](const uint8_t button) { onSelect(button); });
|
||||||
addText("Einstellungen", [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> widget;
|
std::shared_ptr<Widget> widget;
|
||||||
switch(id) {
|
switch (id)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
widget = std::make_shared<LightMenu>(m_options);
|
widget = std::make_shared<LightMenu>(m_options);
|
||||||
break;
|
break;
|
||||||
@@ -21,7 +22,8 @@ void MainMenu::onSelect(const uint8_t id) const {
|
|||||||
widget = std::make_shared<SettingsMenu>(m_options);
|
widget = std::make_shared<SettingsMenu>(m_options);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(m_options && m_options->pushScreen) {
|
if (m_options && m_options->pushScreen)
|
||||||
|
{
|
||||||
m_options->pushScreen(widget);
|
m_options->pushScreen(widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
addText("OTA Einspielen", demo);
|
||||||
}
|
}
|
||||||
|
@@ -10,16 +10,18 @@
|
|||||||
|
|
||||||
uint64_t counter = 0;
|
uint64_t counter = 0;
|
||||||
|
|
||||||
SplashScreen::SplashScreen(menu_options_t* options)
|
SplashScreen::SplashScreen(menu_options_t *options) : Widget(options->u8g2), m_options(options)
|
||||||
: Widget(options->u8g2)
|
{
|
||||||
, m_options(options) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplashScreen::update(const uint64_t dt) {
|
void SplashScreen::update(const uint64_t dt)
|
||||||
|
{
|
||||||
counter += dt;
|
counter += dt;
|
||||||
if(counter > 200000) {
|
if (counter > 200000)
|
||||||
|
{
|
||||||
counter = 0;
|
counter = 0;
|
||||||
if(m_options && m_options->setScreen) {
|
if (m_options && m_options->setScreen)
|
||||||
|
{
|
||||||
m_options->setScreen(std::make_shared<MainMenu>(m_options));
|
m_options->setScreen(std::make_shared<MainMenu>(m_options));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -28,7 +30,8 @@ void SplashScreen::update(const uint64_t dt) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void SplashScreen::render() {
|
void SplashScreen::render()
|
||||||
|
{
|
||||||
u8g2_SetFont(u8g2, u8g2_font_DigitalDisco_tr);
|
u8g2_SetFont(u8g2, u8g2_font_DigitalDisco_tr);
|
||||||
u8g2_DrawStr(u8g2, 28, u8g2->height / 2 - 10, "HO Anlage");
|
u8g2_DrawStr(u8g2, 28, u8g2->height / 2 - 10, "HO Anlage");
|
||||||
u8g2_DrawStr(u8g2, 30, u8g2->height / 2 + 5, "Axel Janz");
|
u8g2_DrawStr(u8g2, 30, u8g2->height / 2 + 5, "Axel Janz");
|
||||||
|
@@ -1,10 +1,10 @@
|
|||||||
if (DEFINED ENV{IDF_PATH})
|
if (DEFINED ENV{IDF_PATH})
|
||||||
idf_component_register(SRCS
|
idf_component_register(SRCS
|
||||||
PushButton.cpp
|
PushButton.cpp
|
||||||
INCLUDE_DIRS "include"
|
INCLUDE_DIRS "include"
|
||||||
)
|
)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif ()
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.30)
|
cmake_minimum_required(VERSION 3.30)
|
||||||
project(peter)
|
project(peter)
|
||||||
|
@@ -1,42 +1,43 @@
|
|||||||
#include "button_handling.h"
|
#include "button_handling.h"
|
||||||
|
|
||||||
#include "sdkconfig.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/i2c.h"
|
#include "driver/i2c.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_timer.h"
|
|
||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
|
#include "esp_timer.h"
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
static const char* TAG = "button_handling";
|
static const char *TAG = "button_handling";
|
||||||
|
|
||||||
#define DEBOUNCE_TIME_MS (500)
|
#define DEBOUNCE_TIME_MS (500)
|
||||||
|
|
||||||
#define BUTTON_QUEUE_LENGTH 5
|
#define BUTTON_QUEUE_LENGTH 5
|
||||||
#define BUTTON_QUEUE_ITEM_SIZE sizeof(uint8_t)
|
#define BUTTON_QUEUE_ITEM_SIZE sizeof(uint8_t)
|
||||||
|
|
||||||
#define WLED_GPIO GPIO_NUM_47
|
#define WLED_GPIO GPIO_NUM_47
|
||||||
#define WLED_RMT_CHANNEL RMT_CHANNEL_0
|
#define WLED_RMT_CHANNEL RMT_CHANNEL_0
|
||||||
#define WLED_RESOLUTION_HZ (10000000)
|
#define WLED_RESOLUTION_HZ (10000000)
|
||||||
#define WLED_ON_DURATION_MS (100)
|
#define WLED_ON_DURATION_MS (100)
|
||||||
#define NUM_LEDS (1)
|
#define NUM_LEDS (1)
|
||||||
|
|
||||||
const uint8_t pins[] =
|
const uint8_t pins[] = {BUTTON_DOWN, BUTTON_UP, BUTTON_LEFT, BUTTON_RIGHT, BUTTON_SELECT, BUTTON_BACK};
|
||||||
{BUTTON_DOWN, BUTTON_UP, BUTTON_LEFT, BUTTON_RIGHT, BUTTON_SELECT, BUTTON_BACK};
|
|
||||||
|
|
||||||
QueueHandle_t buttonQueue = NULL;
|
QueueHandle_t buttonQueue = NULL;
|
||||||
volatile int64_t last_interrupt_time = 0;
|
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();
|
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;
|
last_interrupt_time = now;
|
||||||
|
|
||||||
uintptr_t pin_value = (uintptr_t)arg;
|
uintptr_t pin_value = (uintptr_t)arg;
|
||||||
@@ -45,26 +46,31 @@ void IRAM_ATTR button_isr_handler(void* arg) {
|
|||||||
|
|
||||||
xQueueSendFromISR(buttonQueue, &press_signal, &higherPriorityTaskWoken);
|
xQueueSendFromISR(buttonQueue, &press_signal, &higherPriorityTaskWoken);
|
||||||
|
|
||||||
if(higherPriorityTaskWoken) {
|
if (higherPriorityTaskWoken)
|
||||||
|
{
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupButtons(void) {
|
void setupButtons(void)
|
||||||
|
{
|
||||||
buttonQueue = xQueueCreate(BUTTON_QUEUE_LENGTH, BUTTON_QUEUE_ITEM_SIZE);
|
buttonQueue = xQueueCreate(BUTTON_QUEUE_LENGTH, BUTTON_QUEUE_ITEM_SIZE);
|
||||||
if(buttonQueue == NULL) {
|
if (buttonQueue == NULL)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Error while Queue creation!");
|
ESP_LOGE(TAG, "Error while Queue creation!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "Button Queue created.");
|
ESP_LOGI(TAG, "Button Queue created.");
|
||||||
|
|
||||||
esp_err_t isr_service_err = gpio_install_isr_service(ESP_INTR_FLAG_IRAM);
|
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));
|
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];
|
const uint8_t pin = pins[i];
|
||||||
gpio_config_t io_conf;
|
gpio_config_t io_conf;
|
||||||
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
||||||
@@ -75,8 +81,9 @@ void setupButtons(void) {
|
|||||||
gpio_config(&io_conf);
|
gpio_config(&io_conf);
|
||||||
|
|
||||||
uintptr_t pin_as_arg = (uintptr_t)pin;
|
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);
|
esp_err_t add_isr_err = gpio_isr_handler_add(pin, button_isr_handler, (void *)pin_as_arg);
|
||||||
if(add_isr_err != ESP_OK) {
|
if (add_isr_err != ESP_OK)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "Error in gpio_isr_handler_add: %s", esp_err_to_name(add_isr_err));
|
ESP_LOGE(TAG, "Error in gpio_isr_handler_add: %s", esp_err_to_name(add_isr_err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
void setupButtons(void);
|
void setupButtons(void);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
@@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define BUTTON_UP GPIO_NUM_1
|
#define BUTTON_UP GPIO_NUM_1
|
||||||
#define BUTTON_DOWN GPIO_NUM_6
|
#define BUTTON_DOWN GPIO_NUM_6
|
||||||
#define BUTTON_LEFT GPIO_NUM_3
|
#define BUTTON_LEFT GPIO_NUM_3
|
||||||
#define BUTTON_RIGHT GPIO_NUM_5
|
#define BUTTON_RIGHT GPIO_NUM_5
|
||||||
#define BUTTON_SELECT GPIO_NUM_18
|
#define BUTTON_SELECT GPIO_NUM_18
|
||||||
#define BUTTON_BACK GPIO_NUM_16
|
#define BUTTON_BACK GPIO_NUM_16
|
18
main/main.c
18
main/main.c
@@ -1,19 +1,23 @@
|
|||||||
#include "setup.h"
|
|
||||||
#include "freertos/idf_additions.h"
|
#include "freertos/idf_additions.h"
|
||||||
|
#include "setup.h"
|
||||||
|
|
||||||
void app_task(void* param) {
|
void app_task(void *param)
|
||||||
|
{
|
||||||
setup();
|
setup();
|
||||||
while(1) {
|
while (1)
|
||||||
|
{
|
||||||
loop();
|
loop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
void app_main(void) {
|
void app_main(void)
|
||||||
xTaskCreatePinnedToCore(app_task, "main_loop", 4096, NULL, 5, NULL, tskIDLE_PRIORITY + 1);
|
{
|
||||||
}
|
xTaskCreatePinnedToCore(app_task, "main_loop", 4096, NULL, 5, NULL, tskIDLE_PRIORITY + 1);
|
||||||
|
}
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
49
main/setup.c
49
main/setup.c
@@ -1,7 +1,5 @@
|
|||||||
#include "setup.h"
|
#include "setup.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
@@ -9,6 +7,8 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
#include "freertos/task.h"
|
#include "freertos/task.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "driver/rmt_encoder.h"
|
#include "driver/rmt_encoder.h"
|
||||||
#include "driver/rmt_tx.h"
|
#include "driver/rmt_tx.h"
|
||||||
@@ -16,22 +16,22 @@
|
|||||||
#include "u8g2.h"
|
#include "u8g2.h"
|
||||||
#include "u8g2_esp32_hal.h"
|
#include "u8g2_esp32_hal.h"
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "button_handling.h"
|
#include "button_handling.h"
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
#define PIN_SDA GPIO_NUM_35
|
#define PIN_SDA GPIO_NUM_35
|
||||||
#define PIN_SCL GPIO_NUM_36
|
#define PIN_SCL GPIO_NUM_36
|
||||||
#define PIN_RST GPIO_NUM_NC
|
#define PIN_RST GPIO_NUM_NC
|
||||||
|
|
||||||
#define WLED_GPIO GPIO_NUM_47
|
#define WLED_GPIO GPIO_NUM_47
|
||||||
#define WLED_RMT_CHANNEL RMT_CHANNEL_0
|
#define WLED_RMT_CHANNEL RMT_CHANNEL_0
|
||||||
#define WLED_RESOLUTION_HZ (10000000)
|
#define WLED_RESOLUTION_HZ (10000000)
|
||||||
#define WLED_ON_DURATION_MS (100)
|
#define WLED_ON_DURATION_MS (100)
|
||||||
#define NUM_LEDS (1)
|
#define NUM_LEDS (1)
|
||||||
|
|
||||||
uint8_t last_value = 0;
|
uint8_t last_value = 0;
|
||||||
|
|
||||||
static const char* TAG = "main";
|
static const char *TAG = "main";
|
||||||
|
|
||||||
extern QueueHandle_t buttonQueue;
|
extern QueueHandle_t buttonQueue;
|
||||||
|
|
||||||
@@ -43,7 +43,8 @@ int64_t wled_turn_off_time = 0;
|
|||||||
u8g2_t u8g2;
|
u8g2_t u8g2;
|
||||||
uint8_t received_signal;
|
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);
|
ESP_LOGI(TAG, "Initialize RMT TX Channel for WS2812B on GPIO %d", WLED_GPIO);
|
||||||
rmt_tx_channel_config_t tx_chan_config = {
|
rmt_tx_channel_config_t tx_chan_config = {
|
||||||
.gpio_num = WLED_GPIO,
|
.gpio_num = WLED_GPIO,
|
||||||
@@ -66,15 +67,18 @@ static void init_rmt_ws2812b(void) {
|
|||||||
ESP_ERROR_CHECK(rmt_enable(rmt_led_chan));
|
ESP_ERROR_CHECK(rmt_enable(rmt_led_chan));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_wled_color(uint8_t r, uint8_t g, uint8_t b) {
|
static void set_wled_color(uint8_t r, uint8_t g, uint8_t b)
|
||||||
if(!rmt_led_chan || !rmt_led_encoder) {
|
{
|
||||||
|
if (!rmt_led_chan || !rmt_led_encoder)
|
||||||
|
{
|
||||||
ESP_LOGE(TAG, "RMT Channel or Encoder not initialized!");
|
ESP_LOGE(TAG, "RMT Channel or Encoder not initialized!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t buffer_size = 3 * NUM_LEDS;
|
size_t buffer_size = 3 * NUM_LEDS;
|
||||||
uint8_t led_data[buffer_size];
|
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 + 0] = g;
|
||||||
led_data[i * 3 + 1] = r;
|
led_data[i * 3 + 1] = r;
|
||||||
led_data[i * 3 + 2] = b;
|
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 = {
|
rmt_transmit_config_t tx_config = {
|
||||||
.loop_count = 0,
|
.loop_count = 0,
|
||||||
};
|
};
|
||||||
esp_err_t ret =
|
esp_err_t ret = rmt_transmit(rmt_led_chan, rmt_led_encoder, led_data, sizeof(led_data), &tx_config);
|
||||||
rmt_transmit(rmt_led_chan, rmt_led_encoder, led_data, sizeof(led_data), &tx_config);
|
if (ret != ESP_OK)
|
||||||
if(ret != ESP_OK) {
|
{
|
||||||
ESP_LOGE(TAG, "RMT Transmit failed: %s", esp_err_to_name(ret));
|
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)));
|
ESP_ERROR_CHECK(rmt_tx_wait_all_done(rmt_led_chan, pdMS_TO_TICKS(100)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup(void) {
|
void setup(void)
|
||||||
|
{
|
||||||
setupButtons();
|
setupButtons();
|
||||||
|
|
||||||
u8g2_esp32_hal_t u8g2_esp32_hal = U8G2_ESP32_HAL_DEFAULT;
|
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.reset = PIN_RST;
|
||||||
u8g2_esp32_hal_init(u8g2_esp32_hal);
|
u8g2_esp32_hal_init(u8g2_esp32_hal);
|
||||||
|
|
||||||
u8g2_Setup_sh1106_i2c_128x64_noname_f(
|
u8g2_Setup_sh1106_i2c_128x64_noname_f(&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb);
|
||||||
&u8g2, U8G2_R0, u8g2_esp32_i2c_byte_cb, u8g2_esp32_gpio_and_delay_cb);
|
|
||||||
u8x8_SetI2CAddress(&u8g2.u8x8, 0x3C * 2);
|
u8x8_SetI2CAddress(&u8g2.u8x8, 0x3C * 2);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "u8g2_InitDisplay");
|
ESP_LOGI(TAG, "u8g2_InitDisplay");
|
||||||
@@ -115,7 +119,8 @@ void setup(void) {
|
|||||||
ESP_LOGI(TAG, "Start of main loop. Waiting for button press...");
|
ESP_LOGI(TAG, "Start of main loop. Waiting for button press...");
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(void) {
|
void loop(void)
|
||||||
|
{
|
||||||
u8g2_ClearBuffer(&u8g2);
|
u8g2_ClearBuffer(&u8g2);
|
||||||
u8g2_SetFont(&u8g2, u8g2_font_ncenB10_tr);
|
u8g2_SetFont(&u8g2, u8g2_font_ncenB10_tr);
|
||||||
u8g2_DrawStr(&u8g2, 5, 20, "Ready!");
|
u8g2_DrawStr(&u8g2, 5, 20, "Ready!");
|
||||||
@@ -124,7 +129,8 @@ void loop(void) {
|
|||||||
u8g2_DrawStr(&u8g2, 5, 45, count_str);
|
u8g2_DrawStr(&u8g2, 5, 45, count_str);
|
||||||
u8g2_SendBuffer(&u8g2);
|
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!");
|
ESP_LOGI(TAG, "Button event from Queue received!");
|
||||||
|
|
||||||
last_value = received_signal;
|
last_value = received_signal;
|
||||||
@@ -143,7 +149,8 @@ void loop(void) {
|
|||||||
wled_turn_off_time = esp_timer_get_time() + (WLED_ON_DURATION_MS * 1000);
|
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");
|
ESP_LOGD(TAG, "Switch WLED OFF");
|
||||||
set_wled_color(0, 0, 0);
|
set_wled_color(0, 0, 0);
|
||||||
wled_is_on = false;
|
wled_is_on = false;
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
void setup(void);
|
void setup(void);
|
||||||
void loop(void);
|
void loop(void);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
@@ -2,11 +2,13 @@
|
|||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
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;
|
constexpr uint32_t window_flag = SDL_WINDOW_HIDDEN;
|
||||||
const auto window = SDL_CreateWindow(title, width, height, window_flag);
|
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);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create window", SDL_GetError(), nullptr);
|
||||||
return 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();
|
const SDL_PropertiesID props = SDL_CreateProperties();
|
||||||
SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window);
|
SDL_SetPointerProperty(props, SDL_PROP_RENDERER_CREATE_WINDOW_POINTER, window);
|
||||||
SDL_SetNumberProperty(props, SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER, SDL_COLORSPACE_SRGB_LINEAR);
|
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);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Couldn't create renderer", SDL_GetError(), nullptr);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
#include "model/Window.h"
|
#include "model/Window.h"
|
||||||
|
|
||||||
auto createWindow(const char *title, int width, int height) -> Window *;
|
auto CreateWindow(const char *title, int width, int height) -> Window *;
|
||||||
|
@@ -1,46 +1,108 @@
|
|||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <iostream>
|
|
||||||
#include <SDL3_image/SDL_image.h>
|
#include <SDL3_image/SDL_image.h>
|
||||||
|
#include <memory>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
ResourceManager& ResourceManager::getInstance() {
|
ResourceManager &ResourceManager::Instance()
|
||||||
|
{
|
||||||
static ResourceManager instance;
|
static ResourceManager instance;
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceManager::ResourceManager() {
|
ResourceManager::ResourceManager()
|
||||||
|
{
|
||||||
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "ResourceManager instance created.");
|
SDL_LogDebug(SDL_LOG_CATEGORY_APPLICATION, "ResourceManager instance created.");
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceManager::~ResourceManager() {
|
/**
|
||||||
for(const auto& texture : m_textures | std::views::values) {
|
* @brief Destructor for the ResourceManager
|
||||||
if(texture != nullptr) {
|
* 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);
|
SDL_DestroyTexture(texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_textures.clear();
|
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);
|
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;
|
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) {
|
if (!texture)
|
||||||
SDL_LogError(
|
{
|
||||||
SDL_LOG_CATEGORY_APPLICATION,
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not load %s -> %s", GetResourcePath(path).c_str(),
|
||||||
"Could not load %s -> %s",
|
SDL_GetError());
|
||||||
path.c_str(),
|
|
||||||
SDL_GetError());
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store texture in cache
|
||||||
m_textures[path] = texture;
|
m_textures[path] = texture;
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
@@ -1,27 +1,59 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <unordered_map>
|
|
||||||
#include <string>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
class ResourceManager {
|
class ResourceManager
|
||||||
|
{
|
||||||
public:
|
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(const ResourceManager &) = delete;
|
||||||
ResourceManager& operator=(const ResourceManager&) = delete;
|
ResourceManager &operator=(const ResourceManager &) = delete;
|
||||||
ResourceManager(ResourceManager&&) = delete;
|
ResourceManager(ResourceManager &&) = delete;
|
||||||
ResourceManager& operator=(ResourceManager&&) = delete;
|
ResourceManager &operator=(ResourceManager &&) = delete;
|
||||||
|
|
||||||
~ResourceManager();
|
~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:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Constructor for the ResourceManager
|
||||||
|
* Initializes a new instance and logs its creation
|
||||||
|
*/
|
||||||
ResourceManager();
|
ResourceManager();
|
||||||
|
|
||||||
std::unordered_map<std::string, SDL_Texture*> 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<std::string, SDL_Texture *> m_textures;
|
||||||
|
|
||||||
mutable std::mutex m_mutex;
|
mutable std::mutex m_mutex;
|
||||||
};
|
};
|
@@ -1,61 +1,73 @@
|
|||||||
#include "debug/DebugOverlay.h"
|
#include "debug/DebugOverlay.h"
|
||||||
|
|
||||||
#include <imgui_impl_sdlrenderer3.h>
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "imgui_impl_sdl3.h"
|
#include "imgui_impl_sdl3.h"
|
||||||
#include "ui/Matrix.h"
|
#include "ui/Matrix.h"
|
||||||
|
#include <imgui_impl_sdlrenderer3.h>
|
||||||
|
|
||||||
namespace DebugOverlay {
|
namespace DebugOverlay
|
||||||
void init(const AppContext* context) {
|
{
|
||||||
|
void Init(const AppContext *context)
|
||||||
|
{
|
||||||
IMGUI_CHECKVERSION();
|
IMGUI_CHECKVERSION();
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
ImGuiIO& io{ImGui::GetIO()};
|
ImGuiIO &io{ImGui::GetIO()};
|
||||||
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||||
|
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
|
|
||||||
ImGui_ImplSDL3_InitForSDLRenderer(context->window(), context->renderer());
|
ImGui_ImplSDL3_InitForSDLRenderer(context->MainWindow(), context->MainRenderer());
|
||||||
ImGui_ImplSDLRenderer3_Init(context->renderer());
|
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);
|
ImGui_ImplSDL3_ProcessEvent(event);
|
||||||
|
|
||||||
if(show_led_matrix) {
|
if (show_led_matrix)
|
||||||
if(context->matrix_window() == nullptr) {
|
{
|
||||||
const auto win = createWindow("LED Matrix", 32 * 50, 8 * 50);
|
if (context->LedMatrixWindow() == nullptr)
|
||||||
|
{
|
||||||
|
const auto win = CreateWindow("LED Matrix", 32 * 50, 8 * 50);
|
||||||
SDL_SetWindowFocusable(win->window(), false);
|
SDL_SetWindowFocusable(win->window(), false);
|
||||||
SDL_SetRenderVSync(win->renderer(), SDL_RENDERER_VSYNC_ADAPTIVE);
|
SDL_SetRenderVSync(win->renderer(), SDL_RENDERER_VSYNC_ADAPTIVE);
|
||||||
SDL_SetWindowPosition(win->window(), 0, 0);
|
SDL_SetWindowPosition(win->window(), 0, 0);
|
||||||
SDL_ShowWindow(win->window());
|
SDL_ShowWindow(win->window());
|
||||||
|
|
||||||
context->setMatrix(new Matrix(win));
|
context->SetMatrix(new Matrix(win));
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if(context->matrix_window() != nullptr) {
|
else
|
||||||
SDL_DestroyWindow(context->matrix_window());
|
{
|
||||||
|
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_ImplSDLRenderer3_NewFrame();
|
||||||
ImGui_ImplSDL3_NewFrame();
|
ImGui_ImplSDL3_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
if(show_debug_window && ImGui::BeginMainMenuBar()) {
|
if (show_debug_window && ImGui::BeginMainMenuBar())
|
||||||
if(ImGui::BeginMenu("Config")) {
|
{
|
||||||
|
if (ImGui::BeginMenu("Config"))
|
||||||
|
{
|
||||||
ImGui::Checkbox("Show LED Matrix", &show_led_matrix);
|
ImGui::Checkbox("Show LED Matrix", &show_led_matrix);
|
||||||
ImGui::Checkbox("Show Unhandled Events", &show_unhandled_events);
|
ImGui::Checkbox("Show Unhandled Events", &show_unhandled_events);
|
||||||
|
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
if(ImGui::BeginMenu("Help")) {
|
if (ImGui::BeginMenu("Help"))
|
||||||
|
{
|
||||||
ImGui::Text("FPS: %.2f", ImGui::GetIO().Framerate);
|
ImGui::Text("FPS: %.2f", ImGui::GetIO().Framerate);
|
||||||
ImGui::SeparatorText("App Info");
|
ImGui::SeparatorText("App Info");
|
||||||
ImGui::Text("Project: %s", MyProject.c_str());
|
ImGui::Text("Project: %s", MyProject.c_str());
|
||||||
@@ -70,12 +82,13 @@ void render(const AppContext* context) {
|
|||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), context->renderer());
|
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), context->MainRenderer());
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup() {
|
void Cleanup()
|
||||||
|
{
|
||||||
ImGui_ImplSDLRenderer3_Shutdown();
|
ImGui_ImplSDLRenderer3_Shutdown();
|
||||||
ImGui_ImplSDL3_Shutdown();
|
ImGui_ImplSDL3_Shutdown();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
}
|
}
|
||||||
} // namespace DebugOverlay
|
} // namespace DebugOverlay
|
@@ -4,16 +4,17 @@
|
|||||||
|
|
||||||
#include "model/AppContext.h"
|
#include "model/AppContext.h"
|
||||||
|
|
||||||
namespace DebugOverlay {
|
namespace DebugOverlay
|
||||||
|
{
|
||||||
inline bool show_debug_window = false;
|
inline bool show_debug_window = false;
|
||||||
inline bool show_unhandled_events = 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();
|
||||||
}
|
}
|
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
#include "u8g2.h"
|
#include "u8g2.h"
|
||||||
|
|
||||||
#define U8G2_SCREEN_WIDTH (128)
|
#define U8G2_SCREEN_WIDTH (128)
|
||||||
#define U8G2_SCREEN_HEIGHT (64)
|
#define U8G2_SCREEN_HEIGHT (64)
|
||||||
#define U8G2_SCREEN_FACTOR (3)
|
#define U8G2_SCREEN_FACTOR (3)
|
||||||
#define U8G2_SCREEN_PADDING (25)
|
#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_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_gpio_and_delay_sdl(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr);
|
||||||
|
@@ -3,8 +3,10 @@
|
|||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
uint8_t u8x8_byte_sdl_hw_spi(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)
|
||||||
switch(msg) {
|
{
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
case U8X8_MSG_BYTE_SEND:
|
case U8X8_MSG_BYTE_SEND:
|
||||||
case U8X8_MSG_BYTE_INIT:
|
case U8X8_MSG_BYTE_INIT:
|
||||||
case U8X8_MSG_BYTE_SET_DC:
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t u8x8_gpio_and_delay_sdl(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)
|
||||||
switch(msg) {
|
{
|
||||||
|
switch (msg)
|
||||||
|
{
|
||||||
case U8X8_MSG_DELAY_MILLI:
|
case U8X8_MSG_DELAY_MILLI:
|
||||||
SDL_Delay(arg_int);
|
SDL_Delay(arg_int);
|
||||||
break;
|
break;
|
||||||
|
160
src/main.cc
160
src/main.cc
@@ -1,160 +0,0 @@
|
|||||||
#include <imgui_impl_sdlrenderer3.h>
|
|
||||||
#include <vector>
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include <SDL3/SDL_main.h>
|
|
||||||
|
|
||||||
#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> device;
|
|
||||||
std::vector<std::shared_ptr<UIWidget>> 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<Device>(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<AppContext*>(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<AppContext*>(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();
|
|
||||||
}
|
|
180
src/main.cpp
Normal file
180
src/main.cpp
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <SDL3/SDL_main.h>
|
||||||
|
#include <imgui_impl_sdlrenderer3.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <u8g2.h>
|
||||||
|
|
||||||
|
#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> device;
|
||||||
|
std::vector<std::shared_ptr<UIWidget>> 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<Device>(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<AppContext *>(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<AppContext *>(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();
|
||||||
|
}
|
@@ -2,42 +2,53 @@
|
|||||||
|
|
||||||
#include "ui/Matrix.h"
|
#include "ui/Matrix.h"
|
||||||
|
|
||||||
auto AppContext::window() const -> SDL_Window* {
|
auto AppContext::MainWindow() const -> SDL_Window *
|
||||||
|
{
|
||||||
return m_window->window();
|
return m_window->window();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppContext::renderer() const -> SDL_Renderer* {
|
auto AppContext::MainRenderer() const -> SDL_Renderer *
|
||||||
|
{
|
||||||
return m_window->renderer();
|
return m_window->renderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppContext::surface() const -> SDL_Surface* {
|
auto AppContext::MainSurface() const -> SDL_Surface *
|
||||||
|
{
|
||||||
return SDL_GetWindowSurface(m_window->window());
|
return SDL_GetWindowSurface(m_window->window());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppContext::setMatrix(Matrix* matrix) {
|
void AppContext::SetMatrix(Matrix *matrix)
|
||||||
|
{
|
||||||
m_matrix = matrix;
|
m_matrix = matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppContext::matrix() const -> Matrix* {
|
auto AppContext::LedMatrix() const -> Matrix *
|
||||||
|
{
|
||||||
return m_matrix;
|
return m_matrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppContext::matrix_window() const -> SDL_Window* {
|
auto AppContext::LedMatrixWindow() const -> SDL_Window *
|
||||||
if(m_matrix && m_matrix->window()) {
|
{
|
||||||
|
if (m_matrix && m_matrix->window())
|
||||||
|
{
|
||||||
return m_matrix->window()->window();
|
return m_matrix->window()->window();
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto AppContext::matrix_renderer() const -> SDL_Renderer* {
|
auto AppContext::LedMatrixRenderer() const -> SDL_Renderer *
|
||||||
if(m_matrix && m_matrix->window()) {
|
{
|
||||||
|
if (m_matrix && m_matrix->window())
|
||||||
|
{
|
||||||
return m_matrix->window()->renderer();
|
return m_matrix->window()->renderer();
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppContext::matrix_render() const {
|
void AppContext::Render() const
|
||||||
if(m_matrix && m_matrix->window()) {
|
{
|
||||||
m_matrix->render();
|
if (m_matrix && m_matrix->window())
|
||||||
|
{
|
||||||
|
m_matrix->Render();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -5,39 +5,41 @@
|
|||||||
|
|
||||||
class Matrix;
|
class Matrix;
|
||||||
|
|
||||||
class AppContext {
|
class AppContext
|
||||||
public:
|
{
|
||||||
explicit AppContext(const Window* window)
|
public:
|
||||||
: m_window(window) {
|
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);
|
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_default);
|
||||||
TTF_CloseFont(m_font_text);
|
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:
|
private:
|
||||||
const Window* m_window;
|
const Window *m_window;
|
||||||
Matrix* m_matrix = nullptr;
|
Matrix *m_matrix = nullptr;
|
||||||
TTF_Font* m_font_text = nullptr;
|
TTF_Font *m_font_text = nullptr;
|
||||||
};
|
};
|
||||||
|
@@ -1,9 +1,11 @@
|
|||||||
#include "model/Window.h"
|
#include "model/Window.h"
|
||||||
|
|
||||||
auto Window::window() const -> SDL_Window* {
|
auto Window::window() const -> SDL_Window *
|
||||||
|
{
|
||||||
return m_window;
|
return m_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Window::renderer() const -> SDL_Renderer* {
|
auto Window::renderer() const -> SDL_Renderer *
|
||||||
|
{
|
||||||
return SDL_GetRenderer(m_window);
|
return SDL_GetRenderer(m_window);
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,17 @@
|
|||||||
|
|
||||||
#include "SDL3/SDL.h"
|
#include "SDL3/SDL.h"
|
||||||
|
|
||||||
class Window {
|
class Window
|
||||||
public:
|
{
|
||||||
explicit Window(SDL_Window* window)
|
public:
|
||||||
: m_window(window) {
|
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:
|
private:
|
||||||
SDL_Window* m_window = nullptr;
|
SDL_Window *m_window = nullptr;
|
||||||
};
|
};
|
||||||
|
@@ -1,200 +1,264 @@
|
|||||||
#include "ui/Device.h"
|
#include "ui/Device.h"
|
||||||
|
|
||||||
#include "SDL3_ttf/SDL_ttf.h"
|
#include <hal/u8g2_hal_sdl.h>
|
||||||
|
#include <u8g2.h>
|
||||||
|
|
||||||
|
#include "MenuOptions.h"
|
||||||
|
#include "ui/SplashScreen.h"
|
||||||
#include "ui/widgets/Button.h"
|
#include "ui/widgets/Button.h"
|
||||||
#include "ui/widgets/D_Pad.h"
|
#include "ui/widgets/D_Pad.h"
|
||||||
|
|
||||||
#include <u8g2.h>
|
|
||||||
#include <hal/u8g2_hal_sdl.h>
|
|
||||||
|
|
||||||
#include "ui/SplashScreen.h"
|
|
||||||
#include "MenuOptions.h"
|
|
||||||
|
|
||||||
u8g2_t u8g2;
|
u8g2_t u8g2;
|
||||||
menu_options_t options;
|
menu_options_t options;
|
||||||
|
|
||||||
static void set_pixel_rgba(
|
static void set_pixel_rgba(const SDL_Surface *surface, const int x, const int y, const uint32_t pixel_color)
|
||||||
const SDL_Surface* surface,
|
{
|
||||||
const int x,
|
if (!surface || x < 0 || x >= surface->w || y < 0 || y >= surface->h)
|
||||||
const int y,
|
{
|
||||||
const uint32_t pixel_color) {
|
|
||||||
if(!surface || x < 0 || x >= surface->w || y < 0 || y >= surface->h) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const auto p =
|
const auto p = static_cast<uint8_t *>(surface->pixels) + y * surface->pitch + x * sizeof(uint32_t);
|
||||||
static_cast<uint8_t*>(surface->pixels) + y * surface->pitch + x * sizeof(uint32_t);
|
*reinterpret_cast<uint32_t *>(p) = pixel_color;
|
||||||
*reinterpret_cast<uint32_t*>(p) = pixel_color;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Device(void* appstate)
|
Device::Device(void *appstate) : UIWidget(appstate)
|
||||||
: UIWidget(appstate) {
|
{
|
||||||
m_children.push_back(
|
auto dpad_callback = [](const D_Pad::Direction direction) {
|
||||||
std::make_shared<Button>(
|
SDL_Keycode key = 0;
|
||||||
get_context(),
|
switch (direction)
|
||||||
U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + DPAD_WIDTH,
|
{
|
||||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - BUTTON_WIDTH,
|
case D_Pad::Direction::UP:
|
||||||
BUTTON_WIDTH,
|
key = SDLK_UP;
|
||||||
[]() { pushKey(SDLK_RETURN); }));
|
break;
|
||||||
m_children.push_back(
|
case D_Pad::Direction::DOWN:
|
||||||
std::make_shared<Button>(
|
key = SDLK_DOWN;
|
||||||
get_context(),
|
break;
|
||||||
U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 4 * U8G2_SCREEN_PADDING + DPAD_WIDTH +
|
case D_Pad::Direction::LEFT:
|
||||||
BUTTON_WIDTH,
|
key = SDLK_LEFT;
|
||||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - 2 * BUTTON_WIDTH,
|
break;
|
||||||
BUTTON_WIDTH,
|
case D_Pad::Direction::RIGHT:
|
||||||
[]() { pushKey(SDLK_BACKSPACE); }));
|
key = SDLK_RIGHT;
|
||||||
m_children.push_back(
|
break;
|
||||||
std::make_shared<D_Pad>(
|
case D_Pad::Direction::NONE: // Fallthrough oder keine Aktion
|
||||||
get_context(),
|
default:
|
||||||
U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 2 * U8G2_SCREEN_PADDING,
|
break;
|
||||||
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - DPAD_WIDTH,
|
}
|
||||||
DPAD_WIDTH,
|
if (key != 0)
|
||||||
[](int d) {}));
|
{
|
||||||
|
PushKey(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
u8g2_Setup_sh1106_128x64_noname_f(
|
m_children.push_back(std::make_shared<Button>(
|
||||||
&u8g2, U8G2_R0, u8x8_byte_sdl_hw_spi, u8x8_gpio_and_delay_sdl);
|
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 3 * U8G2_SCREEN_PADDING + DPAD_WIDTH,
|
||||||
|
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - BUTTON_WIDTH, BUTTON_WIDTH,
|
||||||
|
[]() {
|
||||||
|
PushKey(SDLK_RETURN);
|
||||||
|
}));
|
||||||
|
m_children.push_back(std::make_shared<Button>(
|
||||||
|
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 4 * U8G2_SCREEN_PADDING + DPAD_WIDTH + BUTTON_WIDTH,
|
||||||
|
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - 2 * BUTTON_WIDTH, BUTTON_WIDTH,
|
||||||
|
[]() {
|
||||||
|
PushKey(SDLK_BACKSPACE);
|
||||||
|
}));
|
||||||
|
m_children.push_back(std::make_shared<D_Pad>(
|
||||||
|
GetContext(), U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR + 2 * U8G2_SCREEN_PADDING,
|
||||||
|
U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR + U8G2_SCREEN_PADDING - DPAD_WIDTH, DPAD_WIDTH, dpad_callback));
|
||||||
|
|
||||||
|
u8g2_Setup_sh1106_128x64_noname_f(&u8g2, U8G2_R0, u8x8_byte_sdl_hw_spi, u8x8_gpio_and_delay_sdl);
|
||||||
u8x8_InitDisplay(u8g2_GetU8x8(&u8g2));
|
u8x8_InitDisplay(u8g2_GetU8x8(&u8g2));
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
.u8g2 = &u8g2,
|
.u8g2 = &u8g2,
|
||||||
.setScreen = [this](const std::shared_ptr<Widget>& screen) { this->setScreen(screen); },
|
.setScreen = [this](const std::shared_ptr<Widget> &screen) {
|
||||||
.pushScreen = [this](const std::shared_ptr<Widget>& screen) { this->pushScreen(screen); },
|
this->SetScreen(screen);
|
||||||
.popScreen = [this]() { this->popScreen(); },
|
},
|
||||||
|
.pushScreen = [this](const std::shared_ptr<Widget> &screen) {
|
||||||
|
this->PushScreen(screen);
|
||||||
|
},
|
||||||
|
.popScreen = [this]() {
|
||||||
|
this->PopScreen();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
widget = std::make_shared<SplashScreen>(&options);
|
widget = std::make_shared<SplashScreen>(&options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::setScreen(const std::shared_ptr<Widget>& screen) {
|
void Device::SetScreen(const std::shared_ptr<Widget> &screen)
|
||||||
if(screen != nullptr) {
|
{
|
||||||
|
if (screen != nullptr)
|
||||||
|
{
|
||||||
widget = screen;
|
widget = screen;
|
||||||
history.clear();
|
history.clear();
|
||||||
history.emplace_back(widget);
|
history.emplace_back(widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::pushScreen(const std::shared_ptr<Widget>& screen) {
|
void Device::PushScreen(const std::shared_ptr<Widget> &screen)
|
||||||
if(screen != nullptr) {
|
{
|
||||||
|
if (screen != nullptr)
|
||||||
|
{
|
||||||
widget = screen;
|
widget = screen;
|
||||||
history.emplace_back(widget);
|
history.emplace_back(widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::popScreen() {
|
void Device::PopScreen()
|
||||||
if(history.size() >= 2) {
|
{
|
||||||
|
if (history.size() >= 2)
|
||||||
|
{
|
||||||
history.pop_back();
|
history.pop_back();
|
||||||
widget = history.back();
|
widget = history.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::pushKey(const SDL_Keycode key) {
|
void Device::PushKey(const SDL_Keycode key)
|
||||||
|
{
|
||||||
SDL_Event ev;
|
SDL_Event ev;
|
||||||
ev.type = SDL_EVENT_KEY_DOWN;
|
ev.type = SDL_EVENT_KEY_DOWN;
|
||||||
ev.key.key = key;
|
ev.key.key = key;
|
||||||
SDL_PushEvent(&ev);
|
SDL_PushEvent(&ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::render_u8g2() const {
|
void Device::RenderU8G2() const
|
||||||
SDL_Surface* u8g2_surface = nullptr;
|
{
|
||||||
SDL_Texture* u8g2_texture = nullptr;
|
SDL_Surface *u8g2_surface = nullptr;
|
||||||
|
SDL_Texture *u8g2_texture = nullptr;
|
||||||
|
|
||||||
u8g2_surface =
|
u8g2_surface = SDL_CreateSurface(U8G2_SCREEN_WIDTH, U8G2_SCREEN_HEIGHT, SDL_PIXELFORMAT_RGBA8888);
|
||||||
SDL_CreateSurface(U8G2_SCREEN_WIDTH, U8G2_SCREEN_HEIGHT, SDL_PIXELFORMAT_RGBA8888);
|
|
||||||
|
|
||||||
if(!u8g2_surface) {
|
if (!u8g2_surface)
|
||||||
|
{
|
||||||
SDL_Log("SDL_CreateSurfaceFrom Error: %s\n", SDL_GetError());
|
SDL_Log("SDL_CreateSurfaceFrom Error: %s\n", SDL_GetError());
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
const auto color_black = SDL_MapSurfaceRGBA(u8g2_surface, 0, 0, 0, 255);
|
const auto color_black = SDL_MapSurfaceRGBA(u8g2_surface, 0, 0, 0, 255);
|
||||||
const auto color_white = SDL_MapSurfaceRGBA(u8g2_surface, 255, 255, 255, 255);
|
const auto color_white = SDL_MapSurfaceRGBA(u8g2_surface, 255, 255, 255, 255);
|
||||||
|
|
||||||
if(!SDL_LockSurface(u8g2_surface)) {
|
const auto u8g2_buf = u8g2_GetBufferPtr(&u8g2);
|
||||||
SDL_Log("SDL_LockSurface Error: %s\n", SDL_GetError());
|
for (auto y = 0; y < U8G2_SCREEN_HEIGHT; ++y)
|
||||||
} else {
|
{
|
||||||
const auto u8g2_buf = u8g2_GetBufferPtr(&u8g2);
|
for (auto x = 0; x < U8G2_SCREEN_WIDTH; ++x)
|
||||||
for(auto y = 0; y < U8G2_SCREEN_HEIGHT; ++y) {
|
{
|
||||||
for(auto x = 0; x < U8G2_SCREEN_WIDTH; ++x) {
|
const auto page = y / 8;
|
||||||
const auto page = y / 8;
|
const auto bit_index = y % 8;
|
||||||
const auto bit_index = y % 8;
|
const auto byte_ptr = u8g2_buf + page * U8G2_SCREEN_WIDTH + x;
|
||||||
const auto byte_ptr = u8g2_buf + page * U8G2_SCREEN_WIDTH + x;
|
const auto pixel_is_set = (*byte_ptr >> bit_index) & 0x01;
|
||||||
const auto pixel_is_set = (*byte_ptr >> bit_index) & 0x01;
|
set_pixel_rgba(u8g2_surface, x, y, pixel_is_set ? color_white : color_black);
|
||||||
set_pixel_rgba(u8g2_surface, x, y, pixel_is_set ? color_white : color_black);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SDL_UnlockSurface(u8g2_surface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8g2_texture = SDL_CreateTextureFromSurface(get_context()->renderer(), u8g2_surface);
|
u8g2_texture = SDL_CreateTextureFromSurface(GetContext()->MainRenderer(), u8g2_surface);
|
||||||
if(!u8g2_texture) {
|
if (!u8g2_texture)
|
||||||
|
{
|
||||||
SDL_Log("SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError());
|
SDL_Log("SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError());
|
||||||
}
|
}
|
||||||
if(!SDL_SetTextureScaleMode(u8g2_texture, SDL_SCALEMODE_NEAREST)) {
|
if (!SDL_SetTextureScaleMode(u8g2_texture, SDL_SCALEMODE_NEAREST))
|
||||||
|
{
|
||||||
SDL_Log("SDL_SetTextureScaleMode Error: %s\n", SDL_GetError());
|
SDL_Log("SDL_SetTextureScaleMode Error: %s\n", SDL_GetError());
|
||||||
}
|
}
|
||||||
SDL_DestroySurface(u8g2_surface);
|
SDL_DestroySurface(u8g2_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(u8g2_texture) {
|
if (u8g2_texture)
|
||||||
|
{
|
||||||
SDL_FRect destRect;
|
SDL_FRect destRect;
|
||||||
destRect.x = U8G2_SCREEN_PADDING;
|
destRect.x = U8G2_SCREEN_PADDING;
|
||||||
destRect.y = U8G2_SCREEN_PADDING;
|
destRect.y = U8G2_SCREEN_PADDING;
|
||||||
destRect.w = U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR;
|
destRect.w = U8G2_SCREEN_WIDTH * U8G2_SCREEN_FACTOR;
|
||||||
destRect.h = U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR;
|
destRect.h = U8G2_SCREEN_HEIGHT * U8G2_SCREEN_FACTOR;
|
||||||
|
|
||||||
SDL_RenderTexture(get_context()->renderer(), u8g2_texture, nullptr, &destRect);
|
SDL_RenderTexture(GetContext()->MainRenderer(), u8g2_texture, nullptr, &destRect);
|
||||||
|
SDL_DestroyTexture(u8g2_texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::draw_background() const {
|
void Device::DrawBackground() const
|
||||||
|
{
|
||||||
int windowWidth = 0;
|
int windowWidth = 0;
|
||||||
int windowHeight = 0;
|
int windowHeight = 0;
|
||||||
|
|
||||||
if(!SDL_GetWindowSize(get_context()->window(), &windowWidth, &windowHeight)) {
|
if (!SDL_GetWindowSize(GetContext()->MainWindow(), &windowWidth, &windowHeight))
|
||||||
|
{
|
||||||
SDL_Log("SDL_GetWindowSize Error: %s\n", SDL_GetError());
|
SDL_Log("SDL_GetWindowSize Error: %s\n", SDL_GetError());
|
||||||
}
|
}
|
||||||
const auto rect =
|
const auto rect = SDL_FRect{0.0f, 0.0f, static_cast<float>(windowWidth), static_cast<float>(windowHeight)};
|
||||||
SDL_FRect{0.0f, 0.0f, static_cast<float>(windowWidth), static_cast<float>(windowHeight)};
|
SDL_SetRenderDrawColor(GetContext()->MainRenderer(), 193, 46, 31, 255);
|
||||||
SDL_SetRenderDrawColor(get_context()->renderer(), 193, 46, 31, 255);
|
SDL_RenderFillRect(GetContext()->MainRenderer(), &rect);
|
||||||
SDL_RenderFillRect(get_context()->renderer(), &rect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::draw_screen() const {
|
void Device::DrawScreen() const
|
||||||
|
{
|
||||||
u8g2_ClearBuffer(&u8g2);
|
u8g2_ClearBuffer(&u8g2);
|
||||||
|
|
||||||
if(widget != nullptr) {
|
if (widget != nullptr)
|
||||||
|
{
|
||||||
widget->update(SDL_GetTicks());
|
widget->update(SDL_GetTicks());
|
||||||
widget->render();
|
widget->render();
|
||||||
}
|
}
|
||||||
|
|
||||||
render_u8g2();
|
RenderU8G2();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::draw_text() const {
|
void Device::Render() const
|
||||||
constexpr auto color = SDL_Color({0, 255, 200});
|
{
|
||||||
const auto surface =
|
DrawBackground();
|
||||||
TTF_RenderText_Blended(get_context()->m_font_default, "HelloWorld SDL3 TTF", 0, color);
|
DrawScreen();
|
||||||
const auto texture = SDL_CreateTextureFromSurface(get_context()->renderer(), surface);
|
|
||||||
SDL_DestroySurface(surface);
|
|
||||||
const SDL_FRect dstRect{
|
|
||||||
500, 100, static_cast<float>(texture->w), static_cast<float>(texture->h)};
|
|
||||||
SDL_RenderTexture(get_context()->renderer(), texture, nullptr, &dstRect);
|
|
||||||
SDL_DestroyTexture(texture); // ? Is this safe to do here ?
|
|
||||||
}
|
|
||||||
|
|
||||||
void Device::render() const {
|
for (const auto &child : m_children)
|
||||||
draw_background();
|
{
|
||||||
draw_screen();
|
child->Render();
|
||||||
// draw_text();
|
|
||||||
|
|
||||||
for(const auto& child : m_children) {
|
|
||||||
child->render();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::hit_test(SDL_MouseMotionEvent* event) const {
|
void Device::HandleTap(const SDL_MouseButtonEvent *event) const
|
||||||
SDL_Log("x: %f", event->x);
|
{
|
||||||
|
// SDL_Log("HandleTap: x=%f, y=%f, button=%d", event->x, event->y, event->button);
|
||||||
|
|
||||||
|
for (const auto &child : m_children)
|
||||||
|
{
|
||||||
|
if (child->IsHit(static_cast<int>(event->x), static_cast<int>(event->y)))
|
||||||
|
{
|
||||||
|
child->OnTap(static_cast<int>(event->x), static_cast<int>(event->y));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::onButtonClicked(const uint8_t button) const {
|
void Device::ReleaseTap(const SDL_MouseButtonEvent *event) const
|
||||||
if(widget != nullptr) {
|
{
|
||||||
|
// SDL_Log("ReleaseTap: x=%f, y=%f, button=%d", event->x, event->y, event->button);
|
||||||
|
|
||||||
|
for (const auto &child : m_children)
|
||||||
|
{
|
||||||
|
if (child->IsHit(static_cast<int>(event->x), static_cast<int>(event->y)))
|
||||||
|
{
|
||||||
|
child->ReleaseTap(static_cast<int>(event->x), static_cast<int>(event->y));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Device::OnButtonClicked(const uint8_t button) const
|
||||||
|
{
|
||||||
|
if (widget != nullptr)
|
||||||
|
{
|
||||||
widget->onButtonClicked(button);
|
widget->onButtonClicked(button);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Device::IsHit(int mouse_x, int mouse_y) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::OnTap(int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
////
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::ReleaseTap(int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
///
|
||||||
|
}
|
@@ -5,38 +5,44 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "UIWidget.h"
|
#include "UIWidget.h"
|
||||||
#include "model/AppContext.h"
|
|
||||||
#include "common/Widget.h"
|
#include "common/Widget.h"
|
||||||
|
#include "model/AppContext.h"
|
||||||
|
|
||||||
class Device final : public UIWidget {
|
class Device final : public UIWidget
|
||||||
public:
|
{
|
||||||
explicit Device(void* appstate);
|
public:
|
||||||
|
explicit Device(void *appstate);
|
||||||
|
|
||||||
void render() const override;
|
void Render() const override;
|
||||||
|
|
||||||
void hit_test(SDL_MouseMotionEvent* event) const;
|
void HandleTap(const SDL_MouseButtonEvent *event) const;
|
||||||
|
|
||||||
void onButtonClicked(uint8_t button) const;
|
void ReleaseTap(const SDL_MouseButtonEvent *event) const;
|
||||||
|
|
||||||
private:
|
void OnButtonClicked(uint8_t button) const;
|
||||||
void draw_background() const;
|
|
||||||
|
|
||||||
void draw_screen() const;
|
[[nodiscard]] bool IsHit(int mouse_x, int mouse_y) const override;
|
||||||
|
|
||||||
void draw_text() const;
|
void OnTap(int mouse_x, int mouse_y) override;
|
||||||
|
|
||||||
void render_u8g2() const;
|
void ReleaseTap(int mouse_x, int mouse_y) override;
|
||||||
|
|
||||||
void setScreen(const std::shared_ptr<Widget>& screen);
|
private:
|
||||||
|
void DrawBackground() const;
|
||||||
|
|
||||||
void pushScreen(const std::shared_ptr<Widget>& screen);
|
void DrawScreen() const;
|
||||||
|
|
||||||
void popScreen();
|
void RenderU8G2() const;
|
||||||
|
|
||||||
static void pushKey(SDL_Keycode key);
|
void SetScreen(const std::shared_ptr<Widget> &screen);
|
||||||
|
|
||||||
|
void PushScreen(const std::shared_ptr<Widget> &screen);
|
||||||
|
|
||||||
|
void PopScreen();
|
||||||
|
|
||||||
|
static void PushKey(SDL_Keycode key);
|
||||||
|
|
||||||
std::vector<std::shared_ptr<UIWidget>> m_children{};
|
std::vector<std::shared_ptr<UIWidget>> m_children{};
|
||||||
|
|
||||||
std::shared_ptr<Widget> widget;
|
std::shared_ptr<Widget> widget;
|
||||||
std::vector<std::shared_ptr<Widget>> history;
|
std::vector<std::shared_ptr<Widget>> history;
|
||||||
};
|
};
|
||||||
|
@@ -1,22 +1,30 @@
|
|||||||
#include "ui/Matrix.h"
|
#include "ui/Matrix.h"
|
||||||
|
|
||||||
Matrix::Matrix(Window *window): m_window(window) {
|
Matrix::Matrix(Window *window) : m_window(window)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Window *Matrix::window() const {
|
Window *Matrix::window() const
|
||||||
|
{
|
||||||
return m_window;
|
return m_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Matrix::draw_colored_grid(const int rows, const int cols, const float cellSize, const float spacing) const {
|
void Matrix::DrawColoredGrid(const int rows, const int cols, const float cellSize, const float spacing) const
|
||||||
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (int w = 0; w < cols; w++) {
|
for (int w = 0; w < cols; w++)
|
||||||
|
{
|
||||||
const auto phase = w % (2 * rows);
|
const auto phase = w % (2 * rows);
|
||||||
|
|
||||||
for (int h_raw = 0; h_raw < rows; h_raw++) {
|
for (int h_raw = 0; h_raw < rows; h_raw++)
|
||||||
|
{
|
||||||
int h;
|
int h;
|
||||||
if (phase < rows) {
|
if (phase < rows)
|
||||||
|
{
|
||||||
h = h_raw;
|
h = h_raw;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
h = rows - 1 - h_raw;
|
h = rows - 1 - h_raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,11 +45,12 @@ void Matrix::draw_colored_grid(const int rows, const int cols, const float cellS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Matrix::render() const {
|
void Matrix::Render() const
|
||||||
|
{
|
||||||
SDL_SetRenderDrawColor(m_window->renderer(), 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(m_window->renderer(), 0, 0, 0, 255);
|
||||||
SDL_RenderClear(m_window->renderer());
|
SDL_RenderClear(m_window->renderer());
|
||||||
|
|
||||||
draw_colored_grid(8, 32, 50.0f, 1.0f);
|
DrawColoredGrid(8, 32, 50.0f, 1.0f);
|
||||||
|
|
||||||
SDL_RenderPresent(m_window->renderer());
|
SDL_RenderPresent(m_window->renderer());
|
||||||
}
|
}
|
||||||
|
@@ -2,16 +2,17 @@
|
|||||||
|
|
||||||
#include "model/Window.h"
|
#include "model/Window.h"
|
||||||
|
|
||||||
class Matrix {
|
class Matrix
|
||||||
public:
|
{
|
||||||
explicit Matrix(Window* window);
|
public:
|
||||||
|
explicit Matrix(Window *window);
|
||||||
|
|
||||||
[[nodiscard]] Window* window() const;
|
[[nodiscard]] Window *window() const;
|
||||||
|
|
||||||
void render() const;
|
void Render() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void draw_colored_grid(int rows, int cols, float cellSize, float spacing) const;
|
void DrawColoredGrid(int rows, int cols, float cellSize, float spacing) const;
|
||||||
|
|
||||||
Window* m_window;
|
Window *m_window;
|
||||||
};
|
};
|
||||||
|
@@ -1,10 +1,12 @@
|
|||||||
#include "ui/UIWidget.h"
|
#include "ui/UIWidget.h"
|
||||||
|
|
||||||
UIWidget::UIWidget(void *appstate): m_context(static_cast<AppContext *>(appstate)) {
|
UIWidget::UIWidget(void *appstate) : m_context(static_cast<AppContext *>(appstate))
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
UIWidget::~UIWidget() = default;
|
UIWidget::~UIWidget() = default;
|
||||||
|
|
||||||
auto UIWidget::get_context() const -> AppContext* {
|
auto UIWidget::GetContext() const -> AppContext *
|
||||||
|
{
|
||||||
return m_context;
|
return m_context;
|
||||||
}
|
}
|
||||||
|
@@ -2,15 +2,22 @@
|
|||||||
|
|
||||||
#include "model/AppContext.h"
|
#include "model/AppContext.h"
|
||||||
|
|
||||||
class UIWidget {
|
class UIWidget
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
explicit UIWidget(void *appstate);
|
explicit UIWidget(void *appstate);
|
||||||
|
|
||||||
virtual ~UIWidget();
|
virtual ~UIWidget();
|
||||||
|
|
||||||
virtual void render() const = 0;
|
virtual void Render() const = 0;
|
||||||
|
|
||||||
[[nodiscard]] AppContext *get_context() const;
|
[[nodiscard]] virtual bool IsHit(int mouse_x, int mouse_y) const = 0;
|
||||||
|
|
||||||
|
virtual void OnTap(int mouse_x, int mouse_y) = 0;
|
||||||
|
|
||||||
|
virtual void ReleaseTap(int mouse_x, int mouse_y) = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] AppContext *GetContext() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AppContext *m_context{};
|
AppContext *m_context{};
|
||||||
|
@@ -1,34 +1,49 @@
|
|||||||
#include "ui/widgets/Button.h"
|
#include "ui/widgets/Button.h"
|
||||||
|
|
||||||
|
#include "ResourceManager.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <SDL3_image/SDL_image.h>
|
|
||||||
#include "ResourceManager.h"
|
|
||||||
|
|
||||||
auto pressed = false;
|
auto pressed = false;
|
||||||
|
|
||||||
Button::Button(
|
Button::Button(void *appState, const float x, const float y, const float width, std::function<void()> callback)
|
||||||
void* appState,
|
: UIWidget(appState), m_x(x), m_y(y), m_width(width), m_callback(std::move(callback))
|
||||||
const float x,
|
{
|
||||||
const float y,
|
|
||||||
const float width,
|
|
||||||
std::function<void()> callback)
|
|
||||||
: UIWidget(appState)
|
|
||||||
, m_x(x)
|
|
||||||
, m_y(y)
|
|
||||||
, m_width(width)
|
|
||||||
, m_callback(std::move(callback)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Button::render() const {
|
void Button::Render() const
|
||||||
const auto button = ResourceManager::getInstance().get_texture(
|
{
|
||||||
get_context()->renderer(), "assets/button_normal.png");
|
const auto button =
|
||||||
const auto overlay = ResourceManager::getInstance().get_texture(
|
ResourceManager::Instance().GetTextureByName(GetContext()->MainRenderer(), "button_normal.png");
|
||||||
get_context()->renderer(), "assets/button_pressed_overlay.png");
|
const auto overlay =
|
||||||
|
ResourceManager::Instance().GetTextureByName(GetContext()->MainRenderer(), "button_pressed_overlay.png");
|
||||||
|
|
||||||
const auto dst = SDL_FRect(m_x, m_y, m_width, m_width);
|
const auto dst = SDL_FRect(m_x, m_y, m_width, m_width);
|
||||||
SDL_RenderTexture(get_context()->renderer(), button, nullptr, &dst);
|
SDL_RenderTexture(GetContext()->MainRenderer(), button, nullptr, &dst);
|
||||||
if(pressed) {
|
if (m_isPressed)
|
||||||
SDL_RenderTexture(get_context()->renderer(), overlay, nullptr, &dst);
|
{
|
||||||
|
SDL_RenderTexture(GetContext()->MainRenderer(), overlay, nullptr, &dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Button::IsHit(const int mouse_x, const int mouse_y) const
|
||||||
|
{
|
||||||
|
const auto fx = static_cast<float>(mouse_x);
|
||||||
|
const auto fy = static_cast<float>(mouse_y);
|
||||||
|
return (fx >= m_x && fx <= (m_x + m_width) &&
|
||||||
|
fy >= m_y && fy <= (m_y + m_width)) || m_isPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::OnTap(int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
if (m_callback)
|
||||||
|
{
|
||||||
|
m_isPressed = true;
|
||||||
|
m_callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::ReleaseTap(int mouse_x, int mouse_y)
|
||||||
|
{
|
||||||
|
m_isPressed = false;
|
||||||
|
}
|
@@ -6,15 +6,23 @@
|
|||||||
|
|
||||||
#define BUTTON_WIDTH (35)
|
#define BUTTON_WIDTH (35)
|
||||||
|
|
||||||
class Button final : public UIWidget {
|
class Button final : public UIWidget
|
||||||
public:
|
{
|
||||||
Button(void* appState, float x, float y, float width, std::function<void()> callback);
|
public:
|
||||||
|
Button(void *appState, float x, float y, float width, std::function<void()> callback);
|
||||||
|
|
||||||
void render() const override;
|
void Render() const override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsHit(int mouse_x, int mouse_y) const override;
|
||||||
|
|
||||||
|
void OnTap(int mouse_x, int mouse_y) override;
|
||||||
|
|
||||||
|
void ReleaseTap(int mouse_x, int mouse_y) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float m_x;
|
float m_x;
|
||||||
float m_y;
|
float m_y;
|
||||||
float m_width;
|
float m_width;
|
||||||
std::function<void()> m_callback;
|
std::function<void()> m_callback;
|
||||||
|
bool m_isPressed = false;
|
||||||
};
|
};
|
||||||
|
@@ -1,24 +1,82 @@
|
|||||||
|
#include "D_Pad.h"
|
||||||
#include "ui/widgets/D_Pad.h"
|
#include "ui/widgets/D_Pad.h"
|
||||||
|
|
||||||
#include "ResourceManager.h"
|
#include "ResourceManager.h"
|
||||||
|
|
||||||
D_Pad::D_Pad(
|
D_Pad::D_Pad(void *appState, const float x, const float y, const float width, std::function<void(Direction)> callback)
|
||||||
void* appState,
|
: UIWidget(appState), m_x(x), m_y(y), m_width(width), m_callback(std::move(callback))
|
||||||
const float x,
|
{
|
||||||
const float y,
|
|
||||||
const float width,
|
|
||||||
std::function<void(int)> callback)
|
|
||||||
: UIWidget(appState)
|
|
||||||
, m_x(x)
|
|
||||||
, m_y(y)
|
|
||||||
, m_width(width)
|
|
||||||
, m_callback(std::move(callback)) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void D_Pad::render() const {
|
void D_Pad::Render() const
|
||||||
const auto dPad = ResourceManager::getInstance().get_texture(
|
{
|
||||||
get_context()->renderer(), "assets/d-pad_normal.png");
|
const auto dPad =
|
||||||
|
ResourceManager::Instance().GetTextureByName(GetContext()->MainRenderer(), "d-pad_normal.png");
|
||||||
|
|
||||||
const auto dst = SDL_FRect(m_x, m_y, m_width, m_width);
|
const auto dst = SDL_FRect(m_x, m_y, m_width, m_width);
|
||||||
SDL_RenderTexture(get_context()->renderer(), dPad, nullptr, &dst);
|
SDL_RenderTexture(GetContext()->MainRenderer(), dPad, nullptr, &dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool D_Pad::IsHit(const int mouse_x, const int mouse_y) const
|
||||||
|
{
|
||||||
|
const auto fx = static_cast<float>(mouse_x);
|
||||||
|
const auto fy = static_cast<float>(mouse_y);
|
||||||
|
return (fx >= m_x && fx <= (m_x + m_width) &&
|
||||||
|
fy >= m_y && fy <= (m_y + m_width));
|
||||||
|
}
|
||||||
|
|
||||||
|
D_Pad::Direction D_Pad::GetDirectionFromTap(const float local_x, const float local_y) const
|
||||||
|
{
|
||||||
|
const float segment = m_width / 3.0f;
|
||||||
|
|
||||||
|
int col = -1;
|
||||||
|
if (local_x < segment)
|
||||||
|
col = 0;
|
||||||
|
else if (local_x < 2 * segment)
|
||||||
|
col = 1;
|
||||||
|
else if (local_x <= m_width)
|
||||||
|
col = 2;
|
||||||
|
else
|
||||||
|
return Direction::NONE;
|
||||||
|
|
||||||
|
int row = -1;
|
||||||
|
if (local_y < segment)
|
||||||
|
row = 0;
|
||||||
|
else if (local_y < 2 * segment)
|
||||||
|
row = 1;
|
||||||
|
else if (local_y <= m_width)
|
||||||
|
row = 2;
|
||||||
|
else
|
||||||
|
return Direction::NONE;
|
||||||
|
|
||||||
|
if (col == 1 && row == 0)
|
||||||
|
return Direction::UP;
|
||||||
|
if (col == 1 && row == 2)
|
||||||
|
return Direction::DOWN;
|
||||||
|
if (col == 0 && row == 1)
|
||||||
|
return Direction::LEFT;
|
||||||
|
if (col == 2 && row == 1)
|
||||||
|
return Direction::RIGHT;
|
||||||
|
|
||||||
|
return Direction::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void D_Pad::OnTap(const int mouse_x, const int mouse_y)
|
||||||
|
{
|
||||||
|
if (m_callback)
|
||||||
|
{
|
||||||
|
const auto local_x = static_cast<float>(mouse_x) - m_x;
|
||||||
|
const auto local_y = static_cast<float>(mouse_y) - m_y;
|
||||||
|
|
||||||
|
if (local_x >= 0 && local_x <= m_width && local_y >= 0 && local_y <= m_width)
|
||||||
|
{
|
||||||
|
const auto dir = GetDirectionFromTap(local_x, local_y);
|
||||||
|
m_callback(dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void D_Pad::ReleaseTap(const int mouse_x, const int mouse_y)
|
||||||
|
{
|
||||||
|
///
|
||||||
|
}
|
@@ -5,15 +5,25 @@
|
|||||||
|
|
||||||
#define DPAD_WIDTH (105)
|
#define DPAD_WIDTH (105)
|
||||||
|
|
||||||
class D_Pad final : public UIWidget {
|
|
||||||
public:
|
|
||||||
D_Pad(void* appState, float x, float y, float width, std::function<void(int)> callback);
|
|
||||||
|
|
||||||
void render() const override;
|
class D_Pad final : public UIWidget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Direction { NONE, UP, DOWN, LEFT, RIGHT };
|
||||||
|
|
||||||
|
D_Pad(void *appState, float x, float y, float width, std::function<void(Direction)> callback);
|
||||||
|
|
||||||
|
void Render() const override;
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsHit(int mouse_x, int mouse_y) const override;
|
||||||
|
|
||||||
|
void OnTap(int mouse_x, int mouse_y) override;
|
||||||
|
|
||||||
|
void ReleaseTap(int mouse_x, int mouse_y) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float m_x;
|
float m_x, m_y, m_width;
|
||||||
float m_y;
|
std::function<void(Direction)> m_callback;
|
||||||
float m_width;
|
|
||||||
std::function<void(int)> m_callback;
|
[[nodiscard]] Direction GetDirectionFromTap(float local_x, float local_y) const;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user