v1.0 (#1)
* init rework * Update LICENSE * removing tests * adding Gui Component system * added spdlog library * Fixed input restriction bug * nothing * Making the default button stand out * Setting up run Component * changing components * restarted because i cant do it visualising sorting through value/step diagrams * g * working (kinda) * fixed sqrt comp error * added debug flag * abbandoning Lua... Error in runtime * fixing errors, making cuts * removing unnessecary dependencies * Improving UI
This commit is contained in:
parent
96e6514337
commit
a89b27d456
36 changed files with 1665 additions and 1228 deletions
269
CMakeLists.txt
269
CMakeLists.txt
|
@ -5,8 +5,8 @@
|
||||||
cmake_minimum_required(VERSION 3.22)
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
project(sortiva
|
project(sortiva
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
VERSION 1.0.0
|
VERSION 1.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
@ -18,7 +18,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Enforce C++20 standard
|
||||||
set(CMAKE_CXX_EXTENSIONS OFF) # Disable compiler-specific extensions
|
set(CMAKE_CXX_EXTENSIONS OFF) # Disable compiler-specific extensions
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Generate compile commands (useful for IDEs)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Generate compile commands (useful for IDEs)
|
||||||
set(USE_FOLDERS ON) # Organize targets into folders (for IDEs)
|
set(USE_FOLDERS ON) # Organize targets into folders (for IDEs)
|
||||||
set(BUILD_SHARED_LIBS OFF) # Build static libraries by default
|
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE) # Build static libraries by default
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
# Helper Functions:
|
# Helper Functions:
|
||||||
|
@ -30,35 +30,35 @@ set(BUILD_SHARED_LIBS OFF) # Build static libraries by default
|
||||||
# It then sets the folder property for the target.
|
# It then sets the folder property for the target.
|
||||||
|
|
||||||
function(put_targets_into_folder)
|
function(put_targets_into_folder)
|
||||||
set(oneValueArgs FOLDER)
|
set(oneValueArgs FOLDER)
|
||||||
set(multiValueArgs TARGETS)
|
set(multiValueArgs TARGETS)
|
||||||
cmake_parse_arguments(ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
cmake_parse_arguments(ARGS "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||||
|
|
||||||
foreach(target ${ARGS_TARGETS})
|
foreach(target ${ARGS_TARGETS})
|
||||||
# Check if target exists
|
# Check if target exists
|
||||||
if (NOT TARGET ${target})
|
if (NOT TARGET ${target})
|
||||||
message(FATAL_ERROR "${target} target not found")
|
message(FATAL_ERROR "${target} target not found")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Get the actual target (if it is aliased)
|
# Get the actual target (if it is aliased)
|
||||||
get_target_property(actual_target ${target} ALIASED_TARGET)
|
get_target_property(actual_target ${target} ALIASED_TARGET)
|
||||||
if (NOT actual_target)
|
if (NOT actual_target)
|
||||||
set(actual_target ${target})
|
set(actual_target ${target})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Set the folder property for the target
|
# Set the folder property for the target
|
||||||
set_target_properties(${actual_target} PROPERTIES FOLDER ${ARGS_FOLDER})
|
set_target_properties(${actual_target} PROPERTIES FOLDER ${ARGS_FOLDER})
|
||||||
endforeach()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
|
||||||
function(find_files var_name path)
|
function(find_files var_name path)
|
||||||
set(sources)
|
set(sources)
|
||||||
foreach(ext ${ARGN})
|
foreach(ext ${ARGN})
|
||||||
file(GLOB_RECURSE files "${path}/*.${ext}")
|
file(GLOB_RECURSE files "${path}/*.${ext}")
|
||||||
list(APPEND sources ${files})
|
list(APPEND sources ${files})
|
||||||
endforeach()
|
endforeach()
|
||||||
set(${var_name} ${${var_name}} ${sources} PARENT_SCOPE)
|
set(${var_name} ${${var_name}} ${sources} PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
@ -74,33 +74,27 @@ set(FETCHCONTENT_QUIET OFF) # Display download progress
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Generate compile_commands.json
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Generate compile_commands.json
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
# Options
|
# External Dependencies (currently not needed)
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
|
||||||
option(SVA_BUILD_TEST ON) # Option for test to be build as well
|
# # --- Add Sol2 (Lua C++ Binding Library)
|
||||||
|
# FetchContent_Declare(
|
||||||
# ========================================================
|
# sol2
|
||||||
# External Dependencies
|
# GIT_REPOSITORY https://github.com/ThePhD/sol2.git
|
||||||
# ========================================================
|
# GIT_TAG v3.3.0
|
||||||
|
# )
|
||||||
# --- Add Sol2 (Lua C++ Binding Library)
|
# FetchContent_MakeAvailable(sol2)
|
||||||
FetchContent_Declare(
|
#
|
||||||
sol2
|
# # --- Add Lua
|
||||||
GIT_REPOSITORY https://github.com/ThePhD/sol2.git
|
# FetchContent_Declare(
|
||||||
GIT_TAG v3.3.0
|
# lua
|
||||||
)
|
# GIT_REPOSITORY "https://github.com/marovira/lua"
|
||||||
FetchContent_MakeAvailable(sol2)
|
# GIT_TAG "5.4.4"
|
||||||
|
# )
|
||||||
# --- Add Lua
|
# FetchContent_MakeAvailable(lua)
|
||||||
FetchContent_Declare(
|
#
|
||||||
lua
|
# set(LUA_BUILD_INTERPRETER ON CACHE BOOL "Build the Lua interpreter" FORCE)
|
||||||
GIT_REPOSITORY "https://github.com/marovira/lua"
|
# set(SOL2_ENABLE_INSTALL OFF CACHE BOOL "" FORCE)
|
||||||
GIT_TAG "5.4.4"
|
|
||||||
)
|
|
||||||
|
|
||||||
FetchContent_MakeAvailable(lua)
|
|
||||||
|
|
||||||
set(LUA_BUILD_INTERPRETER ON CACHE BOOL "Build the Lua interpreter" FORCE)
|
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
# Helper Function: Set Common Target Properties
|
# Helper Function: Set Common Target Properties
|
||||||
|
@ -109,155 +103,96 @@ set(LUA_BUILD_INTERPRETER ON CACHE BOOL "Build the Lua interpreter" FORCE)
|
||||||
# that are shared among all targets.
|
# that are shared among all targets.
|
||||||
|
|
||||||
function(set_common_properties target)
|
function(set_common_properties target)
|
||||||
target_link_libraries(${target} PRIVATE sol2::sol2) # Link with Sol2
|
#target_link_libraries(${target} PRIVATE sol2::sol2) # Link with Sol2
|
||||||
target_compile_definitions(${target} PRIVATE SOL_ALL_SAFETIES_ON=1)
|
#target_compile_definitions(${target} PRIVATE SOL_ALL_SAFETIES_ON=1)
|
||||||
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) # Include project headers
|
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include) # Include project headers
|
||||||
target_sources(${target} PRIVATE ${SVA_COMMON_FILES}) # Include common files
|
#target_sources(${target} PRIVATE ${SVA_COMMON_FILES}) # Include common files
|
||||||
target_link_libraries(${target} PRIVATE lua::lua)
|
#target_link_libraries(${target} PRIVATE lua::lua)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# ========================================================
|
# ========================================================
|
||||||
# GUI Setup
|
# Executable
|
||||||
# ========================================================
|
# ========================================================
|
||||||
|
|
||||||
set(GUI_TARGET_NAME "${PROJECT_NAME}")
|
set(GUI_TARGET_NAME "${PROJECT_NAME}")
|
||||||
# --- Create GUI Executable
|
# --- Create GUI Executable
|
||||||
find_files(SVA_GUI_FILES "./src/" hpp cpp h c hxx cxx)
|
find_files(SVA_GUI_FILES "./src/" hpp cpp h c hxx cxx)
|
||||||
add_executable(${GUI_TARGET_NAME}
|
add_executable(${GUI_TARGET_NAME}
|
||||||
${SVA_GUI_FILES}
|
${SVA_GUI_FILES}
|
||||||
)
|
)
|
||||||
|
target_compile_definitions(${GUI_TARGET_NAME} PUBLIC "$<$<CONFIG:DEBUG>:_DEBUG>")
|
||||||
|
source_group(TREE ${PROJECT_SOURCE_DIR}/src/ PREFIX "Source" FILES ${SVA_GUI_FILES})
|
||||||
|
|
||||||
# ---------------
|
# ---------------
|
||||||
# RAYLIB
|
# RAYLIB
|
||||||
# ---------------
|
# ---------------
|
||||||
# Dependencies
|
# Dependencies
|
||||||
set(RAYLIB_VERSION 5.0)
|
set(RAYLIB_VERSION 5.5)
|
||||||
find_package(raylib ${RAYLIB_VERSION} QUIET) # QUIET or REQUIRED
|
find_package(raylib ${RAYLIB_VERSION} QUIET) # QUIET or REQUIRED
|
||||||
|
|
||||||
if (NOT raylib_FOUND) # If there's none, fetch and build raylib
|
if (NOT raylib_FOUND) # If there's none, fetch and build raylib
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
raylib
|
raylib
|
||||||
DOWNLOAD_EXTRACT_TIMESTAMP OFF
|
DOWNLOAD_EXTRACT_TIMESTAMP OFF
|
||||||
URL https://github.com/raysan5/raylib/archive/refs/tags/${RAYLIB_VERSION}.tar.gz
|
URL https://github.com/raysan5/raylib/archive/refs/tags/${RAYLIB_VERSION}.tar.gz
|
||||||
)
|
)
|
||||||
FetchContent_GetProperties(raylib)
|
FetchContent_GetProperties(raylib)
|
||||||
if (NOT raylib_POPULATED) # Have we downloaded raylib yet?
|
if (NOT raylib_POPULATED) # Have we downloaded raylib yet?
|
||||||
set(FETCHCONTENT_QUIET NO)
|
set(FETCHCONTENT_QUIET NO)
|
||||||
FetchContent_MakeAvailable(raylib)
|
FetchContent_MakeAvailable(raylib)
|
||||||
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples
|
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
put_targets_into_folder(FOLDER "raylib" TARGETS raylib uninstall)
|
|
||||||
|
|
||||||
target_link_libraries(${GUI_TARGET_NAME} PRIVATE raylib)
|
target_link_libraries(${GUI_TARGET_NAME} PRIVATE raylib)
|
||||||
|
|
||||||
# Checks if OSX and links appropriate frameworks (Only required on MacOS)
|
# Checks if OSX and links appropriate frameworks (Only required on MacOS)
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
target_link_libraries(${PROJECT_NAME} "-framework IOKit")
|
target_link_libraries(${PROJECT_NAME} "-framework IOKit")
|
||||||
target_link_libraries(${PROJECT_NAME} "-framework Cocoa")
|
target_link_libraries(${PROJECT_NAME} "-framework Cocoa")
|
||||||
target_link_libraries(${PROJECT_NAME} "-framework OpenGL")
|
target_link_libraries(${PROJECT_NAME} "-framework OpenGL")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# -------------------------------
|
|
||||||
# SFML (Not used anymore)
|
|
||||||
# -------------------------------
|
|
||||||
#
|
|
||||||
# --- Add SFML (Simple and Fast Multimedia Library)
|
|
||||||
# FetchContent_Declare(SFML
|
|
||||||
# GIT_REPOSITORY https://github.com/SFML/SFML.git
|
|
||||||
# GIT_TAG 2.6.x
|
|
||||||
# GIT_SHALLOW ON
|
|
||||||
# EXCLUDE_FROM_ALL
|
|
||||||
# SYSTEM
|
|
||||||
# )
|
|
||||||
# FetchContent_MakeAvailable(SFML)
|
|
||||||
#
|
|
||||||
# target_link_libraries(${GUI_TARGET_NAME} PRIVATE sfml-graphics) # Link SFML graphics library
|
|
||||||
#
|
|
||||||
# --- Special handling for Windows: Copy OpenAL DLL (for sound support)
|
|
||||||
# if(WIN32)
|
|
||||||
# add_custom_command(
|
|
||||||
# TARGET ${GUI_TARGET_NAME}
|
|
||||||
# COMMENT "Copy OpenAL DLL"
|
|
||||||
# PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy ${SFML_SOURCE_DIR}/extlibs/bin/$<IF:$<EQUAL:${CMAKE_SIZEOF_VOID_P},8>,x64,x86>/openal32.dll $<TARGET_FILE_DIR:${GUI_TARGET_NAME}>
|
|
||||||
# VERBATIM
|
|
||||||
# )
|
|
||||||
# endif()
|
|
||||||
# // SFML is not used anymore
|
|
||||||
|
|
||||||
set_common_properties(${GUI_TARGET_NAME})
|
set_common_properties(${GUI_TARGET_NAME})
|
||||||
|
|
||||||
|
|
||||||
# ========================================================
|
|
||||||
# Test Setup (Only if SVA_BUILD_TEST is ON)
|
|
||||||
# ========================================================
|
|
||||||
|
|
||||||
if(${SVA_BUILD_TEST})
|
|
||||||
# --- Add Google Test
|
put_targets_into_folder(
|
||||||
FetchContent_Declare(
|
FOLDER "ThirdParty/raylib"
|
||||||
googletest
|
TARGETS
|
||||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
raylib uninstall
|
||||||
GIT_TAG release-1.12.1
|
)
|
||||||
)
|
|
||||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Prevent shared CRT issues on Windows
|
#put_targets_into_folder(
|
||||||
FetchContent_MakeAvailable(googletest)
|
# FOLDER "ThirdParty/lua"
|
||||||
|
# TARGETS
|
||||||
# Enable testing support
|
# lua lua_lib
|
||||||
enable_testing()
|
#)
|
||||||
|
|
||||||
# --- Create Test Executable
|
put_targets_into_folder(
|
||||||
set(TEST_TARGET_NAME "${GUI_TARGET_NAME}_test")
|
FOLDER "ThirdParty/glfw"
|
||||||
add_executable(
|
TARGETS
|
||||||
${TEST_TARGET_NAME}
|
glfw update_mappings
|
||||||
tests/test_main.cpp # Test entry point
|
)
|
||||||
tests/test_sorting_functions.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(
|
|
||||||
${TEST_TARGET_NAME}
|
|
||||||
PRIVATE GTest::gtest_main # Link Google Test framework
|
|
||||||
)
|
|
||||||
set_common_properties(${TEST_TARGET_NAME})
|
|
||||||
|
|
||||||
# --- Enable Google Test's test discovery feature
|
|
||||||
include(GoogleTest)
|
|
||||||
gtest_discover_tests(${TEST_TARGET_NAME})
|
|
||||||
|
|
||||||
# put google test targets into a folder
|
|
||||||
put_targets_into_folder(
|
|
||||||
FOLDER "gtest"
|
|
||||||
TARGETS
|
|
||||||
GTest::gtest_main
|
|
||||||
GTest::gmock_main
|
|
||||||
GTest::gmock
|
|
||||||
GTest::gtest
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Option to create an includes target
|
# Option to create an includes target
|
||||||
set(SVA_CREATE_INCLUDES_TARGET ON CACHE BOOL "Create an includes target")
|
set(SVA_CREATE_INCLUDES_TARGET ON CACHE BOOL "Create an includes target")
|
||||||
|
|
||||||
if(${SVA_CREATE_INCLUDES_TARGET})
|
if(${SVA_CREATE_INCLUDES_TARGET})
|
||||||
set(INCLUDES_TARGET_NAME "${GUI_TARGET_NAME}_includes")
|
set(INCLUDES_TARGET_NAME "includes")
|
||||||
set(INCLUDE_FILES)
|
set(INCLUDE_FILES)
|
||||||
find_files(
|
find_files(
|
||||||
INCLUDE_FILES
|
INCLUDE_FILES
|
||||||
"include/"
|
"include/"
|
||||||
hpp h hxx
|
hpp h hxx
|
||||||
)
|
)
|
||||||
message(STATUS "Include files: ${INCLUDE_FILES}")
|
message(STATUS "Include files: ${INCLUDE_FILES}")
|
||||||
add_custom_target(${INCLUDES_TARGET_NAME}
|
add_custom_target(${INCLUDES_TARGET_NAME}
|
||||||
SOURCES
|
SOURCES
|
||||||
${INCLUDE_FILES}
|
${INCLUDE_FILES}
|
||||||
)
|
)
|
||||||
set_target_properties(${INCLUDES_TARGET_NAME} PROPERTIES FOLDER "sva")
|
source_group(TREE ${PROJECT_SOURCE_DIR}/include/ PREFIX "Source" FILES ${INCLUDE_FILES})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
put_targets_into_folder(
|
|
||||||
FOLDER "sva"
|
|
||||||
TARGETS
|
|
||||||
${GUI_TARGET_NAME}
|
|
||||||
${TEST_TARGET_NAME}
|
|
||||||
)
|
|
||||||
|
|
214
LICENSE
214
LICENSE
|
@ -1,201 +1,21 @@
|
||||||
Apache License
|
MIT License
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
Copyright (c) 2024 Jann Hoffmann
|
||||||
|
|
||||||
1. Definitions.
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
The above copyright notice and this permission notice shall be included in all
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
the copyright owner that is granting the License.
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
other entities that control, are controlled by, or are under common
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
control with that entity. For the purposes of this definition,
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
SOFTWARE.
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [yyyy] [name of copyright owner]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
|
|
|
@ -1,106 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <chrono>
|
|
||||||
#include <iostream>
|
|
||||||
#include <optional>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
struct timer_result
|
|
||||||
{
|
|
||||||
double seconds = 0;
|
|
||||||
double difftime = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Timer {
|
|
||||||
enum State : u8
|
|
||||||
{
|
|
||||||
running = 0,
|
|
||||||
paused = 1
|
|
||||||
};
|
|
||||||
State state = paused;
|
|
||||||
|
|
||||||
std::clock_t begin;
|
|
||||||
std::clock_t elapsed = 0;
|
|
||||||
std::optional<std::ostream*> out;
|
|
||||||
std::optional<timer_result*> result;
|
|
||||||
|
|
||||||
Timer() : begin(std::clock()) {}
|
|
||||||
Timer(std::ostream& o) : begin(std::clock()), out(&o) {}
|
|
||||||
Timer(timer_result& r) : begin(std::clock()), result(&r) {}
|
|
||||||
Timer(std::ostream& o, timer_result& r) : begin(std::clock()), out(&o), result(&r) {}
|
|
||||||
Timer(State initial_state) : state(initial_state), begin(std::clock())
|
|
||||||
{
|
|
||||||
if (state == paused)
|
|
||||||
begin = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer(std::ostream& o, State initial_state) : state(initial_state), begin(std::clock()), out(&o)
|
|
||||||
{
|
|
||||||
if (state == paused)
|
|
||||||
begin = 0;
|
|
||||||
}
|
|
||||||
Timer(timer_result& r, State initial_state) : state(initial_state), begin(std::clock()), result(&r)
|
|
||||||
{
|
|
||||||
if (state == paused)
|
|
||||||
begin = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer(std::ostream& o, timer_result& r, State initial_state) : state(initial_state), begin(std::clock()), out(&o), result(&r)
|
|
||||||
{
|
|
||||||
if (state == paused)
|
|
||||||
begin = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset(State init_state) {
|
|
||||||
if (state == paused)
|
|
||||||
begin = 0;
|
|
||||||
else
|
|
||||||
begin = std::clock();
|
|
||||||
elapsed = 0;
|
|
||||||
state = init_state;
|
|
||||||
lap();
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_state(State new_state)
|
|
||||||
{
|
|
||||||
if (this->state == new_state)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (new_state == running)
|
|
||||||
{
|
|
||||||
begin = std::clock();
|
|
||||||
}
|
|
||||||
else // pausing
|
|
||||||
{
|
|
||||||
assert(begin != 0);
|
|
||||||
elapsed += std::clock() - begin;
|
|
||||||
begin = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
lap();
|
|
||||||
this->state = new_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
void lap()
|
|
||||||
{
|
|
||||||
std::clock_t total_time = elapsed;
|
|
||||||
if (state == running)
|
|
||||||
{
|
|
||||||
total_time += std::clock() - begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
result.value()->seconds = static_cast<double>(total_time) / CLOCKS_PER_SEC;
|
|
||||||
result.value()->difftime = static_cast<double>(total_time) / CLOCKS_PER_SEC;
|
|
||||||
}
|
|
||||||
if (out)
|
|
||||||
{
|
|
||||||
*out.value() << static_cast<double>(total_time) / CLOCKS_PER_SEC << " seconds.\n";
|
|
||||||
*out.value() << "Total time = " << static_cast<double>(total_time) / CLOCKS_PER_SEC << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
~Timer() {
|
|
||||||
lap();
|
|
||||||
}
|
|
||||||
};
|
|
25
include/TickSystem.hpp
Normal file
25
include/TickSystem.hpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#pragma once
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class TickSystem {
|
||||||
|
private:
|
||||||
|
std::chrono::duration<float> timer{ 0 };
|
||||||
|
std::chrono::duration<float> tickRate;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TickSystem(std::chrono::duration<float> tickRateSeconds)
|
||||||
|
: tickRate(tickRateSeconds) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update(std::chrono::duration<float> deltaTime) {
|
||||||
|
timer += deltaTime;
|
||||||
|
|
||||||
|
if (timer >= tickRate) {
|
||||||
|
timer -= tickRate;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
137
include/collections.hpp
Normal file
137
include/collections.hpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class tree
|
||||||
|
{
|
||||||
|
size_t m_CountBranches = 0;
|
||||||
|
tree<T>* branches = nullptr;
|
||||||
|
public:
|
||||||
|
T value;
|
||||||
|
|
||||||
|
tree() = default;
|
||||||
|
|
||||||
|
~tree()
|
||||||
|
{
|
||||||
|
delete[] branches;
|
||||||
|
m_CountBranches = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const tree& rhs) const
|
||||||
|
{
|
||||||
|
return branches == rhs.branches;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
explicit tree(Args&&... args) : value(std::forward<Args>(args)...) {}
|
||||||
|
|
||||||
|
tree<T>& get(size_t idx)
|
||||||
|
{
|
||||||
|
if (m_CountBranches <= idx || !branches) throw std::out_of_range("Index is out of range!");
|
||||||
|
return branches[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(size_t idx, const tree<T>* t)
|
||||||
|
{
|
||||||
|
if (m_CountBranches >= idx || !t || !branches) throw std::out_of_range("Index is out of range!");
|
||||||
|
branches[idx] = *t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(const tree<T>* t)
|
||||||
|
{
|
||||||
|
tree<T>* tmp = new tree<T>[m_CountBranches + 1];
|
||||||
|
if (branches) {
|
||||||
|
memcpy(tmp, branches, sizeof(tree<T>) * m_CountBranches);
|
||||||
|
delete[] branches;
|
||||||
|
}
|
||||||
|
branches = tmp;
|
||||||
|
tmp[m_CountBranches++] = *t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(size_t idx, const T& val)
|
||||||
|
{
|
||||||
|
if (m_CountBranches >= idx || !branches) throw std::out_of_range("Index is out of range!");
|
||||||
|
branches[idx].value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ...Args>
|
||||||
|
void add(Args&& ...args)
|
||||||
|
{
|
||||||
|
tree<T>* tmp = new tree<T>[m_CountBranches + 1];
|
||||||
|
if (branches) {
|
||||||
|
memcpy(tmp, branches, sizeof(tree<T>) * m_CountBranches);
|
||||||
|
delete[] branches;
|
||||||
|
}
|
||||||
|
branches = tmp;
|
||||||
|
tmp[m_CountBranches++] = tree(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t depth()
|
||||||
|
{
|
||||||
|
if (branches) return 1;
|
||||||
|
size_t res = 0;
|
||||||
|
for (int i = 0; i < m_CountBranches; ++i)
|
||||||
|
{
|
||||||
|
res = max(res, branches[i].depth());
|
||||||
|
}
|
||||||
|
return res + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t width() const
|
||||||
|
{
|
||||||
|
return m_CountBranches;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree<T>& operator[](size_t idx)
|
||||||
|
{
|
||||||
|
return get(idx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct linked_list
|
||||||
|
{
|
||||||
|
linked_list<T>* next = nullptr;
|
||||||
|
linked_list<T>* first = nullptr;
|
||||||
|
T value;
|
||||||
|
|
||||||
|
linked_list() = default;
|
||||||
|
linked_list(T val) : value(val) {}
|
||||||
|
~linked_list()
|
||||||
|
{
|
||||||
|
delete next;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const linked_list& rhs) const
|
||||||
|
{
|
||||||
|
return
|
||||||
|
this->first == rhs.first &&
|
||||||
|
this->next == rhs.next &&
|
||||||
|
this->value == rhs.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
linked_list& put(const T& val)
|
||||||
|
{
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
next = new linked_list<T>(val);
|
||||||
|
if (first)
|
||||||
|
next->first = first;
|
||||||
|
else
|
||||||
|
next->first = this;
|
||||||
|
return *next;
|
||||||
|
}
|
||||||
|
if (first)
|
||||||
|
next->first = first;
|
||||||
|
else
|
||||||
|
next->first = this;
|
||||||
|
return next->put(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t depth()
|
||||||
|
{
|
||||||
|
if (!next) return 1;
|
||||||
|
return next->depth() + 1;
|
||||||
|
}
|
||||||
|
};
|
626
include/raylibs/modules/gui_window_file_dialog.hpp
Normal file
626
include/raylibs/modules/gui_window_file_dialog.hpp
Normal file
|
@ -0,0 +1,626 @@
|
||||||
|
#pragma once
|
||||||
|
/*******************************************************************************************
|
||||||
|
*
|
||||||
|
* Window File Dialog v1.2 - Modal file dialog to open/save files
|
||||||
|
*
|
||||||
|
* MODULE USAGE:
|
||||||
|
* #define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION
|
||||||
|
* #include "gui_window_file_dialog.h"
|
||||||
|
*
|
||||||
|
* INIT: GuiWindowFileDialogState state = GuiInitWindowFileDialog();
|
||||||
|
* DRAW: GuiWindowFileDialog(&state);
|
||||||
|
*
|
||||||
|
* NOTE: This module depends on some raylib file system functions:
|
||||||
|
* - LoadDirectoryFiles()
|
||||||
|
* - UnloadDirectoryFiles()
|
||||||
|
* - GetWorkingDirectory()
|
||||||
|
* - DirectoryExists()
|
||||||
|
* - FileExists()
|
||||||
|
*
|
||||||
|
* LICENSE: zlib/libpng
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019-2024 Ramon Santamaria (@raysan5)
|
||||||
|
*
|
||||||
|
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||||
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, including commercial
|
||||||
|
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||||
|
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||||
|
* in the product documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||||
|
* as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*
|
||||||
|
**********************************************************************************************/
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
#ifndef GUI_WINDOW_FILE_DIALOG_H
|
||||||
|
#define GUI_WINDOW_FILE_DIALOG_H
|
||||||
|
|
||||||
|
// Gui file dialog context data
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
// Window management variables
|
||||||
|
bool windowActive;
|
||||||
|
Rectangle windowBounds;
|
||||||
|
Vector2 panOffset;
|
||||||
|
bool dragMode;
|
||||||
|
bool supportDrag;
|
||||||
|
|
||||||
|
// UI variables
|
||||||
|
bool dirPathEditMode;
|
||||||
|
char dirPathText[1024];
|
||||||
|
|
||||||
|
int filesListScrollIndex;
|
||||||
|
bool filesListEditMode;
|
||||||
|
int filesListActive;
|
||||||
|
|
||||||
|
bool fileNameEditMode;
|
||||||
|
char fileNameText[1024];
|
||||||
|
bool SelectFilePressed;
|
||||||
|
bool CancelFilePressed;
|
||||||
|
int fileTypeActive;
|
||||||
|
int itemFocused;
|
||||||
|
|
||||||
|
// Custom state variables
|
||||||
|
FilePathList dirFiles;
|
||||||
|
char filterExt[256];
|
||||||
|
char dirPathTextCopy[1024];
|
||||||
|
char fileNameTextCopy[1024];
|
||||||
|
|
||||||
|
int prevFilesListActive;
|
||||||
|
|
||||||
|
bool saveFileMode;
|
||||||
|
|
||||||
|
} GuiWindowFileDialogState;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" { // Prevents name mangling of functions
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Defines and Macros
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
//...
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Types and Structures Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// ...
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Global Variables Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
//...
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Module Functions Declaration
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
GuiWindowFileDialogState InitGuiWindowFileDialog(const char* initPath);
|
||||||
|
void GuiWindowFileDialog(GuiWindowFileDialogState* state);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // GUI_WINDOW_FILE_DIALOG_H
|
||||||
|
|
||||||
|
/***********************************************************************************
|
||||||
|
*
|
||||||
|
* GUI_WINDOW_FILE_DIALOG IMPLEMENTATION
|
||||||
|
*
|
||||||
|
************************************************************************************/
|
||||||
|
#if defined(GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION)
|
||||||
|
|
||||||
|
#include <raylibs/raygui.h>
|
||||||
|
|
||||||
|
#include <string.h> // Required for: strcpy()
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Defines and Macros
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
#define MAX_DIRECTORY_FILES 2048
|
||||||
|
#define MAX_ICON_PATH_LENGTH 512
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PATH_SEPERATOR "\\"
|
||||||
|
#else
|
||||||
|
#define PATH_SEPERATOR "/"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Types and Structures Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
|
||||||
|
// Detailed file info type
|
||||||
|
typedef struct FileInfo {
|
||||||
|
const char* name;
|
||||||
|
int size;
|
||||||
|
int modTime;
|
||||||
|
int type;
|
||||||
|
int icon;
|
||||||
|
} FileInfo;
|
||||||
|
#else
|
||||||
|
// Filename only
|
||||||
|
typedef char* FileInfo; // Files are just a path string
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Global Variables Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
FileInfo* dirFilesIcon = NULL; // Path string + icon (for fancy drawing)
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Internal Module Functions Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Read files in new path
|
||||||
|
static void ReloadDirectoryFiles(GuiWindowFileDialogState* state);
|
||||||
|
|
||||||
|
#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
|
||||||
|
// List View control for files info with extended parameters
|
||||||
|
static int GuiListViewFiles(Rectangle bounds, FileInfo* files, int count, int* focus, int* scrollIndex, int active);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
// Module Functions Definition
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
GuiWindowFileDialogState InitGuiWindowFileDialog(const char* initPath)
|
||||||
|
{
|
||||||
|
GuiWindowFileDialogState state = { 0 };
|
||||||
|
|
||||||
|
// Init window data
|
||||||
|
state.windowBounds = { static_cast<float>(GetScreenWidth()) / 2 - 440 / 2, static_cast<float>(GetScreenHeight()) / 2 - 310 / 2, 440, 310 };
|
||||||
|
state.windowActive = false;
|
||||||
|
state.supportDrag = true;
|
||||||
|
state.dragMode = false;
|
||||||
|
state.panOffset = { 0, 0 };
|
||||||
|
|
||||||
|
// Init path data
|
||||||
|
state.dirPathEditMode = false;
|
||||||
|
state.filesListActive = -1;
|
||||||
|
state.prevFilesListActive = state.filesListActive;
|
||||||
|
state.filesListScrollIndex = 0;
|
||||||
|
|
||||||
|
state.fileNameEditMode = false;
|
||||||
|
|
||||||
|
state.SelectFilePressed = false;
|
||||||
|
state.CancelFilePressed = false;
|
||||||
|
|
||||||
|
state.fileTypeActive = 0;
|
||||||
|
|
||||||
|
strcpy(state.fileNameText, "\0");
|
||||||
|
|
||||||
|
// Custom variables initialization
|
||||||
|
if (initPath && DirectoryExists(initPath))
|
||||||
|
{
|
||||||
|
strcpy(state.dirPathText, initPath);
|
||||||
|
}
|
||||||
|
else if (initPath && FileExists(initPath))
|
||||||
|
{
|
||||||
|
strcpy(state.dirPathText, GetDirectoryPath(initPath));
|
||||||
|
strcpy(state.fileNameText, GetFileName(initPath));
|
||||||
|
}
|
||||||
|
else strcpy(state.dirPathText, GetWorkingDirectory());
|
||||||
|
|
||||||
|
// TODO: Why we keep a copy?
|
||||||
|
strcpy(state.dirPathTextCopy, state.dirPathText);
|
||||||
|
strcpy(state.fileNameTextCopy, state.fileNameText);
|
||||||
|
|
||||||
|
state.filterExt[0] = '\0';
|
||||||
|
//strcpy(state.filterExt, "all");
|
||||||
|
|
||||||
|
state.dirFiles.count = 0;
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update and draw file dialog
|
||||||
|
void GuiWindowFileDialog(GuiWindowFileDialogState* state)
|
||||||
|
{
|
||||||
|
if (state->windowActive)
|
||||||
|
{
|
||||||
|
// Update window dragging
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
if (state->supportDrag)
|
||||||
|
{
|
||||||
|
Vector2 mousePosition = GetMousePosition();
|
||||||
|
|
||||||
|
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON))
|
||||||
|
{
|
||||||
|
// Window can be dragged from the top window bar
|
||||||
|
if (CheckCollisionPointRec(mousePosition, { state->windowBounds.x, state->windowBounds.y, (float)state->windowBounds.width, RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }))
|
||||||
|
{
|
||||||
|
state->dragMode = true;
|
||||||
|
state->panOffset.x = mousePosition.x - state->windowBounds.x;
|
||||||
|
state->panOffset.y = mousePosition.y - state->windowBounds.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->dragMode)
|
||||||
|
{
|
||||||
|
state->windowBounds.x = (mousePosition.x - state->panOffset.x);
|
||||||
|
state->windowBounds.y = (mousePosition.y - state->panOffset.y);
|
||||||
|
|
||||||
|
// Check screen limits to avoid moving out of screen
|
||||||
|
if (state->windowBounds.x < 0) state->windowBounds.x = 0;
|
||||||
|
else if (state->windowBounds.x > (GetScreenWidth() - state->windowBounds.width)) state->windowBounds.x = GetScreenWidth() - state->windowBounds.width;
|
||||||
|
|
||||||
|
if (state->windowBounds.y < 0) state->windowBounds.y = 0;
|
||||||
|
else if (state->windowBounds.y > (GetScreenHeight() - state->windowBounds.height)) state->windowBounds.y = GetScreenHeight() - state->windowBounds.height;
|
||||||
|
|
||||||
|
if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) state->dragMode = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Load dirFilesIcon and state->dirFiles lazily on windows open
|
||||||
|
// NOTE: They are automatically unloaded at fileDialog closing
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
if (dirFilesIcon == NULL)
|
||||||
|
{
|
||||||
|
dirFilesIcon = (FileInfo*)RL_CALLOC(MAX_DIRECTORY_FILES, sizeof(FileInfo)); // Max files to read
|
||||||
|
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) dirFilesIcon[i] = (char*)RL_CALLOC(MAX_ICON_PATH_LENGTH, 1); // Max file name length
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load current directory files
|
||||||
|
if (state->dirFiles.paths == NULL) ReloadDirectoryFiles(state);
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Draw window and controls
|
||||||
|
//----------------------------------------------------------------------------------------
|
||||||
|
state->windowActive = !GuiWindowBox(state->windowBounds, "#198# Select File Dialog");
|
||||||
|
|
||||||
|
// Draw previous directory button + logic
|
||||||
|
if (GuiButton({ state->windowBounds.x + state->windowBounds.width - 48, state->windowBounds.y + 24 + 12, 40, 24 }, "< .."))
|
||||||
|
{
|
||||||
|
// Move dir path one level up
|
||||||
|
strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
|
||||||
|
|
||||||
|
// Reload directory files (frees previous list)
|
||||||
|
ReloadDirectoryFiles(state);
|
||||||
|
|
||||||
|
state->filesListActive = -1;
|
||||||
|
memset(state->fileNameText, 0, 1024);
|
||||||
|
memset(state->fileNameTextCopy, 0, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw current directory text box info + path editing logic
|
||||||
|
if (GuiTextBox({ state->windowBounds.x + 8, state->windowBounds.y + 24 + 12, state->windowBounds.width - 48 - 16, 24 }, state->dirPathText, 1024, state->dirPathEditMode))
|
||||||
|
{
|
||||||
|
if (state->dirPathEditMode)
|
||||||
|
{
|
||||||
|
// Verify if a valid path has been introduced
|
||||||
|
if (DirectoryExists(state->dirPathText))
|
||||||
|
{
|
||||||
|
// Reload directory files (frees previous list)
|
||||||
|
ReloadDirectoryFiles(state);
|
||||||
|
|
||||||
|
strcpy(state->dirPathTextCopy, state->dirPathText);
|
||||||
|
}
|
||||||
|
else strcpy(state->dirPathText, state->dirPathTextCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->dirPathEditMode = !state->dirPathEditMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// List view elements are aligned left
|
||||||
|
int prevTextAlignment = GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT);
|
||||||
|
int prevElementsHeight = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
|
||||||
|
GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT);
|
||||||
|
GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 24);
|
||||||
|
# if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
|
||||||
|
state->filesListActive = GuiListViewFiles({ state->position.x + 8, state->position.y + 48 + 20, state->windowBounds.width - 16, state->windowBounds.height - 60 - 16 - 68 }, fileInfo, state->dirFiles.count, &state->itemFocused, &state->filesListScrollIndex, state->filesListActive);
|
||||||
|
# else
|
||||||
|
GuiListViewEx({ state->windowBounds.x + 8, state->windowBounds.y + 48 + 20, state->windowBounds.width - 16, state->windowBounds.height - 60 - 16 - 68 },
|
||||||
|
(const char**)dirFilesIcon, state->dirFiles.count, &state->filesListScrollIndex, &state->filesListActive, &state->itemFocused);
|
||||||
|
# endif
|
||||||
|
GuiSetStyle(LISTVIEW, TEXT_ALIGNMENT, prevTextAlignment);
|
||||||
|
GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, prevElementsHeight);
|
||||||
|
|
||||||
|
// Check if a path has been selected, if it is a directory, move to that directory (and reload paths)
|
||||||
|
if ((state->filesListActive >= 0) && (state->filesListActive != state->prevFilesListActive))
|
||||||
|
//&& (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsKeyPressed(KEY_ENTER) || IsKeyPressed(KEY_DPAD_A)))
|
||||||
|
{
|
||||||
|
strcpy(state->fileNameText, GetFileName(state->dirFiles.paths[state->filesListActive]));
|
||||||
|
|
||||||
|
if (DirectoryExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText)))
|
||||||
|
{
|
||||||
|
if (TextIsEqual(state->fileNameText, "..")) strcpy(state->dirPathText, GetPrevDirectoryPath(state->dirPathText));
|
||||||
|
else strcpy(state->dirPathText, TextFormat("%s/%s", (strcmp(state->dirPathText, "/") == 0) ? "" : state->dirPathText, state->fileNameText));
|
||||||
|
|
||||||
|
strcpy(state->dirPathTextCopy, state->dirPathText);
|
||||||
|
|
||||||
|
// Reload directory files (frees previous list)
|
||||||
|
ReloadDirectoryFiles(state);
|
||||||
|
|
||||||
|
strcpy(state->dirPathTextCopy, state->dirPathText);
|
||||||
|
|
||||||
|
state->filesListActive = -1;
|
||||||
|
strcpy(state->fileNameText, "\0");
|
||||||
|
strcpy(state->fileNameTextCopy, state->fileNameText);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->prevFilesListActive = state->filesListActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw bottom controls
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
GuiLabel({ state->windowBounds.x + 8, state->windowBounds.y + state->windowBounds.height - 68, 60, 24 }, "File name:");
|
||||||
|
if (GuiTextBox({ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 68, state->windowBounds.width - 184, 24 }, state->fileNameText, 128, state->fileNameEditMode))
|
||||||
|
{
|
||||||
|
if (*state->fileNameText)
|
||||||
|
{
|
||||||
|
// Verify if a valid filename has been introduced
|
||||||
|
if (FileExists(TextFormat("%s/%s", state->dirPathText, state->fileNameText)))
|
||||||
|
{
|
||||||
|
// Select filename from list view
|
||||||
|
for (int i = 0; i < state->dirFiles.count; i++)
|
||||||
|
{
|
||||||
|
if (TextIsEqual(state->fileNameText, state->dirFiles.paths[i]))
|
||||||
|
{
|
||||||
|
state->filesListActive = i;
|
||||||
|
strcpy(state->fileNameTextCopy, state->fileNameText);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!state->saveFileMode)
|
||||||
|
{
|
||||||
|
strcpy(state->fileNameText, state->fileNameTextCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
state->fileNameEditMode = !state->fileNameEditMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
GuiLabel({ state->windowBounds.x + 8, state->windowBounds.y + state->windowBounds.height - 24 - 12, 68, 24 }, "File filter:");
|
||||||
|
GuiComboBox({ state->windowBounds.x + 72, state->windowBounds.y + state->windowBounds.height - 24 - 12, state->windowBounds.width - 184, 24 }, "All files", &state->fileTypeActive);
|
||||||
|
|
||||||
|
state->SelectFilePressed = GuiButton({ state->windowBounds.x + state->windowBounds.width - 96 - 8, state->windowBounds.y + state->windowBounds.height - 68, 96, 24 }, "Select");
|
||||||
|
|
||||||
|
if (GuiButton({ state->windowBounds.x + state->windowBounds.width - 96 - 8, state->windowBounds.y + state->windowBounds.height - 24 - 12, 96, 24 }, "Cancel")) state->windowActive = false;
|
||||||
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Exit on file selected
|
||||||
|
if (state->SelectFilePressed) state->windowActive = false;
|
||||||
|
|
||||||
|
// File dialog has been closed, free all memory before exit
|
||||||
|
if (!state->windowActive)
|
||||||
|
{
|
||||||
|
// Free dirFilesIcon memory
|
||||||
|
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) RL_FREE(dirFilesIcon[i]);
|
||||||
|
|
||||||
|
RL_FREE(dirFilesIcon);
|
||||||
|
dirFilesIcon = NULL;
|
||||||
|
|
||||||
|
// Unload directory file paths
|
||||||
|
UnloadDirectoryFiles(state->dirFiles);
|
||||||
|
|
||||||
|
// Reset state variables
|
||||||
|
state->dirFiles.count = 0;
|
||||||
|
state->dirFiles.capacity = 0;
|
||||||
|
state->dirFiles.paths = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two files from a directory
|
||||||
|
static inline int FileCompare(const char* d1, const char* d2, const char* dir)
|
||||||
|
{
|
||||||
|
const bool b1 = DirectoryExists(TextFormat("%s/%s", dir, d1));
|
||||||
|
const bool b2 = DirectoryExists(TextFormat("%s/%s", dir, d2));
|
||||||
|
|
||||||
|
if (b1 && !b2) return -1;
|
||||||
|
if (!b1 && b2) return 1;
|
||||||
|
|
||||||
|
if (!FileExists(TextFormat("%s/%s", dir, d1))) return 1;
|
||||||
|
if (!FileExists(TextFormat("%s/%s", dir, d2))) return -1;
|
||||||
|
|
||||||
|
return strcmp(d1, d2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read files in new path
|
||||||
|
static void ReloadDirectoryFiles(GuiWindowFileDialogState* state)
|
||||||
|
{
|
||||||
|
UnloadDirectoryFiles(state->dirFiles);
|
||||||
|
|
||||||
|
state->dirFiles = LoadDirectoryFilesEx(state->dirPathText, (state->filterExt[0] == '\0') ? NULL : state->filterExt, false);
|
||||||
|
state->itemFocused = 0;
|
||||||
|
|
||||||
|
// Reset dirFilesIcon memory
|
||||||
|
for (int i = 0; i < MAX_DIRECTORY_FILES; i++) memset(dirFilesIcon[i], 0, MAX_ICON_PATH_LENGTH);
|
||||||
|
|
||||||
|
// Copy paths as icon + fileNames into dirFilesIcon
|
||||||
|
for (int i = 0; i < state->dirFiles.count; i++)
|
||||||
|
{
|
||||||
|
if (IsPathFile(state->dirFiles.paths[i]))
|
||||||
|
{
|
||||||
|
// Path is a file, a file icon for convenience (for some recognized extensions)
|
||||||
|
if (IsFileExtension(state->dirFiles.paths[i], ".png;.bmp;.tga;.gif;.jpg;.jpeg;.psd;.hdr;.qoi;.dds;.pkm;.ktx;.pvr;.astc"))
|
||||||
|
{
|
||||||
|
strcpy(dirFilesIcon[i], TextFormat("#12#%s", GetFileName(state->dirFiles.paths[i])));
|
||||||
|
}
|
||||||
|
else if (IsFileExtension(state->dirFiles.paths[i], ".wav;.mp3;.ogg;.flac;.xm;.mod;.it;.wma;.aiff"))
|
||||||
|
{
|
||||||
|
strcpy(dirFilesIcon[i], TextFormat("#11#%s", GetFileName(state->dirFiles.paths[i])));
|
||||||
|
}
|
||||||
|
else if (IsFileExtension(state->dirFiles.paths[i], ".txt;.info;.md;.nfo;.xml;.json;.c;.cpp;.cs;.lua;.py;.glsl;.vs;.fs"))
|
||||||
|
{
|
||||||
|
strcpy(dirFilesIcon[i], TextFormat("#10#%s", GetFileName(state->dirFiles.paths[i])));
|
||||||
|
}
|
||||||
|
else if (IsFileExtension(state->dirFiles.paths[i], ".exe;.bin;.raw;.msi"))
|
||||||
|
{
|
||||||
|
strcpy(dirFilesIcon[i], TextFormat("#200#%s", GetFileName(state->dirFiles.paths[i])));
|
||||||
|
}
|
||||||
|
else strcpy(dirFilesIcon[i], TextFormat("#218#%s", GetFileName(state->dirFiles.paths[i])));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Path is a directory, add a directory icon
|
||||||
|
strcpy(dirFilesIcon[i], TextFormat("#1#%s", GetFileName(state->dirFiles.paths[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(USE_CUSTOM_LISTVIEW_FILEINFO)
|
||||||
|
// List View control for files info with extended parameters
|
||||||
|
static int GuiListViewFiles(Rectangle bounds, FileInfo* files, int count, int* focus, int* scrollIndex, int* active)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
GuiState state = guiState;
|
||||||
|
int itemFocused = (focus == NULL) ? -1 : *focus;
|
||||||
|
int itemSelected = *active;
|
||||||
|
|
||||||
|
// Check if we need a scroll bar
|
||||||
|
bool useScrollBar = false;
|
||||||
|
if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING)) * count > bounds.height) useScrollBar = true;
|
||||||
|
|
||||||
|
// Define base item rectangle [0]
|
||||||
|
Rectangle itemBounds = { 0 };
|
||||||
|
itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING);
|
||||||
|
itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
|
||||||
|
itemBounds.width = bounds.width - 2 * GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) - GuiGetStyle(DEFAULT, BORDER_WIDTH);
|
||||||
|
itemBounds.height = GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT);
|
||||||
|
if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH);
|
||||||
|
|
||||||
|
// Get items on the list
|
||||||
|
int visibleItems = bounds.height / (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
|
||||||
|
if (visibleItems > count) visibleItems = count;
|
||||||
|
|
||||||
|
int startIndex = (scrollIndex == NULL) ? 0 : *scrollIndex;
|
||||||
|
if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0;
|
||||||
|
int endIndex = startIndex + visibleItems;
|
||||||
|
|
||||||
|
// Update control
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
if ((state != GUI_STATE_DISABLED) && !guiLocked)
|
||||||
|
{
|
||||||
|
Vector2 mousePoint = GetMousePosition();
|
||||||
|
|
||||||
|
// Check mouse inside list view
|
||||||
|
if (CheckCollisionPointRec(mousePoint, bounds))
|
||||||
|
{
|
||||||
|
state = GUI_STATE_FOCUSED;
|
||||||
|
|
||||||
|
// Check focused and selected item
|
||||||
|
for (int i = 0; i < visibleItems; i++)
|
||||||
|
{
|
||||||
|
if (CheckCollisionPointRec(mousePoint, itemBounds))
|
||||||
|
{
|
||||||
|
itemFocused = startIndex + i;
|
||||||
|
if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) itemSelected = startIndex + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update item rectangle y position for next item
|
||||||
|
itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useScrollBar)
|
||||||
|
{
|
||||||
|
int wheelMove = GetMouseWheelMove();
|
||||||
|
startIndex -= wheelMove;
|
||||||
|
|
||||||
|
if (startIndex < 0) startIndex = 0;
|
||||||
|
else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems;
|
||||||
|
|
||||||
|
endIndex = startIndex + visibleItems;
|
||||||
|
if (endIndex > count) endIndex = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else itemFocused = -1;
|
||||||
|
|
||||||
|
// Reset item rectangle y to [0]
|
||||||
|
itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING) + GuiGetStyle(DEFAULT, BORDER_WIDTH);
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Draw control
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
DrawRectangleRec(bounds, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background
|
||||||
|
DrawRectangleLinesEx(bounds, GuiGetStyle(DEFAULT, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER + state * 3)), guiAlpha));
|
||||||
|
|
||||||
|
// TODO: Draw list view header with file sections: icon+name | size | type | modTime
|
||||||
|
|
||||||
|
// Draw visible items
|
||||||
|
for (int i = 0; i < visibleItems; i++)
|
||||||
|
{
|
||||||
|
if (state == GUI_STATE_DISABLED)
|
||||||
|
{
|
||||||
|
if ((startIndex + i) == itemSelected)
|
||||||
|
{
|
||||||
|
DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED)), guiAlpha));
|
||||||
|
DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), guiAlpha));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Draw full file info line: icon+name | size | type | modTime
|
||||||
|
|
||||||
|
GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED)), guiAlpha));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ((startIndex + i) == itemSelected)
|
||||||
|
{
|
||||||
|
// Draw item selected
|
||||||
|
DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED)), guiAlpha));
|
||||||
|
DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), guiAlpha));
|
||||||
|
|
||||||
|
GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED)), guiAlpha));
|
||||||
|
}
|
||||||
|
else if ((startIndex + i) == itemFocused)
|
||||||
|
{
|
||||||
|
// Draw item focused
|
||||||
|
DrawRectangleRec(itemBounds, Fade(GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED)), guiAlpha));
|
||||||
|
DrawRectangleLinesEx(itemBounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), Fade(GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), guiAlpha));
|
||||||
|
|
||||||
|
GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED)), guiAlpha));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Draw item normal
|
||||||
|
GuiDrawText(files[startIndex + i].name, GetTextBounds(DEFAULT, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL)), guiAlpha));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update item rectangle y position for next item
|
||||||
|
itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_PADDING));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useScrollBar)
|
||||||
|
{
|
||||||
|
Rectangle scrollBarBounds = {
|
||||||
|
bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
|
||||||
|
bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH),
|
||||||
|
bounds.height - 2 * GuiGetStyle(DEFAULT, BORDER_WIDTH)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Calculate percentage of visible items and apply same percentage to scrollbar
|
||||||
|
float percentVisible = (float)(endIndex - startIndex) / count;
|
||||||
|
float sliderSize = bounds.height * percentVisible;
|
||||||
|
|
||||||
|
int prevSliderSize = GuiGetStyle(SCROLLBAR, SLIDER_WIDTH); // Save default slider size
|
||||||
|
int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed
|
||||||
|
GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, sliderSize); // Change slider size
|
||||||
|
GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed
|
||||||
|
|
||||||
|
startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems);
|
||||||
|
|
||||||
|
GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default
|
||||||
|
GuiSetStyle(SCROLLBAR, SLIDER_WIDTH, prevSliderSize); // Reset slider size to default
|
||||||
|
}
|
||||||
|
//--------------------------------------------------------------------
|
||||||
|
|
||||||
|
if (focus != NULL) *focus = itemFocused;
|
||||||
|
if (scrollIndex != NULL) *scrollIndex = startIndex;
|
||||||
|
|
||||||
|
*active = itemSelected;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif // USE_CUSTOM_LISTVIEW_FILEINFO
|
||||||
|
|
||||||
|
#endif // GUI_FILE_DIALOG_IMPLEMENTATION
|
80
include/raylibs/raylib-cpp.hpp
Normal file
80
include/raylibs/raylib-cpp.hpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* [raylib-cpp](https://github.com/RobLoach/raylib-cpp) is a C++ wrapper library for raylib, a simple and easy-to-use library to enjoy videogames programming. This C++ header provides object-oriented wrappers around raylib's struct interfaces.
|
||||||
|
*
|
||||||
|
* @see raylib namespace for a list of all available classes.
|
||||||
|
* @mainpage raylib-cpp
|
||||||
|
* @include core_basic_window.cpp
|
||||||
|
* @author Rob Loach (RobLoach)
|
||||||
|
* @copyright zlib/libpng
|
||||||
|
*
|
||||||
|
* raylib-cpp is licensed under an unmodified zlib/libpng license, which is an OSI-certified,
|
||||||
|
* BSD-like license that allows static linking with closed source software:
|
||||||
|
*
|
||||||
|
* Copyright 2020 Rob Loach (RobLoach)
|
||||||
|
*
|
||||||
|
* This software is provided "as-is", without any express or implied warranty. In no event
|
||||||
|
* will the authors be held liable for any damages arising from the use of this software.
|
||||||
|
*
|
||||||
|
* Permission is granted to anyone to use this software for any purpose, including commercial
|
||||||
|
* applications, and to alter it and redistribute it freely, subject to the following restrictions:
|
||||||
|
*
|
||||||
|
* 1. The origin of this software must not be misrepresented; you must not claim that you
|
||||||
|
* wrote the original software. If you use this software in a product, an acknowledgment
|
||||||
|
* in the product documentation would be appreciated but is not required.
|
||||||
|
*
|
||||||
|
* 2. Altered source versions must be plainly marked as such, and must not be misrepresented
|
||||||
|
* as being the original software.
|
||||||
|
*
|
||||||
|
* 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RAYLIB_CPP_INCLUDE_RAYLIB_CPP_HPP_
|
||||||
|
#define RAYLIB_CPP_INCLUDE_RAYLIB_CPP_HPP_
|
||||||
|
|
||||||
|
#include "./AudioDevice.hpp"
|
||||||
|
#include "./AudioStream.hpp"
|
||||||
|
#include "./AutomationEventList.hpp"
|
||||||
|
#include "./BoundingBox.hpp"
|
||||||
|
#include "./Camera2D.hpp"
|
||||||
|
#include "./Camera3D.hpp"
|
||||||
|
#include "./Color.hpp"
|
||||||
|
#include "./FileData.hpp"
|
||||||
|
#include "./FileText.hpp"
|
||||||
|
#include "./Font.hpp"
|
||||||
|
#include "./Functions.hpp"
|
||||||
|
#include "./Gamepad.hpp"
|
||||||
|
#include "./Image.hpp"
|
||||||
|
#include "./Keyboard.hpp"
|
||||||
|
#include "./Material.hpp"
|
||||||
|
#include "./Matrix.hpp"
|
||||||
|
#include "./Mesh.hpp"
|
||||||
|
#include "./Model.hpp"
|
||||||
|
#include "./ModelAnimation.hpp"
|
||||||
|
#include "./Mouse.hpp"
|
||||||
|
#include "./Music.hpp"
|
||||||
|
#include "./Ray.hpp"
|
||||||
|
#include "./RayCollision.hpp"
|
||||||
|
#include "./RaylibException.hpp"
|
||||||
|
#include "./Rectangle.hpp"
|
||||||
|
#include "./RenderTexture.hpp"
|
||||||
|
#include "./Shader.hpp"
|
||||||
|
#include "./Sound.hpp"
|
||||||
|
#include "./Text.hpp"
|
||||||
|
#include "./Texture.hpp"
|
||||||
|
#include "./TextureUnmanaged.hpp"
|
||||||
|
#include "./Touch.hpp"
|
||||||
|
#include "./Vector2.hpp"
|
||||||
|
#include "./Vector3.hpp"
|
||||||
|
#include "./Vector4.hpp"
|
||||||
|
#include "./VrStereoConfig.hpp"
|
||||||
|
#include "./Wave.hpp"
|
||||||
|
#include "./Window.hpp"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All raylib-cpp classes and functions appear in the raylib namespace.
|
||||||
|
*/
|
||||||
|
namespace raylib {
|
||||||
|
// Nothing.
|
||||||
|
} // namespace raylib
|
||||||
|
|
||||||
|
#endif // RAYLIB_CPP_INCLUDE_RAYLIB_CPP_HPP_
|
Binary file not shown.
Before Width: | Height: | Size: 5.7 KiB |
25
res/lua/bubble_sortiva.lua
Normal file
25
res/lua/bubble_sortiva.lua
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
local bubble_sort = Future:new()
|
||||||
|
|
||||||
|
function bubble_sort:poll(array)
|
||||||
|
local n = array:size()
|
||||||
|
self.state[n] = self.state[n] or n
|
||||||
|
if n == 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local swapped = false
|
||||||
|
for i = 1, n - 1 do
|
||||||
|
if array.at(i-1) > array.at(i) then
|
||||||
|
array.swap(i-1, i)
|
||||||
|
swapped = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.state.n = self.state.n - 1
|
||||||
|
|
||||||
|
return not swapped
|
||||||
|
end
|
||||||
|
|
||||||
|
function make_available(sorter_list)
|
||||||
|
table.insert(sorter_list, "bubble_sort")
|
||||||
|
end
|
59
res/lua/quick_sortiva.lua
Normal file
59
res/lua/quick_sortiva.lua
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
local quick_sort = Future:new()
|
||||||
|
|
||||||
|
function quick_sort:sort(A, lo, hi, i)
|
||||||
|
if lo >= 0 and lo < hi then
|
||||||
|
lt, gt = partition(A, lo, hi) -- Multiple return values
|
||||||
|
|
||||||
|
if #self.state["lt"] >= i and #self.state["gt"] >= i then
|
||||||
|
self:sort(A, lo, self.state["lt"][i] - 1, i+1)
|
||||||
|
self:sort(A, self.state["gt"][i] + 1, hi, i+1)
|
||||||
|
else
|
||||||
|
table.insert(self.state["lt"], lt)
|
||||||
|
table.insert(self.state["gt"], gt)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function quick_sort:poll(array)
|
||||||
|
return self:sort(array, 0, array:size(),0)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- Divides array into three partitions
|
||||||
|
function partition(A, lo, hi)
|
||||||
|
-- Pivot value
|
||||||
|
local pivot = A.at((lo + hi) / 2) -- Choose the middle element as the pivot (integer division)
|
||||||
|
|
||||||
|
-- Lesser, equal and greater index
|
||||||
|
local lt = lo
|
||||||
|
local eq = lo
|
||||||
|
local gt = hi
|
||||||
|
|
||||||
|
-- Iterate and compare all elements with the pivot
|
||||||
|
while eq <= gt do
|
||||||
|
if A[eq] < pivot then
|
||||||
|
-- Swap the elements at the equal and lesser indices
|
||||||
|
A:swap(eq, lt)
|
||||||
|
-- Increase lesser index
|
||||||
|
lt = lt + 1
|
||||||
|
-- Increase equal index
|
||||||
|
eq = eq + 1
|
||||||
|
elseif A[eq] > pivot then
|
||||||
|
-- Swap the elements at the equal and greater indices
|
||||||
|
A:swap(eq, gt)
|
||||||
|
-- Decrease greater index
|
||||||
|
gt = gt - 1
|
||||||
|
else -- if A[eq] = pivot then
|
||||||
|
-- Increase equal index
|
||||||
|
eq = eq + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Return lesser and greater indices
|
||||||
|
return lt, gt
|
||||||
|
end
|
||||||
|
|
||||||
|
function make_available(sorter_list)
|
||||||
|
table.insert(sorter_list, "quick_sort")
|
||||||
|
end
|
33
src/LuaSortList.hpp
Normal file
33
src/LuaSortList.hpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class LuaSortList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<uint16_t> list;
|
||||||
|
|
||||||
|
void swap(size_t i1, size_t i2)
|
||||||
|
{
|
||||||
|
std::swap(list[i1], list[i2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
return list.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t at(size_t i) const
|
||||||
|
{
|
||||||
|
return list[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sorted() const
|
||||||
|
{
|
||||||
|
for (int i = 1; i < list.size(); ++i)
|
||||||
|
{
|
||||||
|
if (list[i - 1] > list[i]) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -1 +0,0 @@
|
||||||
#include "Renderer.h"
|
|
|
@ -1,7 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
class Renderer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
};
|
|
|
@ -1,47 +0,0 @@
|
||||||
#include "SortingTester.h"
|
|
||||||
|
|
||||||
|
|
||||||
SortingTester::SortingTester() : list(10)
|
|
||||||
{
|
|
||||||
std::cout << "Loading lua" << std::endl;
|
|
||||||
|
|
||||||
lua.lua.open_libraries(sol::lib::coroutine, sol::lib::table);
|
|
||||||
lua.lua.new_usertype<SortingTester>("List",
|
|
||||||
"size", &SortingTester::list_size,
|
|
||||||
"swap", &SortingTester::list_swap,
|
|
||||||
"greater", &SortingTester::list_greater,
|
|
||||||
"less", &SortingTester::list_less,
|
|
||||||
"equal", &SortingTester::list_equal
|
|
||||||
);
|
|
||||||
|
|
||||||
lua.lua["list"] = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortingTester::load(const std::string& script)
|
|
||||||
{
|
|
||||||
if(lua.load(script) != safesol::LuaResultType::SUCCESS)
|
|
||||||
{
|
|
||||||
std::cerr << "Error loading file" << std::endl;
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "internal_script.hpp"
|
|
||||||
|
|
||||||
void SortingTester::load_internal()
|
|
||||||
{
|
|
||||||
if (lua.script(std_intern_sorting_script) != safesol::LuaResultType::SUCCESS)
|
|
||||||
{
|
|
||||||
std::cerr << "Error loading internal script" << std::endl;
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortingTester::populate(const populate_function& f)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < list.size(); i++)
|
|
||||||
{
|
|
||||||
f(i, list[i]);
|
|
||||||
}
|
|
||||||
std::cout << list << std::endl;
|
|
||||||
}
|
|
|
@ -1,143 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#define SVA_LIST_CALLBACKS
|
|
||||||
#include <std.hpp>
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include "lua/safesol.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
|
|
||||||
class SortingTester
|
|
||||||
{
|
|
||||||
List<u64> list;
|
|
||||||
|
|
||||||
safesol lua;
|
|
||||||
|
|
||||||
Timer timer = Timer(Timer::State::paused);
|
|
||||||
|
|
||||||
using populate_function = std::function<void(size_t, u64&)>;
|
|
||||||
|
|
||||||
template<typename ...Args>
|
|
||||||
sol::protected_function_result run_function(const sol::protected_function& function, Args&&... args)
|
|
||||||
{
|
|
||||||
timer.set_state(Timer::State::running);
|
|
||||||
sol::protected_function_result result = function(std::forward<Args>(args)...);
|
|
||||||
timer.set_state(Timer::State::paused);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool list_greater(size_t index1, size_t index2)
|
|
||||||
{
|
|
||||||
if (active_result)
|
|
||||||
++active_result->count_greater;
|
|
||||||
return list[index1] > list[index2];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool list_less(size_t index1, size_t index2)
|
|
||||||
{
|
|
||||||
if (active_result)
|
|
||||||
++active_result->count_less;
|
|
||||||
return list[index1] < list[index2];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool list_equal(size_t index1, size_t index2)
|
|
||||||
{
|
|
||||||
if (active_result)
|
|
||||||
++active_result->count_equal;
|
|
||||||
return list[index1] == list[index2];
|
|
||||||
}
|
|
||||||
|
|
||||||
void list_swap(size_t index1, size_t index2)
|
|
||||||
{
|
|
||||||
if (active_result)
|
|
||||||
++active_result->count_swaps;
|
|
||||||
// list[index1] ^= list[index2];
|
|
||||||
// list[index2] ^= list[index1];
|
|
||||||
// list[index1] ^= list[index2];
|
|
||||||
auto tmp = list[index1];
|
|
||||||
list[index1] = list[index2];
|
|
||||||
list[index2] = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t list_size() const
|
|
||||||
{
|
|
||||||
return list.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_sorted()
|
|
||||||
{
|
|
||||||
if (list.size() <= 1)
|
|
||||||
return true;
|
|
||||||
for (size_t i = 1; i < list.size(); i++)
|
|
||||||
{
|
|
||||||
if (list[i - 1] > list[i])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
struct run_result
|
|
||||||
{
|
|
||||||
timer_result timer;
|
|
||||||
// counts
|
|
||||||
u64 count_swaps = 0;
|
|
||||||
u64 count_greater = 0;
|
|
||||||
u64 count_less = 0;
|
|
||||||
u64 count_equal = 0;
|
|
||||||
// counts for comparisons
|
|
||||||
u64 count_comparisons = 0;
|
|
||||||
};
|
|
||||||
private:
|
|
||||||
run_result* active_result = nullptr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
SortingTester();
|
|
||||||
|
|
||||||
void load(const std::string& script);
|
|
||||||
void load_internal();
|
|
||||||
|
|
||||||
template<typename ...Args>
|
|
||||||
run_result run(const std::string& function_name, Args&&... args)
|
|
||||||
{
|
|
||||||
run_result result;
|
|
||||||
timer.result.emplace(&result.timer);
|
|
||||||
timer.reset(Timer::State::paused);
|
|
||||||
active_result = &result;
|
|
||||||
|
|
||||||
// Create a bound member function using std::bind
|
|
||||||
auto bound_run_function = std::bind(&SortingTester::run_function<Args...>,
|
|
||||||
this,
|
|
||||||
std::placeholders::_1,
|
|
||||||
std::forward<Args>(args)...);
|
|
||||||
|
|
||||||
safesol::LuaResultType runstate = lua.run_on_caller(function_name, bound_run_function);
|
|
||||||
|
|
||||||
if (runstate != safesol::LuaResultType::SUCCESS)
|
|
||||||
{
|
|
||||||
std::cerr << "Error running function \"" << function_name << "\": " << static_cast<u16>(runstate) << std::endl;
|
|
||||||
exit(static_cast<int>(runstate));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_sorted())
|
|
||||||
{
|
|
||||||
std::cerr << "[ERROR] The algorithm \"" << function_name << "\" did not sort the list" << std::endl;
|
|
||||||
std::cerr << list << std::endl;
|
|
||||||
std::flush(std::cerr);
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
result.count_comparisons = result.count_equal + result.count_greater + result.count_less;
|
|
||||||
|
|
||||||
active_result = nullptr;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void populate(const populate_function& f);
|
|
||||||
};
|
|
|
@ -1,60 +0,0 @@
|
||||||
#include "drawing_helper.hpp"
|
|
||||||
|
|
||||||
namespace sva
|
|
||||||
{
|
|
||||||
std::vector<std::string> split(const std::string& str, char delim)
|
|
||||||
{
|
|
||||||
std::vector<std::string> tokens;
|
|
||||||
std::string token;
|
|
||||||
std::istringstream tokenStream(str);
|
|
||||||
while (std::getline(tokenStream, token, delim))
|
|
||||||
{
|
|
||||||
tokens.push_back(token);
|
|
||||||
}
|
|
||||||
return tokens;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Color sva::GetThemeColor(GuiControlProperty property)
|
|
||||||
{
|
|
||||||
return GetColor(GuiGetStyle(DEFAULT, TEXT_COLOR_NORMAL));
|
|
||||||
}
|
|
||||||
|
|
||||||
void sva::DrawText(const std::string& text, vec2i pos, int size, Color color, TEXT_ALIGNMENT alignment)
|
|
||||||
{
|
|
||||||
switch (alignment)
|
|
||||||
{
|
|
||||||
case TEXT_ALIGN_LEFT:
|
|
||||||
return DrawText(text.c_str(), pos.x, pos.y, size, color);
|
|
||||||
case TEXT_ALIGN_RIGHT:
|
|
||||||
if (text.find('\n') != std::string::npos)
|
|
||||||
{
|
|
||||||
std::vector<std::string> lines = split(text, '\n');
|
|
||||||
for (auto& line : lines)
|
|
||||||
{
|
|
||||||
pos.x -= MeasureText(line.c_str(), size);
|
|
||||||
DrawText(line.c_str(), pos.x, pos.y, size, color);
|
|
||||||
pos.y += size;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pos.x -= MeasureText(text.c_str(), size);
|
|
||||||
return DrawText(text.c_str(), pos.x, pos.y, size, color);
|
|
||||||
|
|
||||||
case TEXT_ALIGN_CENTER:
|
|
||||||
if (text.find('\n') != std::string::npos)
|
|
||||||
{
|
|
||||||
std::vector<std::string> lines = sva::split(text, '\n');
|
|
||||||
for (auto& line : lines)
|
|
||||||
{
|
|
||||||
pos.x -= MeasureText(line.c_str(), size) / 2;
|
|
||||||
DrawText(line.c_str(), pos.x, pos.y, size, color);
|
|
||||||
pos.y += size;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pos.x -= MeasureText(text.c_str(), size) / 2;
|
|
||||||
DrawText(text.c_str(), pos.x, pos.y, size, color);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <raylib.h>
|
|
||||||
#include <raylibs/raygui.h>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
namespace sva
|
|
||||||
{
|
|
||||||
template<typename T>
|
|
||||||
struct TVector2
|
|
||||||
{
|
|
||||||
T x, y;
|
|
||||||
};
|
|
||||||
typedef TVector2<int> vec2i;
|
|
||||||
typedef TVector2<float> vec2f;
|
|
||||||
|
|
||||||
enum TEXT_ALIGNMENT
|
|
||||||
{
|
|
||||||
TEXT_ALIGN_LEFT,
|
|
||||||
TEXT_ALIGN_CENTER,
|
|
||||||
TEXT_ALIGN_RIGHT
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
Color GetThemeColor(GuiControlProperty property);
|
|
||||||
|
|
||||||
void DrawText(const std::string& text, vec2i pos, int size, Color color = GetColor(GuiGetStyle(DEFAULT, TEXT_COLOR_NORMAL)), TEXT_ALIGNMENT alignment = TEXT_ALIGN_LEFT);
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
#define RAYGUI_IMPLEMENTATION
|
|
||||||
#include <raylibs/raygui.h>
|
|
|
@ -1,42 +0,0 @@
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// //
|
|
||||||
// StyleAsCode exporter v2.0 - Style data exported as a values array //
|
|
||||||
// //
|
|
||||||
// USAGE: On init call: GuiLoadStyleDark(); //
|
|
||||||
// //
|
|
||||||
// more info and bugs-report: github.com/raysan5/raygui //
|
|
||||||
// feedback and support: ray[at]raylibtech.com //
|
|
||||||
// //
|
|
||||||
// Copyright (c) 2020-2023 raylib technologies (@raylibtech) //
|
|
||||||
// //
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
#define DARK_STYLE_PROPS_COUNT 8
|
|
||||||
|
|
||||||
// Custom style name: dark
|
|
||||||
static const GuiStyleProp darkStyleProps[DARK_STYLE_PROPS_COUNT] = {
|
|
||||||
{ 0, 0, 0x7b7b7bff }, // DEFAULT_BORDER_COLOR_NORMAL
|
|
||||||
{ 0, 1, 0x595959ff }, // DEFAULT_BASE_COLOR_NORMAL
|
|
||||||
{ 0, 2, 0xdededeff }, // DEFAULT_TEXT_COLOR_NORMAL
|
|
||||||
{ 0, 9, 0x232323ff }, // DEFAULT_BORDER_COLOR_DISABLED
|
|
||||||
{ 0, 10, 0x606060ff }, // DEFAULT_BASE_COLOR_DISABLED
|
|
||||||
{ 0, 11, 0x9f9f9fff }, // DEFAULT_TEXT_COLOR_DISABLED
|
|
||||||
{ 0, 18, 0x68cbd0ff }, // DEFAULT_LINE_COLOR
|
|
||||||
{ 0, 19, 0x262626ff }, // DEFAULT_BACKGROUND_COLOR
|
|
||||||
};
|
|
||||||
|
|
||||||
// Style loading function: dark
|
|
||||||
static void GuiLoadStyleDark(void)
|
|
||||||
{
|
|
||||||
// Load style properties provided
|
|
||||||
// NOTE: Default properties are propagated
|
|
||||||
for (int i = 0; i < DARK_STYLE_PROPS_COUNT; i++)
|
|
||||||
{
|
|
||||||
GuiSetStyle(darkStyleProps[i].controlId, darkStyleProps[i].propertyId, darkStyleProps[i].propertyValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
|
||||||
|
|
||||||
// TODO: Custom user style setup: Set specific properties here (if required)
|
|
||||||
// i.e. Controls specific BORDER_WIDTH, TEXT_PADDING, TEXT_ALIGNMENT
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
inline const char* std_intern_sorting_script = R"(
|
|
||||||
-- bubble sort
|
|
||||||
function bubble_sort()
|
|
||||||
local isSorted = false
|
|
||||||
while not isSorted do
|
|
||||||
local movedElements = 0
|
|
||||||
for x = 0, list:size() - 2 do
|
|
||||||
if list:greater(x, x+1) then
|
|
||||||
movedElements = movedElements + 1
|
|
||||||
list:swap(x, x+1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if movedElements == 0 then
|
|
||||||
isSorted = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function do_nothing()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- other functions
|
|
||||||
|
|
||||||
|
|
||||||
)";
|
|
7
src/libimpl.cpp
Normal file
7
src/libimpl.cpp
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#define RAYGUI_IMPLEMENTATION
|
||||||
|
#include <raylibs/raygui.h>
|
||||||
|
|
||||||
|
#undef RAYGUI_IMPLEMENTATION
|
||||||
|
#define GUI_WINDOW_FILE_DIALOG_IMPLEMENTATION
|
||||||
|
#define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24
|
||||||
|
#include <raylibs/modules/gui_window_file_dialog.hpp>
|
16
src/lua/Future.lua
Normal file
16
src/lua/Future.lua
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
Future = {
|
||||||
|
state = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Future:new(state)
|
||||||
|
local f = {}
|
||||||
|
setmetatable(f, self)
|
||||||
|
self.__index = self
|
||||||
|
f["state"] = state or {}
|
||||||
|
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
|
||||||
|
function Future:pull()
|
||||||
|
return true
|
||||||
|
end
|
35
src/lua/FutureLua.hpp
Normal file
35
src/lua/FutureLua.hpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
static inline const char lua_future_class[] = R"(
|
||||||
|
Future = {
|
||||||
|
state = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Future:new(state)
|
||||||
|
local f = {}
|
||||||
|
setmetatable(f, self)
|
||||||
|
self.__index = self
|
||||||
|
f["state"] = state or {}
|
||||||
|
|
||||||
|
return f
|
||||||
|
end
|
||||||
|
|
||||||
|
function Future:poll()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function Future.get(t, ...)
|
||||||
|
return t:poll(unpack(arg))
|
||||||
|
end
|
||||||
|
)";
|
||||||
|
*/
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Future
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Future() = default;
|
||||||
|
virtual bool poll() = 0;
|
||||||
|
virtual T& get() = 0;
|
||||||
|
};
|
|
@ -1,61 +0,0 @@
|
||||||
#include "safesol.h"
|
|
||||||
|
|
||||||
safesol::LuaResultType safesol::script(const std::string& script)
|
|
||||||
{
|
|
||||||
sol::load_result result = lua.load(script);
|
|
||||||
if (!result.valid()) {
|
|
||||||
sol::error err = result;
|
|
||||||
std::cout << "Error loading script: " << err.what() << std::endl;
|
|
||||||
return LuaResultType::LOAD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sol::protected_function_result script_result = result();
|
|
||||||
|
|
||||||
if (!script_result.valid()) {
|
|
||||||
sol::error err = script_result;
|
|
||||||
std::cout << "Error running script: " << err.what() << std::endl;
|
|
||||||
return LuaResultType::SCRIPT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LuaResultType::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
safesol::LuaResultType safesol::script(const char* script)
|
|
||||||
{
|
|
||||||
sol::load_result result = lua.load(script);
|
|
||||||
if (!result.valid()) {
|
|
||||||
sol::error err = result;
|
|
||||||
std::cout << "Error loading script: " << err.what() << std::endl;
|
|
||||||
return LuaResultType::LOAD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sol::protected_function_result script_result = result();
|
|
||||||
|
|
||||||
if (!script_result.valid()) {
|
|
||||||
sol::error err = script_result;
|
|
||||||
std::cout << "Error running script: " << err.what() << std::endl;
|
|
||||||
return LuaResultType::SCRIPT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LuaResultType::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
safesol::LuaResultType safesol::load(const std::string& file)
|
|
||||||
{
|
|
||||||
sol::load_result result = lua.load_file(file);
|
|
||||||
if (!result.valid()) {
|
|
||||||
sol::error err = result;
|
|
||||||
std::cout << "Error loading file: " << err.what() << std::endl;
|
|
||||||
return LuaResultType::LOAD_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sol::protected_function_result script_result = result();
|
|
||||||
|
|
||||||
if (!script_result.valid()) {
|
|
||||||
sol::error err = script_result;
|
|
||||||
std::cout << "Error running script: " << err.what() << std::endl;
|
|
||||||
return LuaResultType::SCRIPT_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LuaResultType::SUCCESS;
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <std.hpp>
|
|
||||||
#include <sol/sol.hpp>
|
|
||||||
|
|
||||||
class safesol
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class LuaResultType : u8
|
|
||||||
{
|
|
||||||
SUCCESS = 0,
|
|
||||||
LOAD_ERROR = 1,
|
|
||||||
SCRIPT_ERROR,
|
|
||||||
RUN_ERROR,
|
|
||||||
UNKNOWN_ERROR
|
|
||||||
};
|
|
||||||
|
|
||||||
sol::state lua;
|
|
||||||
|
|
||||||
|
|
||||||
LuaResultType script(const std::string& script);
|
|
||||||
LuaResultType script(const char* script);
|
|
||||||
|
|
||||||
LuaResultType load(const std::string& file);
|
|
||||||
|
|
||||||
template<typename ...Args>
|
|
||||||
sol::protected_function_result default_caller(const sol::protected_function& function, Args&&... args)
|
|
||||||
{
|
|
||||||
return function(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ...Args>
|
|
||||||
LuaResultType run(const std::string& function_name, Args&&... args)
|
|
||||||
{
|
|
||||||
return run_on_caller(function_name, default_caller, std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ...Args, typename Caller = std::function<sol::protected_function_result(const sol::protected_function&, Args&&...)>>
|
|
||||||
LuaResultType run_on_caller(const std::string& function_name, const Caller& caller, Args&&... args)
|
|
||||||
{
|
|
||||||
std::cout << "Looking for function: " << function_name << std::endl;
|
|
||||||
|
|
||||||
auto function = lua[function_name];
|
|
||||||
if (!function.valid()) {
|
|
||||||
std::cout << "Error: function " << function_name << " not found" << std::endl;
|
|
||||||
return LuaResultType::RUN_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Found function, attempting to run" << std::endl;
|
|
||||||
|
|
||||||
auto result = caller(function, std::forward<Args>(args)...);
|
|
||||||
if (!result.valid()) {
|
|
||||||
sol::error err = result;
|
|
||||||
std::cout << "Error running function " << function_name << ": " << err.what() << std::endl;
|
|
||||||
return LuaResultType::RUN_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return LuaResultType::SUCCESS;
|
|
||||||
}
|
|
||||||
};
|
|
214
src/main.cpp
214
src/main.cpp
|
@ -1,213 +1,21 @@
|
||||||
#include <iostream>
|
#include <stdio.h>
|
||||||
#include <raylib.h>
|
#include "sortiva/sortiva.hpp"
|
||||||
#include <raylibs/raygui.h>
|
|
||||||
#include "sva.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
#include "gui/drawing_helper.hpp"
|
|
||||||
|
|
||||||
#define RESOURCES_PATH "G:/School/Belegarbeit/sortiva/res/"
|
|
||||||
|
|
||||||
#define SETTINGS_PATH "./.config.cfg"
|
|
||||||
|
|
||||||
#define NO_GUI
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef NO_GUI
|
|
||||||
|
|
||||||
int screenWidth = 1280;
|
|
||||||
int screenHeight = 720;
|
|
||||||
|
|
||||||
enum GAME_STATES
|
|
||||||
{
|
|
||||||
SVA_STATE_TITLE,
|
|
||||||
SVA_STATE_GAMEPLAY,
|
|
||||||
};
|
|
||||||
|
|
||||||
GAME_STATES gameState = SVA_STATE_TITLE;
|
|
||||||
|
|
||||||
void UpdateDrawFrame(); // Update and Draw one frame
|
|
||||||
|
|
||||||
#include "gui/themes/dark.h"
|
|
||||||
#include "gui/Views/ViewManager.h"
|
|
||||||
#endif
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef NO_GUI
|
|
||||||
#include "SortingTester.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include <random>
|
|
||||||
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 gen(rd());
|
|
||||||
std::uniform_int_distribution<u64> dis(0, 10);
|
|
||||||
|
|
||||||
void populate(size_t index, u64& value)
|
|
||||||
{
|
|
||||||
value = dis(gen);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//#undef _DEBUG
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
sva_console_init();
|
printf("Darling, I'm Home!\n");
|
||||||
|
#ifdef _DEBUG
|
||||||
#ifdef NO_GUI
|
try {
|
||||||
|
|
||||||
std::cout << "Sortiva - Sorting Algorithm Visualizer" << std::endl;
|
|
||||||
std::cout << "No GUI mode" << std::endl;
|
|
||||||
|
|
||||||
SortingTester tester;
|
|
||||||
tester.populate( populate );
|
|
||||||
|
|
||||||
tester.load_internal();
|
|
||||||
|
|
||||||
SortingTester::run_result result = tester.run("bubble_sort");
|
|
||||||
|
|
||||||
std::cout << "Time: " << result.timer.seconds << " seconds" << std::endl;
|
|
||||||
std::cout << "Difftime: " << result.timer.difftime << std::endl;
|
|
||||||
|
|
||||||
|
|
||||||
std::cout << "Count swaps: " << result.count_swaps << std::endl;
|
|
||||||
std::cout << "Count comparisons: " << result.count_comparisons << std::endl;
|
|
||||||
std::cout << "\tCount greater: " << result.count_greater << std::endl;
|
|
||||||
std::cout << "\tCount less: " << result.count_less << std::endl;
|
|
||||||
std::cout << "\tCount equal: " << result.count_equal << std::endl;
|
|
||||||
|
|
||||||
std::cout << "\n\n";
|
|
||||||
|
|
||||||
|
|
||||||
std::cout << "\nPress any key to exit..." << std::endl;
|
|
||||||
// getchar();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Sortiva app;
|
||||||
#ifndef NO_GUI
|
app.run();
|
||||||
if(!DirectoryExists(RESOURCES_PATH))
|
#ifdef _DEBUG
|
||||||
{
|
|
||||||
std::cerr << "Resources folder not found!" << std::endl;
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
|
||||||
InitWindow(screenWidth, screenHeight, "Sortiva - Sorting Algorithm Visualizer");
|
|
||||||
|
|
||||||
SetWindowIcon(LoadImage(RESOURCES_PATH "/images/sva-logo.png"));
|
|
||||||
|
|
||||||
SetWindowMinSize(screenWidth, screenHeight);
|
|
||||||
SetWindowState(FLAG_WINDOW_RESIZABLE);
|
|
||||||
SetExitKey(0);
|
|
||||||
|
|
||||||
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
|
|
||||||
//--------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
GuiLoadStyleDark();
|
|
||||||
GuiSetStyle(DEFAULT, TEXT_SIZE, 20);
|
|
||||||
|
|
||||||
// Main game loop
|
|
||||||
while (!WindowShouldClose())
|
|
||||||
{
|
{
|
||||||
if (IsWindowResized())
|
printf("\nError: %s\n\n", e.what());
|
||||||
{
|
|
||||||
screenWidth = GetScreenWidth();
|
|
||||||
screenHeight = GetScreenHeight();
|
|
||||||
}
|
|
||||||
UpdateDrawFrame();
|
|
||||||
}
|
}
|
||||||
CloseWindow();
|
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_GUI
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
// Render Functions
|
|
||||||
//----------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
void RenderGameplayState();
|
|
||||||
|
|
||||||
|
|
||||||
Rectangle ButtonRects[] = {
|
|
||||||
{50, 150, 150, 40},
|
|
||||||
{50, 200, 150, 40},
|
|
||||||
{50, 300, 150, 40},
|
|
||||||
};
|
|
||||||
|
|
||||||
void UpdateDrawFrame()
|
|
||||||
{
|
|
||||||
BeginDrawing();
|
|
||||||
|
|
||||||
ClearBackground(GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR)));
|
|
||||||
|
|
||||||
switch (gameState)
|
|
||||||
{
|
|
||||||
case SVA_STATE_TITLE:
|
|
||||||
sva::DrawText("Sortiva", {screenWidth/2, 20}, 100, sva::GetThemeColor(TEXT_COLOR_NORMAL), sva::TEXT_ALIGN_CENTER);
|
|
||||||
|
|
||||||
if(GuiButton(ButtonRects[0], "Öffnen"))
|
|
||||||
{
|
|
||||||
gameState = SVA_STATE_GAMEPLAY;
|
|
||||||
}
|
|
||||||
if(GuiButton(ButtonRects[1], "Speichern"))
|
|
||||||
{
|
|
||||||
gameState = SVA_STATE_GAMEPLAY;
|
|
||||||
}
|
|
||||||
if(GuiButton(ButtonRects[2], "Schließen"))
|
|
||||||
{
|
|
||||||
CloseWindow();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case SVA_STATE_GAMEPLAY:
|
|
||||||
if(IsKeyPressed(KEY_ESCAPE))
|
|
||||||
{
|
|
||||||
gameState = SVA_STATE_TITLE;
|
|
||||||
}
|
|
||||||
RenderGameplayState();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
EndDrawing();
|
|
||||||
}
|
|
||||||
#include <numbers>
|
|
||||||
|
|
||||||
#define PI_2 std::numbers::pi_v<float> / 2
|
|
||||||
|
|
||||||
#define sin3(x) pow((-cos(PI_2+ ##x)),3)
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
Vector2 heart_position = Vector2{static_cast<float>(screenWidth)/2, static_cast<float>(screenHeight)/2.5f};
|
|
||||||
Vector2 heart_function(float t, float scale)
|
|
||||||
{
|
|
||||||
return Vector2{
|
|
||||||
((16 * static_cast<float>(sin3(t))) * scale) + heart_position.x,
|
|
||||||
((13 * cos(t) - 5 * cos(2*t) - 2 * cos(3*t) - cos(4*t)) * -scale) + heart_position.y
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#define STEPS 1000
|
|
||||||
#define STEP_SIZE 0.01f
|
|
||||||
|
|
||||||
void RenderGameplayState()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < STEPS; i++)
|
|
||||||
{
|
|
||||||
Vector2 pos = heart_function(static_cast<float>(i) * STEP_SIZE, 20);
|
|
||||||
Vector2 pos2 = heart_function(static_cast<float>(i) * STEP_SIZE + STEP_SIZE, 20);
|
|
||||||
DrawLine(
|
|
||||||
pos.x,
|
|
||||||
pos.y,
|
|
||||||
pos2.x,
|
|
||||||
pos2.y,
|
|
||||||
GetColor(GuiGetStyle(DEFAULT, LINE_COLOR))
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
45
src/sortiva/GuiFileDialog.cpp
Normal file
45
src/sortiva/GuiFileDialog.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include "GuiFileDialog.hpp"
|
||||||
|
#include <raylibs/raygui.h>
|
||||||
|
#include <raylibs/modules/gui_window_file_dialog.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
Gui_WindowFileDialog::Gui_WindowFileDialog()
|
||||||
|
{
|
||||||
|
fileDialogState = new GuiWindowFileDialogState(InitGuiWindowFileDialog(GetWorkingDirectory()));
|
||||||
|
fileDialogState->windowBounds = { 10, 10, fileDialogState->windowBounds.height, fileDialogState->windowBounds.height };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gui_WindowFileDialog::update()
|
||||||
|
{
|
||||||
|
bool file_opened = false;
|
||||||
|
if (fileDialogState->SelectFilePressed)
|
||||||
|
{
|
||||||
|
// Load image file (if supported extension)
|
||||||
|
if (IsFileExtension(fileDialogState->fileNameText, ".lua"))
|
||||||
|
{
|
||||||
|
strcpy(fileNameToLoad, TextFormat("%s/%s", fileDialogState->dirPathText, fileDialogState->fileNameText));
|
||||||
|
openedFile = fileNameToLoad;
|
||||||
|
file_opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileDialogState->SelectFilePressed = false;
|
||||||
|
}
|
||||||
|
return file_opened;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gui_WindowFileDialog::draw()
|
||||||
|
{
|
||||||
|
// raygui: controls drawing
|
||||||
|
//----------------------------------------------------------------------------------
|
||||||
|
if (fileDialogState->windowActive) GuiLock();
|
||||||
|
|
||||||
|
if (GuiButton({ 20, 20, 140, 30 }, GuiIconText(GuiIconName::ICON_FILE_OPEN, "Open Image"))) fileDialogState->windowActive = true;
|
||||||
|
|
||||||
|
GuiUnlock();
|
||||||
|
|
||||||
|
// GUI: Dialog Window
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
GuiWindowFileDialog(fileDialogState);
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
}
|
19
src/sortiva/GuiFileDialog.hpp
Normal file
19
src/sortiva/GuiFileDialog.hpp
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <raylibs/modules/gui_window_file_dialog.hpp>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
class Gui_WindowFileDialog
|
||||||
|
{
|
||||||
|
GuiWindowFileDialogState* fileDialogState;
|
||||||
|
char fileNameToLoad[512] = { 0 };
|
||||||
|
public:
|
||||||
|
Gui_WindowFileDialog();
|
||||||
|
|
||||||
|
std::string openedFile;
|
||||||
|
|
||||||
|
bool update();
|
||||||
|
|
||||||
|
void draw();
|
||||||
|
};
|
210
src/sortiva/sortiva-draw.cpp
Normal file
210
src/sortiva/sortiva-draw.cpp
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
#include "sortiva.hpp"
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
|
constexpr Color sorter_colors[] = {
|
||||||
|
{ 253, 249, 0, 255 }, // Yellow
|
||||||
|
{ 255, 203, 0, 255 }, // Gold
|
||||||
|
{ 255, 161, 0, 255 }, // Orange
|
||||||
|
{ 255, 109, 194, 255 }, // Pink
|
||||||
|
{ 230, 41, 55, 255 }, // Red
|
||||||
|
{ 190, 33, 55, 255 }, // Maroon
|
||||||
|
{ 0, 228, 48, 255 }, // Green
|
||||||
|
{ 0, 158, 47, 255 }, // Lime
|
||||||
|
{ 0, 117, 44, 255 }, // Dark Green
|
||||||
|
{ 102, 191, 255, 255 }, // Sky Blue
|
||||||
|
{ 0, 121, 241, 255 }, // Blue
|
||||||
|
{ 0, 82, 172, 255 }, // Dark Blue
|
||||||
|
{ 255, 0, 255, 255 }, // Magenta
|
||||||
|
{ 200, 122, 255, 255 }, // Purple
|
||||||
|
{ 135, 60, 190, 255 }, // Violet
|
||||||
|
{ 112, 31, 126, 255 }, // Dark Purple
|
||||||
|
{ 211, 176, 131, 255 }, // Beige
|
||||||
|
{ 127, 106, 79, 255 }, // Brown
|
||||||
|
{ 76, 63, 47, 255 }, // Dark Brown
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int sorter_colors_size = sizeof(sorter_colors) / sizeof(Color);
|
||||||
|
|
||||||
|
constexpr Color sorter_block_colors[] = {
|
||||||
|
{ 200, 200, 200, 255 }, // Light Gray
|
||||||
|
{ 80, 80, 80, 255 }, // Dark Gray
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr int sorter_block_colors_size = sizeof(sorter_block_colors) / sizeof(Color);
|
||||||
|
|
||||||
|
|
||||||
|
void Sortiva::draw()
|
||||||
|
{
|
||||||
|
Vector2 margin = {
|
||||||
|
.x = m_Width * 0.01f,
|
||||||
|
.y = 70
|
||||||
|
};
|
||||||
|
DrawRectangleV(margin, { m_Width - 2 * margin.x, m_Height - 2 * margin.y }, { 60, 60, 60, 255 });
|
||||||
|
|
||||||
|
|
||||||
|
margin = {
|
||||||
|
.x = m_Width * 0.02f,
|
||||||
|
.y = 80
|
||||||
|
};
|
||||||
|
|
||||||
|
Rectangle plane = {
|
||||||
|
.x = margin.x,
|
||||||
|
.y = margin.y,
|
||||||
|
.width = m_Width - margin.x * 2,
|
||||||
|
.height = m_Height - margin.y * 2
|
||||||
|
};
|
||||||
|
|
||||||
|
if (m_Steps->empty())
|
||||||
|
{
|
||||||
|
static const char* msg = "Press \"Run\" to start a sorting";
|
||||||
|
static int width = MeasureText(msg, 20);
|
||||||
|
DrawText(msg, plane.x + plane.width / 2 - width / 2, plane.y + plane.height / 2 - 10, 20, { 245, 245, 245, 255 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// +2 for start points and end points; will be removed later in the function
|
||||||
|
size_t cvals = m_Steps->size();
|
||||||
|
|
||||||
|
size_t steps = m_Steps->at(0).depth();
|
||||||
|
for (size_t i = 1; i < cvals; ++i)
|
||||||
|
{
|
||||||
|
steps = std::min(steps, m_Steps->at(i).depth());
|
||||||
|
}
|
||||||
|
|
||||||
|
steps += 1;
|
||||||
|
|
||||||
|
// ui distance values
|
||||||
|
int w = static_cast<int>(plane.width / static_cast<float>(steps));
|
||||||
|
int g = plane.height / static_cast<float>(cvals + 1);
|
||||||
|
int h = (plane.height - static_cast<float>(cvals - 1) * g) / 2;
|
||||||
|
int e = w / 2;
|
||||||
|
float wf = static_cast<float>(w);
|
||||||
|
|
||||||
|
float pwhd = sqrtf(plane.width * plane.width + plane.height * plane.height);
|
||||||
|
float pw = plane.width / pwhd - 0.01f;
|
||||||
|
float ph = plane.height / pwhd;
|
||||||
|
float l = pw * ph * pwhd * 0.02f - static_cast<float>(steps) / 2; // Make more fitting
|
||||||
|
|
||||||
|
for (size_t i = 0; i < steps; ++i)
|
||||||
|
{
|
||||||
|
DrawRectangle(
|
||||||
|
static_cast<int>(i) * w + static_cast<int>(plane.x),
|
||||||
|
plane.y,
|
||||||
|
w,
|
||||||
|
plane.height,
|
||||||
|
sorter_block_colors[i % sorter_block_colors_size]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
steps -= 1;
|
||||||
|
|
||||||
|
// colors to values - ratio ; adds high variance to the color selection
|
||||||
|
int colid = sorter_colors_size / cvals;
|
||||||
|
|
||||||
|
// font settings
|
||||||
|
constexpr Color textColor = { 0, 0, 0, 255 };
|
||||||
|
int l3 = static_cast<int>(l * 3);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
DrawFPS(5, 5);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (int v = 0; v < cvals; ++v)
|
||||||
|
{
|
||||||
|
linked_list<uint16_t>* list = &m_Steps->at(v);
|
||||||
|
uint16_t value = list->value;
|
||||||
|
Color col = sorter_colors[(v * colid) % sorter_colors_size];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int s = 0;
|
||||||
|
for (; list->next; list = list->next)
|
||||||
|
{
|
||||||
|
float sf = static_cast<float>(s);
|
||||||
|
|
||||||
|
value = list->value;
|
||||||
|
uint16_t nvalue = list->next->value;
|
||||||
|
float y = plane.y + h + g * (value - 1);
|
||||||
|
float yt = plane.y + h + g * (nvalue - 1);
|
||||||
|
|
||||||
|
|
||||||
|
DrawSplineSegmentBezierCubic(
|
||||||
|
{ (sf + 1.f) * wf + plane.x - 1, y },
|
||||||
|
{ (sf + 2.f) * wf + plane.x, y },
|
||||||
|
{ (sf + 1.f) * wf + plane.x, yt },
|
||||||
|
{ (sf + 2.f) * wf + plane.x, yt },
|
||||||
|
l,
|
||||||
|
col
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
float font_size = l * 1.2f;
|
||||||
|
int yd = y - yt < 0 ? -font_size : +font_size;
|
||||||
|
yd *= 2;
|
||||||
|
DrawText(
|
||||||
|
TextFormat("%d -> %d", value, nvalue),
|
||||||
|
(sf + 1.f) * wf + plane.x + 10,
|
||||||
|
y + yd,
|
||||||
|
font_size,
|
||||||
|
col);
|
||||||
|
#endif
|
||||||
|
++s;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = list->value;
|
||||||
|
|
||||||
|
Vector2 pos = { wf * steps + e + plane.x, h + (value - 1) * g + plane.y };
|
||||||
|
DrawCircleV(pos, l3, col);
|
||||||
|
|
||||||
|
DrawLineEx(
|
||||||
|
{ pos.x - e - 1, pos.y },
|
||||||
|
pos,
|
||||||
|
l,
|
||||||
|
col
|
||||||
|
);
|
||||||
|
|
||||||
|
const char* strv = TextFormat("%d", v + 1);
|
||||||
|
DrawText(
|
||||||
|
strv,
|
||||||
|
static_cast<int>(pos.x) + e / 2,
|
||||||
|
static_cast<int>(pos.y) - l3 / 2,
|
||||||
|
l3,
|
||||||
|
textColor
|
||||||
|
);
|
||||||
|
|
||||||
|
if (list->first)
|
||||||
|
list = list->first;
|
||||||
|
value = list->value;
|
||||||
|
pos = { wf - e + plane.x, h + (value - 1) * g + plane.y };
|
||||||
|
|
||||||
|
DrawText(
|
||||||
|
strv,
|
||||||
|
static_cast<int>(pos.x) - e / 2 - l3 / 2,
|
||||||
|
static_cast<int>(pos.y) - l3 / 2,
|
||||||
|
l3,
|
||||||
|
textColor
|
||||||
|
);
|
||||||
|
|
||||||
|
DrawRing(
|
||||||
|
pos,
|
||||||
|
l * 2,
|
||||||
|
l3,
|
||||||
|
20.f,
|
||||||
|
340.f,
|
||||||
|
10,
|
||||||
|
col
|
||||||
|
);
|
||||||
|
|
||||||
|
DrawLineEx(
|
||||||
|
pos,
|
||||||
|
{ pos.x + e, pos.y },
|
||||||
|
l,
|
||||||
|
col
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
src/sortiva/sortiva-draw_overlay.cpp
Normal file
33
src/sortiva/sortiva-draw_overlay.cpp
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
#include "sortiva.hpp"
|
||||||
|
|
||||||
|
#include <raylibs/raygui.h>
|
||||||
|
|
||||||
|
|
||||||
|
void Sortiva::draw_overlay()
|
||||||
|
{
|
||||||
|
//static bool edit_mode = false;
|
||||||
|
//
|
||||||
|
//GuiUnlock();
|
||||||
|
//
|
||||||
|
//static int active = 0;
|
||||||
|
//if (GuiDropdownBox({ 250,20,200,30 }, m_Lua.SorterListStr.c_str(), &active, edit_mode)) edit_mode = !edit_mode;
|
||||||
|
//
|
||||||
|
//if (edit_mode) GuiLock();
|
||||||
|
|
||||||
|
if (GuiButton({ 20, 15, 100, 40 }, "Run"))
|
||||||
|
{
|
||||||
|
setup();
|
||||||
|
m_SortingFinished = false;
|
||||||
|
}
|
||||||
|
if (GuiButton({ 140, 15, 100, 40 }, m_SortingFinished ? "Continue" : "Pause"))
|
||||||
|
{
|
||||||
|
if (!m_SortingFinished || !m_Steps->empty()) {
|
||||||
|
m_SortingFinished = !m_SortingFinished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GuiButton({ 20, static_cast<float>(GetScreenHeight()) - 15 - 40, 100, 40 }, "Reset"))
|
||||||
|
{
|
||||||
|
m_Steps->clear();
|
||||||
|
}
|
||||||
|
}
|
22
src/sortiva/sortiva-update.cpp
Normal file
22
src/sortiva/sortiva-update.cpp
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include "sortiva.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
void Sortiva::update(double dt) {
|
||||||
|
if (m_Ticker.update(std::chrono::duration<float>(dt)))
|
||||||
|
{
|
||||||
|
if (!m_SortingFinished) {
|
||||||
|
if (m_Sorter.poll())
|
||||||
|
{
|
||||||
|
m_SortingFinished = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LuaSortList& list = m_Sorter.get();
|
||||||
|
for (uint16_t i = 0; i < list.size(); ++i)
|
||||||
|
{
|
||||||
|
m_Steps->at(list.at(i) - 1).put(i + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
81
src/sortiva/sortiva.cpp
Normal file
81
src/sortiva/sortiva.cpp
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#include "sortiva.hpp"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
|
||||||
|
Sortiva::Sortiva() : m_Ticker(std::chrono::seconds(1))
|
||||||
|
{
|
||||||
|
m_Sorter.set(m_List);
|
||||||
|
|
||||||
|
m_Steps = std::make_unique<val_step_diag>();
|
||||||
|
|
||||||
|
InitWindow(1280, 720, "Sortiva");
|
||||||
|
if (!IsWindowReady()) exit(2);
|
||||||
|
|
||||||
|
m_Width = GetRenderWidth();
|
||||||
|
m_Height = GetRenderHeight();
|
||||||
|
SetWindowMinSize(static_cast<int>(1280 * 0.25f), static_cast<int>(720 * 0.25f));
|
||||||
|
SetWindowState(ConfigFlags::FLAG_WINDOW_RESIZABLE | ConfigFlags::FLAG_VSYNC_HINT);
|
||||||
|
|
||||||
|
SetTargetFPS(60);
|
||||||
|
|
||||||
|
MaximizeWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
Sortiva::~Sortiva()
|
||||||
|
{
|
||||||
|
CloseWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sortiva::run()
|
||||||
|
{
|
||||||
|
while (m_Running)
|
||||||
|
{
|
||||||
|
if (WindowShouldClose()) m_Running = false;
|
||||||
|
if (IsWindowResized())
|
||||||
|
{
|
||||||
|
m_Width = GetScreenWidth();
|
||||||
|
m_Height = GetScreenHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearBackground({ 25, 25, 25, 255 });
|
||||||
|
BeginDrawing();
|
||||||
|
|
||||||
|
update(GetFrameTime());
|
||||||
|
draw();
|
||||||
|
draw_overlay();
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sortiva::setup()
|
||||||
|
{
|
||||||
|
m_Steps->clear();
|
||||||
|
m_List.list.clear();
|
||||||
|
|
||||||
|
uint16_t count = 5;
|
||||||
|
|
||||||
|
|
||||||
|
for (int i = 1; i <= count; ++i) // 1,2,3,4,5
|
||||||
|
{
|
||||||
|
m_List.list.push_back(i);
|
||||||
|
m_Steps->emplace_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::random_device dev;
|
||||||
|
std::mt19937 rng(dev());
|
||||||
|
|
||||||
|
std::ranges::shuffle(m_List.list, rng); // 2,3,1,5,4
|
||||||
|
|
||||||
|
for (int i = 1; i <= count; ++i)
|
||||||
|
{
|
||||||
|
m_Steps->at(m_List.at(i - 1) - 1).value = i;
|
||||||
|
}
|
||||||
|
}
|
82
src/sortiva/sortiva.hpp
Normal file
82
src/sortiva/sortiva.hpp
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <collections.hpp>
|
||||||
|
#include "../lua/FutureLua.hpp"
|
||||||
|
#include <TickSystem.hpp>
|
||||||
|
#include "../LuaSortList.hpp"
|
||||||
|
|
||||||
|
class Bubble_Sorter : Future<LuaSortList>
|
||||||
|
{
|
||||||
|
LuaSortList* list = nullptr;
|
||||||
|
struct STATE
|
||||||
|
{
|
||||||
|
size_t n = 1;
|
||||||
|
} state;
|
||||||
|
public:
|
||||||
|
Bubble_Sorter() = default;
|
||||||
|
Bubble_Sorter(LuaSortList& l) : list(&l) {}
|
||||||
|
|
||||||
|
bool poll() override
|
||||||
|
{
|
||||||
|
size_t n = list->size();
|
||||||
|
if (n <= 1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.n = state.n + 1;
|
||||||
|
|
||||||
|
if (state.n > n)
|
||||||
|
{
|
||||||
|
state.n = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list->at(state.n - 2) > list->at(state.n - 1)) {
|
||||||
|
list->swap(state.n - 2, state.n - 1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return list->sorted();
|
||||||
|
}
|
||||||
|
|
||||||
|
LuaSortList& get() override
|
||||||
|
{
|
||||||
|
return *list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(LuaSortList& l)
|
||||||
|
{
|
||||||
|
list = &l;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Sortiva final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sortiva();
|
||||||
|
~Sortiva();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
private:
|
||||||
|
int m_Width;
|
||||||
|
int m_Height;
|
||||||
|
bool m_Running = true;
|
||||||
|
|
||||||
|
void draw();
|
||||||
|
void draw_overlay();
|
||||||
|
void update(double);
|
||||||
|
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
bool m_SortingFinished = true;
|
||||||
|
TickSystem m_Ticker;
|
||||||
|
Bubble_Sorter m_Sorter;
|
||||||
|
LuaSortList m_List;
|
||||||
|
|
||||||
|
|
||||||
|
// std::unique_ptr
|
||||||
|
// -> tree
|
||||||
|
// -> linked_list
|
||||||
|
// -> uint16_t
|
||||||
|
using val_step_diag = std::vector<linked_list<uint16_t>>;
|
||||||
|
std::unique_ptr<val_step_diag> m_Steps;
|
||||||
|
};
|
17
src/sva.hpp
17
src/sva.hpp
|
@ -1,17 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <iostream>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
inline const char* ASCII_TITLE = R"(
|
|
||||||
__
|
|
||||||
(_ _ ___|_ o _
|
|
||||||
__)(_) | |_ | \_/(_|
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
)";
|
|
||||||
|
|
||||||
inline void sva_console_init()
|
|
||||||
{
|
|
||||||
std::cout << ASCII_TITLE;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
|
||||||
testing::InitGoogleTest(&argc, argv);
|
|
||||||
return RUN_ALL_TESTS();
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
// tests/sorting_tests.cpp
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void swap(T& a, T& b) noexcept
|
|
||||||
{
|
|
||||||
T temp = a;
|
|
||||||
a = b;
|
|
||||||
b = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void bubble_sort(std::vector<T>& in)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; i < in.size(); ++i)
|
|
||||||
{
|
|
||||||
for (size_t j = 0; j < in.size() - 1; ++j)
|
|
||||||
{
|
|
||||||
if (in[j] > in[j + 1])
|
|
||||||
{
|
|
||||||
swap(in[j], in[j + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TEST(BubbleSortTest, CorrectlySortsVector) {
|
|
||||||
std::vector input = {5, 2, 8, 1, 9};
|
|
||||||
std::vector expected = {1, 2, 5, 8, 9};
|
|
||||||
|
|
||||||
bubble_sort(input);
|
|
||||||
|
|
||||||
EXPECT_EQ(input, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BubbleSortTest, HandlesEmptyVector) {
|
|
||||||
std::vector<int> input = {};
|
|
||||||
std::vector<int> expected = {};
|
|
||||||
|
|
||||||
bubble_sort(input);
|
|
||||||
|
|
||||||
EXPECT_EQ(input, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(BubbleSortTest, HandlesSingleElement) {
|
|
||||||
std::vector input = {1};
|
|
||||||
std::vector expected = {1};
|
|
||||||
|
|
||||||
bubble_sort(input);
|
|
||||||
|
|
||||||
EXPECT_EQ(input, expected);
|
|
||||||
}
|
|
Loading…
Reference in a new issue