diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000000000000000000000000000000000..293140ab8d18690fd3dab642656d917ee8aef648 --- /dev/null +++ b/.clang-format @@ -0,0 +1,287 @@ +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Right +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + AlignFunctionDeclarations: true + AlignFunctionPointers: false + PadOperators: true +AlignConsecutiveShortCaseStatements: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCaseArrows: true + AlignCaseColons: true +AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenCondOperatorColons: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignConsecutiveTableGenDefinitionColons: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + AlignFunctionDeclarations: false + AlignFunctionPointers: false + PadOperators: false +AlignEscapedNewlines: LeftWithLastLine +AlignOperands: AlignAfterOperator +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseExpressionOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: true +AllowShortCompoundRequirementOnASingleLine: true +AllowShortEnumsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AllowShortNamespacesOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AttributeMacros: + - __capability +BinPackArguments: false +BinPackParameters: OnePerLine +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterExternBlock: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAdjacentStringLiterals: true +BreakAfterAttributes: Leave +BreakAfterJavaFieldAnnotations: false +BreakAfterReturnType: Automatic +BreakArrays: true +BreakBeforeBinaryOperators: All +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Custom +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakBinaryOperations: OnePerLine +BreakConstructorInitializers: BeforeColon +BreakFunctionDefinitionParameters: false +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +BreakTemplateDeclarations: MultiLine +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExportBlock: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: BeforeHash +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: true +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 4 + BinaryMinDigits: 8 + Decimal: 3 + DecimalMinDigits: 5 + Hex: 4 + HexMinDigits: 8 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLines: + AtEndOfFile: false + AtStartOfBlock: true + AtStartOfFile: true +KeepFormFeed: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MainIncludeChar: Quote +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: CurrentLine +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakBeforeMemberAccess: 150 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakScopeResolution: 500 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 1000 +PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Left +ReferenceAlignment: Pointer +ReflowComments: Always +RemoveBracesLLVM: false +RemoveEmptyLinesInUnwrappedLines: true +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SkipMacroDefinitionBody: false +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false +SpaceBeforeParens: ControlStatementsExceptControlMacros +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterPlacementOperator: true + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 0 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + ExceptDoubleParentheses: false + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT + - emit +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TableGenBreakInsideDAGArg: DontBreak +TabWidth: 4 +UseTab: Never +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +WrapNamespaceBodyWithEmptyLines: Leave +... + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6e700b406b2758f8794f08da214a0d963d81e836 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash +*.pro.user* +CMakeLists.txt.user* +*.flc +.*.swp +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* +*.Debug +*.Release +*.pyc +*.dll +*.exe +build/ +.cache/ +settings.json \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000000000000000000000000000000000..a0ae39d66db0883f0d04ec8577732a9616885cfb --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ +{ + "recommendations": [ + "aaron-bond.better-comments", + "ms-vscode.cpptools-extension-pack", + "vadimcn.vscode-lldb", + "mhutchie.git-graph", + "cschlosser.doxdocgen", + "oderwat.indent-rainbow", + "llvm-vs-code-extensions.vscode-clangd" + ] +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000000000000000000000000000000..f90d82b33730c30f58ae3a65c160ce531778a60f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,16 @@ +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "(lldb) Launch", + "type": "lldb", + "request": "launch", + "program": "${command:cmake.launchTargetPath}", + "args": [], + "cwd": "${workspaceFolder}/build" + } + ] +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..94ffedd9f230be75f5f510575bdac6a7068d0796 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,112 @@ +cmake_minimum_required(VERSION 3.18) + +project(SimpleTest VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + + +if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(Qt5_DIR "C:/msys64/clang64/qt5-static/lib/cmake/Qt5")#ucrt64 +endif() + +set(CMAKE_CXX_STANDARD_LIBRARIES "-stdlib=libc++") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld -static")# -static-libstdc++")# -static-libgcc")# -stdlib=libc++ -lc++ -lc++abi +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s") + + +find_package(Qt5 REQUIRED COMPONENTS Widgets Charts) +#find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Charts) +#find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Charts) + +set(PROJECT_SOURCES + src/mainWindow.cpp + src/configPanel.cpp + src/chartMenu.cpp + src/graphNames.cpp + src/cute.cpp + src/control.cpp + src/cuteControl.cpp +) + +#target_include_directories(SimpleTest PRIVATE +# /usr/include/x86_64-linux-gnu/qt6/QtWidgets +# /usr/include/x86_64-linux-gnu/qt6/QtCharts +#) + +add_library(cute SHARED + ${PROJECT_SOURCES} + src/cute.def +) + +target_link_libraries(cute PRIVATE #"-Wl,--no-whole-archive" + Qt${QT_VERSION_MAJOR}::Widgets + Qt${QT_VERSION_MAJOR}::Charts +) + +target_include_directories(cute PRIVATE + include +) + +target_compile_definitions(cute PRIVATE + EXPORT_CUTE + QT_NO_VERSION_TAGGING +) + +if (WIN32) + set_target_properties(cute PROPERTIES PREFIX "") +endif() +set_target_properties(cute PROPERTIES LINK_FLAGS "-Wl,--output-def,cute.def") + + +add_executable(DynamicDemo + src/main.cpp + examples/studiMain.cpp +) + +target_link_libraries(DynamicDemo PRIVATE + cute +) + +target_include_directories(DynamicDemo PRIVATE + include +) + +# Set the WIN32_EXECUTABLE property conditionally for Release, MinSizeRel, and RelWithDebInfo builds. +# This lets the exe run without a terminal, making stdout inaccessible for now. +if(WIN32) + set_target_properties(DynamicDemo PROPERTIES WIN32_EXECUTABLE $<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>) +endif(WIN32) + + +add_executable(LoaderDemo + src/main.cpp + src/cuteImporter.cpp + examples/dynamicLoadDummy.cpp +) + +target_include_directories(LoaderDemo PRIVATE + include +) + +target_compile_definitions(LoaderDemo PRIVATE + RUNTIME_LOAD +) + +# Set the WIN32_EXECUTABLE property conditionally for Release, MinSizeRel, and RelWithDebInfo builds. +# This lets the exe run without a terminal, making stdout inaccessible for now. +if(WIN32) + set_target_properties(LoaderDemo PROPERTIES WIN32_EXECUTABLE $<OR:$<CONFIG:Release>,$<CONFIG:MinSizeRel>,$<CONFIG:RelWithDebInfo>>) +endif(WIN32) + +# Use this command to copy the .dll from the lib folder next to the freshly built .exe. Which is the most simple way to get it working. +#add_custom_command(TARGET LoaderDemo POST_BUILD # Adds a post-build event to DynamicDemo +# COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." +# "${PROJECT_SOURCE_DIR}/lib/cute.dll" # <--this is in-file +# $<TARGET_FILE_DIR:LoaderDemo>) # <--this is out-file path diff --git a/docs/newAPI-Function.md b/docs/newAPI-Function.md new file mode 100644 index 0000000000000000000000000000000000000000..9b9f83b79b7e19af80858b32d2ba8ff4e18b8bc0 --- /dev/null +++ b/docs/newAPI-Function.md @@ -0,0 +1,49 @@ +To add a new function to the cute Interface, follow these steps: + +1. Declare the function in cute.h with `DYNAMIC`. +``` +void DYNAMIC setPlotTheme(int themeNumber); +``` +2. Define the function in cute.cpp. Most likely you just funnel the call and it's parameters into the `CuteControl`-Singleton, to then be able to use Qt's signals and slots. +``` +void cute::setPlotTheme(int themeNumber) +{ +CuteControl::get().setPlotTheme(themeNumber); +} +``` +3. Define a `signal` in CuteControl, corresponding to your function. To avoid naming conflicts, I used the prefix `s_` in CuteControl. `signals` are always void functions, they are defined by the Qt Meta Object Compiler during the compilation. Think of them as part of the Observer-Pattern, they send a `signal` to all connected `slots`. +``` +void s_setPlotTheme(int); +``` + +4. Declare and define the member function publically in CuteControl. Since Qt's built in types, like `QString` don't require extra steps to be able use them in `signals`, it is advisable to any conversions here. Then `emit` a your `signal`, which will carry the necessary information over the thread boundary. `emit` may be thought of as `fireX()` in the Observer-Pattern. +``` +void setChartTheme(int themeNumber) +{ + emit s_setPlotTheme(themeNumber); +} +``` +5. Now define the fitting `slot` in `control.h`, which will be used to receive your `signal`. In the Observer-Pattern, this is the listener function. Technically it only needs to be `public`, if you want to connect to or call it from another class. +``` +public slots: + void setPlotTheme(int themeNumber); +``` +6. Now define the `slot` like a regular function in `control.cpp`. Here is *finally*, where you implementation should be placed. The View lives in the `MainWindow` member `_w`. In this case, I call a member function of the View. +``` +void Control::setPlotTheme(int themeNumber) +{ + _w->changeChartTheme(themeNumber); +} +``` +7. Lastly, connect `signal` and `slot` in `makeConnections()` of the `Control`. This completes the Observer-Pattern, by subscribing `Control` to `CuteControl`. +Connections are pretty resilient. They check if the listener still exists, as well as in which thread they are. If the listener is in another thread, the `signal` will be queued in the threads corresponding event queue. +With clang, this command has to be quite verbose, the basic pattern is: `Sender, &signal, Receiver, &slot` +``` +connect(cc, &CuteControl::s_setPlotTheme, this, &Control::setPlotTheme); +``` +8. Almost forgot: Of course add some Doxygen. At least in `cute.h`. + + +# TODO +## without importlib +setPlotTheme=_ZN4cute12setPlotThemeEi diff --git a/examples/bubblesort.cpp b/examples/bubblesort.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a02bc43bc6a9525341ba002332d3e50e0536c4dc --- /dev/null +++ b/examples/bubblesort.cpp @@ -0,0 +1,70 @@ +#include "cute.h" + +#include <string> + + +using std::vector; +using std::string, std::to_string; + +void algorithm(); + + + +void setup() +{ + using namespace cute; + registerAlgorithm(algorithm, "Bubblesort"); + + setPlotVisible(result, false); + setPlotTitle(plot, "Bubblesort"); + setPlotTitle(runtime, "Laufzeit"); + setPlotScale(runtime, linear, linear); + + setProblemSize(12); // oder setProblemFile("~/my_data.csv"); + enableAutorun(); +} + + +void algorithm() +{ + cute::Timer timer = cute::Timer(); + vector<float> data = cute::getProblemData1D(); + int swaps = 0; + bool did_change = true; + timer.start(); + while (did_change) + { + did_change = false; + for (size_t i = 0; i < data.size() - 1; ++i) + { + if (data[i] > data[i+1]) + { + float temp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = temp; + did_change = true; + ++swaps; + timer.pause(); + cute::resetPlot(); + cute::plotValues(data); + cute::statusMessage(std::to_string(swaps)); + cute::delay(200); + timer.resume(); + } + } + } + timer.stop(); + cute::statusMessage("Finished!"); + string s = "Result: " + to_string(data.size()) + " Values sorted in " + to_string(timer.result()) + "ms.\n"; + cute::logMessage(s); + cute::addRuntime(data.size(), timer.result()); + return; +} + + + +//#include "bubblesort.h" +int example_main() +{ + cute::run(setup); +} \ No newline at end of file diff --git a/examples/dynamicLoadDummy.cpp b/examples/dynamicLoadDummy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..133db94e002c10e76444254e93bec43c97170c63 --- /dev/null +++ b/examples/dynamicLoadDummy.cpp @@ -0,0 +1,90 @@ +#include "cute.h" + + +void superDummy(); +void advancedDummy(); +void bubblesort(); + +// Is run once at startup. +void setup() +{ + //cute::setPlotTitle(cute::plot, "Hallo"); + //cute::setPlotTitle(cute::result, "Hochschule"); + //cute::setPlotTitle(cute::runtime, "Reutlingen"); + cute::logMessage("Hello CuteLib! :D"); + cute::setProgress(69); + //cute::setPlotVisible(cute::result); + //!cute::statusMessage("Hallo TEC"); + cute::registerAlgorithm(superDummy, "DummyAlgo"); + cute::registerAlgorithm(advancedDummy, "Problem"); + cute::setProblemFile("example.csv"); + cute::setProblemSize(4); + cute::enableAutorun(); +} + +void superDummy() +{ + int prog = 0; + while (cute::ok()) + { + cute::setProgress(prog); + //!cute::statusMessage(std::to_string(prog)); + ++prog; + if (prog > 100) + prog = 0; + + cute::delay(200); + } + //std::string s = "Ended cleanly \\(^-^)/"; + cute::logMessage("Ended cleanly \\(^-^)/"); + cute::setProgress(0); +} + + +std::string fvec2str(std::vector<float> v) +{ + std::string s; + for (size_t i = 0; i < v.size() -1; i++) + { + s += std::to_string(v[i]); + while (s.back() == '0') + { + s.pop_back(); + } + s += ", "; + } + s += std::to_string(v.back()); + while (s.back() == '0') + { + s.pop_back(); + } + return s; +} + +std::string point2str(cute::Point p) +{ + std::string s = "( "; + s += std::to_string(p.x); + while (s.back() == '0') + s.pop_back(); + s += " , "; + s += std::to_string(p.y); + while (s.back() == '0') + s.pop_back(); + s += " )"; + return s; +} + +void advancedDummy() +{ + std::vector<float> problem1D = cute::getProblemData1D(); + cute::logMessage(fvec2str(problem1D)); + std::vector<cute::Point> problem2D = cute::getProblemData2D(); + for (auto &&p : problem2D) + { + cute::logMessage(point2str(p)); + } + + + //!cute::statusMessage("Done already!"); +} diff --git a/examples/studiMain.cpp b/examples/studiMain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1a41b13fc342df839179e03cda8de6d812ed6c9f --- /dev/null +++ b/examples/studiMain.cpp @@ -0,0 +1,155 @@ +#include "cute.h" + + +void superDummy(); +void advancedDummy(); +void bubblesort(); + +// Is run once at startup. +void setup() +{ + cute::setPlotTitle(cute::plot, "Hallo"); + cute::setPlotTitle(cute::result, "Hochschule"); + cute::setPlotTitle(cute::runtime, "Reutlingen"); + cute::logMessage("Hello CuteLib! :D"); + cute::setProgress(69); + cute::setPlotVisible(cute::result); + cute::statusMessage("Hallo TEC"); + cute::registerAlgorithm(superDummy, "DummyAlgo"); + cute::registerAlgorithm(advancedDummy, "Problem"); + cute::registerAlgorithm(bubblesort, "Bubblesort"); + cute::setProblemFile("example.csv"); + cute::setProblemSize(4); + cute::enableAutorun(); +} + +void superDummy() +{ + int prog = 0; + while (cute::ok()) + { + cute::setProgress(prog); + cute::statusMessage(std::to_string(prog)); + if (prog % 10 == 0) + cute::setPlotTheme(prog / 10); + ++prog; + if (prog > 100) + prog = 0; + + cute::delay(200); + } + //std::string s = "Ended cleanly \\(^-^)/"; + cute::logMessage("Ended cleanly \\(^-^)/"); + cute::setProgress(0); +} + + +std::string fvec2str(std::vector<float> v) +{ + std::string s; + for (size_t i = 0; i < v.size() -1; i++) + { + s += std::to_string(v[i]); + while (s.back() == '0') + { + s.pop_back(); + } + s += ", "; + } + s += std::to_string(v.back()); + while (s.back() == '0') + { + s.pop_back(); + } + return s; +} + +std::string point2str(cute::Point p) +{ + std::string s = "( "; + s += std::to_string(p.x); + while (s.back() == '0') + s.pop_back(); + s += " , "; + s += std::to_string(p.y); + while (s.back() == '0') + s.pop_back(); + s += " )"; + return s; +} + +void advancedDummy() +{ + std::vector<float> problem1D = cute::getProblemData1D(); + cute::logMessage(fvec2str(problem1D)); + std::vector<cute::Point> problem2D = cute::getProblemData2D(); + for (auto &&p : problem2D) + { + cute::logMessage(point2str(p)); + } + + + cute::statusMessage("Done already!"); +} + + + +/* +void setup() +{ + using namespace cute; + registerAlgorithm(algorithm, "Bubblesort"); + + setPlotVisible(result, false); + setPlotTitle(plot, "Bubblesort"); + setPlotTitle(runtime, "Laufzeit"); + setPlotScale(runtime, linear, linear); + + setProblemSize(12); // oder setProblemFile("~/my_data.csv"); + enableAutorun(); +} +*/ + +void bubblesort() +{ + using std::vector; + using std::string, std::to_string; + //cute::Timer timer = cute::Timer(); + vector<float> data = cute::getProblemData1D(); + int swaps = 0; + bool did_change = true; + //timer.start(); + while (did_change && cute::ok()) + { + did_change = false; + for (size_t i = 0; i < data.size() - 1; ++i) + { + if (data[i] > data[i+1]) + { + float temp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = temp; + did_change = true; + ++swaps; + //timer.pause(); + //cute::resetPlot(); + //cute::plotValues(data); + cute::logMessage(fvec2str(data)); // + cute::statusMessage(std::to_string(swaps)); + cute::delay(200); + //timer.resume(); + } + } + } + //timer.stop(); + if (cute::ok()) + { + cute::statusMessage("Finished!"); + string s = "Result: " + to_string(data.size()) + " Values sorted with " + to_string(swaps) + " swaps in "/* + to_string(timer.result())*/ + "ms.\n"; + cute::logMessage(s); + //cute::addRuntime(data.size(), timer.result()); + } + else + cute::logMessage(":'("); + return; +} diff --git a/include/cute.h b/include/cute.h new file mode 100644 index 0000000000000000000000000000000000000000..09aad77e111780f335072adcc08e38bb0f078499 --- /dev/null +++ b/include/cute.h @@ -0,0 +1,90 @@ +#ifndef CUTE_H +#define CUTE_H + +#include "dllDefines.h" +#include <vector> +#include <string> +#include <chrono> + +namespace cute +{ + struct Point + { + float x; + float y; + }; + enum Plot + { + plot, + result, + runtime + }; + enum Scale + { + linear, + logarithmic + }; + + void DYNAMIC setPlotVisible(Plot plot, bool visible = true); + void DYNAMIC setPlotTitle(Plot plot, const std::string &title); + void DYNAMIC setPlotScale(Plot plot, Scale x, Scale y); + void DYNAMIC setPlotTheme(int themeNumber); + + void DYNAMIC registerAlgorithm(void (*func)(), const std::string &name); + + void DYNAMIC plotPoints(std::vector<Point>& points); + void DYNAMIC plotValues(std::vector<float> &values); + void DYNAMIC plotLines(std::vector<Point> &points); + void DYNAMIC plotLine(Point &a, Point &b); + void DYNAMIC resetPlot(); + + void DYNAMIC addResult(float result); + void DYNAMIC resetResultPlot(); + + void DYNAMIC addRuntime(int problem_size, std::chrono::duration<float, std::milli> duration); + void DYNAMIC addRuntime(int problem_size, float milliseconds); + void DYNAMIC resetRuntimePlot(); + + void DYNAMIC logMessage(const std::string &message); + void DYNAMIC statusMessage(const std::string &message); + void DYNAMIC setProgress(int percentage); + + const std::vector<float> DYNAMIC &getProblemData1D(); + const std::vector<Point> DYNAMIC &getProblemData2D(); + + void DYNAMIC setProblemFile(const std::string &path); + void DYNAMIC setProblemSize(int n); + void DYNAMIC enableAutorun(bool run = true); + + void DYNAMIC delay(int milliseconds); + + int DYNAMIC run(void (*setup)()); + bool DYNAMIC ok(); + + class Timer + { + public: + void start(); + void pause(); + void resume(); + void stop(); + float result(); + private: + std::chrono::duration<float, std::milli> duration; + }; + + namespace core + { + // These are for loading and unloading libcute.dll at runtime + #if !defined(RUNTIME_LOAD) and !defined(EXPORT_CUTE) + inline int initialize() { return 0; } + inline void shutdown() {} + #else + int initialize(); + void shutdown(); + #endif + } +} + + +#endif //CUTE_H diff --git a/include/dllDefines.h b/include/dllDefines.h new file mode 100644 index 0000000000000000000000000000000000000000..2479871d68ce2acce071d5179e50cd964c39562c --- /dev/null +++ b/include/dllDefines.h @@ -0,0 +1,29 @@ + +#ifdef RUNTIME_LOAD + #define DYNAMIC +#else + #ifndef DYNAMIC + #ifdef EXPORT_CUTE + // Building the library + #ifdef _WIN32 + // Use the Windows-specific export attribute + #define DYNAMIC __declspec(dllexport) + #elif __GNUC__ >= 4 + // Use the GCC-specific export attribute + #define DYNAMIC __attribute__((visibility("default"))) + #else + // Assume that no export attributes are needed + #define DYNAMIC + #endif + #else + // Using (including) the library + #ifdef _WIN32 + // Use the Windows-specific import attribute + #define DYNAMIC __declspec(dllimport) + #else + // Assume that no import attributes are needed + #define DYNAMIC + #endif + #endif + #endif +#endif diff --git a/src/algoThread.h b/src/algoThread.h new file mode 100644 index 0000000000000000000000000000000000000000..665a4fc1c1ae0779a3b9e7920c672eb69120dcb7 --- /dev/null +++ b/src/algoThread.h @@ -0,0 +1,29 @@ +#ifndef ALGOTHREAD_H +#define ALGOTHREAD_H + +#include "cuteControl.h" +#include <QThread> + +class AlgoThread : public QThread +{ +private: + void (*func)(); + +public: + void setAlgorithm(void (*algorithm)()) + { + func = algorithm; + } + void run() override + { + func(); + CuteControl::get().moveToMainThread(); + } +}; + + + + + + +#endif // ALGOTHREAD_H \ No newline at end of file diff --git a/src/chartMenu.cpp b/src/chartMenu.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a15b1c9e089cc6eb5b4b27c9b7820a74597b4ce1 --- /dev/null +++ b/src/chartMenu.cpp @@ -0,0 +1,54 @@ +#include "chartMenu.h" +#include <QCheckBox> +#include <qaction.h> +#include <string> +#include "graphNames.h" + +ChartMenu::ChartMenu(std::vector<QWidget *>& graphingWidgets, QWidget *parent) + : QMenu(parent) +{ + cv = graphingWidgets; + + for (size_t i = 0; i < cv.size(); ++i) + { + QString name = getGraphName(i); + QAction *checkboxAction = new QAction(name, this); + vis.push_back(checkboxAction); + checkboxAction->setCheckable(true); // Make it checkable + checkboxAction->setChecked(!cv[i]->isHidden()); + addAction(checkboxAction); + connect(checkboxAction, &QAction::triggered, this, &ChartMenu::onOptionSelected); + } + connect(this, &QMenu::aboutToShow, this, &ChartMenu::onShow); + themeAction = new QAction("Theme", this); + addAction(themeAction); +} + +void ChartMenu::onShow() +{ + for (size_t i = 0; i < cv.size(); ++i) + { + vis[i]->setChecked(!cv[i]->isHidden()); + } +} + +void ChartMenu::onOptionSelected() +{ + QAction *senderAction = qobject_cast<QAction *>(sender()); + if (senderAction) { + for (size_t i = 0; i < vis.size(); ++i) + { + if (senderAction == vis[i]) + { + cv[i]->setHidden(!senderAction->isChecked()); + } + } + } +} + +void ChartMenu::chartThemeChanged(int themeNumber) +{ + QString s = "Theme: "; + s += std::to_string(themeNumber).c_str(); + themeAction->setText(s); +} diff --git a/src/chartMenu.h b/src/chartMenu.h new file mode 100644 index 0000000000000000000000000000000000000000..11f18826a142183f952fdd245652dc7d6a332a95 --- /dev/null +++ b/src/chartMenu.h @@ -0,0 +1,35 @@ +#ifndef CHARTMENU_H +#define CHARTMENU_H + +#include <QMenu> +#include <QWidget> +#include <vector> + + +class ChartMenu : public QMenu +{ + Q_OBJECT +private: + std::vector<QWidget *> cv; + std::vector<QAction *> vis; + int chartTheme; + + public: + ChartMenu(std::vector<QWidget *>& graphingWidgets, QWidget *parent = nullptr); + QAction *themeAction; + +private slots: + void onShow(); + +public slots: + void onOptionSelected(); + void chartThemeChanged(int themeNumber); +}; + + + + + + + +#endif // CHARTVIEW_H \ No newline at end of file diff --git a/src/configPanel.cpp b/src/configPanel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b30ff8e968cabb03770a8ce32f853a9ff6879ea --- /dev/null +++ b/src/configPanel.cpp @@ -0,0 +1,92 @@ +#include "configPanel.h" +#include <QHBoxLayout> +#include <QStackedWidget> +#include <QLineEdit> +#include <QHBoxLayout> + +ConfigPanel::ConfigPanel(QWidget *parent) + : QDockWidget{parent} +{ + setFeatures(QDockWidget::DockWidgetFeature::DockWidgetMovable); + setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + setTitleBarWidget(new QWidget()); + + QFrame *f = new QFrame(); + setWidget(f); + QHBoxLayout *frameLayout = new QHBoxLayout(); + f->setLayout(frameLayout); + stackedWidget = new QStackedWidget(); + f->layout()->addWidget(stackedWidget); + f->setFrameStyle(QFrame::Panel | QFrame::Raised); + + frameLayout->addStretch(); + + algoBox = new QComboBox(); + f->layout()->addWidget(algoBox); + debugBox = new QComboBox(); + f->layout()->addWidget(debugBox); + debugBox->addItem("All"); + debugBox->addItem("Result"); + debugBox->addItem("None"); + runButton = new QPushButton("Start"); + f->layout()->addWidget(runButton); + + + fileWidget = new QWidget(); + stackedWidget->addWidget(fileWidget); + QHBoxLayout *fileLayout = new QHBoxLayout(); + fileWidget->setLayout(fileLayout); + openButton = new QPushButton("Open..."); + fileWidget->layout()->addWidget(openButton); + fileLine = new QLineEdit("YourFile"); + fileWidget->layout()->addWidget(fileLine); + fileGenerateButton = new QPushButton("Generate"); + fileLayout->addWidget(fileGenerateButton); + fileLayout->addStretch(); + + randomWidget = new QWidget(); + stackedWidget->addWidget(randomWidget); + + QHBoxLayout *randomLayout = new QHBoxLayout(); + randomWidget->setLayout(randomLayout); + problemSizeBox = new QSpinBox(); + randomLayout->addWidget(problemSizeBox); + randomGenerateButton = new QPushButton("Generate"); + randomLayout->addWidget(randomGenerateButton); + randomLayout->addStretch(); + + problemSizeBox->setMinimum(1); + problemSizeBox->setMaximum(INT_MAX); + + stackedWidget->setCurrentWidget(randomWidget); +} + +void ConfigPanel::setRunning(bool running) +{ + if (running) + { + runButton->setText("Stop"); + //TODO setIcon + } + else + { + runButton->setText("Start"); + //TODO setIcon + } +} + +void ConfigPanel::setGenLocked() +{ + randomGenerateButton->setEnabled(false); + randomGenerateButton->setText("Generated"); + fileGenerateButton->setEnabled(false); + fileGenerateButton->setText("Generated"); +} + +void ConfigPanel::setGenUnlocked() +{ + randomGenerateButton->setEnabled(true); + randomGenerateButton->setText("Generate"); + fileGenerateButton->setEnabled(true); + fileGenerateButton->setText("Generate"); +} diff --git a/src/configPanel.h b/src/configPanel.h new file mode 100644 index 0000000000000000000000000000000000000000..43f2e8efc45e2782951ffa810c710174e55e086c --- /dev/null +++ b/src/configPanel.h @@ -0,0 +1,37 @@ +#ifndef CONFIGPANEL_H +#define CONFIGPANEL_H + +#include <QDockWidget> +#include <QPushButton> +#include <QSpinBox> +#include <QCheckBox> +#include <QComboBox> +#include <QStackedWidget> + +class ConfigPanel : public QDockWidget +{ + Q_OBJECT + +public: + QPushButton *runButton; + QPushButton *openButton; + QPushButton *randomGenerateButton; + QPushButton *fileGenerateButton; + QLineEdit *fileLine; + QComboBox *algoBox; + QSpinBox *problemSizeBox; + QComboBox *debugBox; + QStackedWidget *stackedWidget; + QWidget *fileWidget; + QWidget *randomWidget; + +public: + explicit ConfigPanel(QWidget *parent = nullptr); + +public slots: + void setRunning(bool running); + void setGenLocked(); + void setGenUnlocked(); +}; + +#endif // CONFIGPANEL_H diff --git a/src/control.cpp b/src/control.cpp new file mode 100644 index 0000000000000000000000000000000000000000..69f339c2df1428a1761660ab5de7443800073374 --- /dev/null +++ b/src/control.cpp @@ -0,0 +1,193 @@ +#include "control.h" +#include "cuteControl.h" +#include "algoThread.h" +#include "mainWindow.h" + +#include <QString> +#include <QChartView> +#include <QComboBox> +#include <QLineEdit> +#include <random> + +void Control::makeConnections() +{ + CuteControl *cc = &CuteControl::get(); + connect(cc, &CuteControl::s_setProgress, this, &Control::setProgress); + connect(cc, &CuteControl::s_logMessage, this, &Control::logMessage); + connect(cc, &CuteControl::s_statusMessage, this, &Control::statusMessage); + connect(cc, &CuteControl::s_setPlotVisible, this, &Control::setPlotVisible); + connect(cc, &CuteControl::s_setPlotTitle, this, &Control::setPlotTitle); + connect(cc, &CuteControl::s_setPlotTheme, this, &Control::setPlotTheme); + connect(cc, &CuteControl::s_enableAutorun, this, &Control::enableAutorun); + connect(cc, &CuteControl::s_setProblemSize, this, &Control::setProblemSize); + connect(cc, &CuteControl::s_setProblemFile, this, &Control::setProblemFile); + connect(this, &Control::endThread, cc, &CuteControl::end); + connect(w->configPanel->runButton, &QPushButton::clicked, this, &Control::onRunButton); + connect(w->configPanel->fileGenerateButton, &QPushButton::clicked, this, &Control::onGenerateButton); + connect(w->configPanel->randomGenerateButton, &QPushButton::clicked, this, &Control::onGenerateButton); + connect(w->configPanel->fileLine, &QLineEdit::textChanged, this, &Control::onProblemSettingChanged); + connect(w->configPanel->problemSizeBox, &QSpinBox::textChanged, this, &Control::onProblemSettingChanged); +} + +int Control::run(void (*userSetup)()) +{ + static bool running = false; + if (!running) + { + running = true; + int argc = 1; + char* argv[] = { (char*)"AppName" }; + QApplication a(argc, argv); + auto Mw = MainWindow(); + w = &Mw; + + makeConnections(); + + userSetup(); + w->show(); + if (autorun) + startThread(algorithms.front().first); + int result = a.exec(); + running = false; + return result; + } + else + return -1; +} + +void Control::logMessage(const QString message) +{ + w->textEdit->append(message); +} + +void Control::setProgress(int percentage) +{ + w->progressBar->setValue(percentage); +} + +void Control::statusMessage(const QString message) +{ + w->statusBar->showMessage(message, 5000); +} + +void Control::setPlotVisible(int plot, bool visible) +{ + w->graphingWidgets[plot]->setHidden(!visible); +} + +void Control::setPlotTitle(int plot, const QString title) +{ + w->charts[plot]->setTitle(title); +} + +void Control::setPlotTheme(int themeNumber) +{ + w->changeChartTheme(themeNumber); +} + + +void Control::registerAlgorithm(void (*func)(), const QString name) +{ + algorithms.emplace_back(func, name); + w->addAlgorithm(name); +} + +void Control::stopThread() +{ + if (thread) + { + emit endThread(); + } +} + +void Control::threadEnded() +{ + threadRunning = false; + w->configPanel->setRunning(false); + thread = nullptr; +} + +void Control::startThread(void (*func)()) +{ + if (!thread) + { + thread = new AlgoThread(); + thread->setAlgorithm(func); + + connect(thread, &AlgoThread::finished, thread, &QObject::deleteLater); + connect(thread, &AlgoThread::finished, this, &Control::threadEnded); + CuteControl::get().setProblem(getProblem()); + CuteControl::get().moveToWorkerThread(thread); + w->configPanel->setRunning(true); + threadRunning = true; + thread->start(); + logMessage("Running..."); + } +} + +void Control::onRunButton() +{ + if (!thread) + { + int index = w->configPanel->algoBox->currentIndex(); + auto func = algorithms[index].first; + startThread(func); + } + else + { + stopThread(); + } +} + +void Control::setProblemSize(int n) +{ + w->configPanel->stackedWidget->setCurrentWidget(w->configPanel->randomWidget); + w->configPanel->problemSizeBox->setValue(n); +} + +void Control::setProblemFile(QString path) +{ + w->configPanel->stackedWidget->setCurrentWidget(w->configPanel->fileWidget); + w->configPanel->fileLine->setText(path); +} + +std::vector<cute::Point> Control::getProblem() +{ + if (!problemRetained) + { + generateProblem(); + } + return problem; +} + +void Control::generateProblem() +{ + problem.clear(); + if (w->configPanel->stackedWidget->currentWidget() == w->configPanel->randomWidget) + { + int problemSize = w->configPanel->problemSizeBox->value(); + problem.reserve(problemSize); + for (int i = 0; i < problemSize; ++i) + { + std::random_device rd = std::random_device(); + problem.emplace_back(cute::Point{(float)(rd() % 100), (float)(rd() % 100)}); + } + } + else if (w->configPanel->stackedWidget->currentWidget() == w->configPanel->fileWidget) + { + //TODO file.csv + } +} + +void Control::onGenerateButton() +{ + generateProblem(); + problemRetained = true; + w->configPanel->setGenLocked(); +} + +void Control::onProblemSettingChanged([[maybe_unused]] const QString &text) +{ + problemRetained = false; + w->configPanel->setGenUnlocked(); +} diff --git a/src/control.h b/src/control.h new file mode 100644 index 0000000000000000000000000000000000000000..382486f1c40fc2b59630160cdc9e05d633d34e27 --- /dev/null +++ b/src/control.h @@ -0,0 +1,66 @@ +#ifndef CONTROL_H +#define CONTROL_H + +#include "mainWindow.h" +#include "algoThread.h" +#include <QApplication> +#include <QObject> + + + + +class Control : public QObject +{ + Q_OBJECT +private: + Control() {} + virtual ~Control() { stopThread(); } + MainWindow *w; + std::vector<std::pair<void(*)(), QString>> algorithms; + bool threadRunning; + bool autorun; + AlgoThread *thread; + void startThread(void (*func)()); + void makeConnections(); + bool problemRetained; + std::vector<cute::Point> problem; + void generateProblem(); + std::vector<cute::Point> getProblem(); + +public: + static Control &getInstance() + { + static Control instance; + return instance; + } + static Control &get() { return getInstance(); } + int run(void (*setup)()); + void registerAlgorithm(void (*func)(), const QString name); +public slots: + void enableAutorun(bool run) { autorun = run; } + void stopThread(); + void threadEnded(); + void setProgress(int percentage); + void statusMessage(const QString message); + void logMessage(const QString message); + void setPlotVisible(int plot, bool visible); + void setPlotTitle(int plot, const QString title); + void setPlotTheme(int themeNumber); + void onRunButton(); + void onGenerateButton(); + void setProblemSize(int n); + void setProblemFile(QString path); + void onProblemSettingChanged(const QString &text); + +signals: + void endThread(); +}; + + + + + + + + +#endif //CONTROL_H diff --git a/src/cute.cpp b/src/cute.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2ee83f72f2180cc5724aa69d0a0f29d783621e35 --- /dev/null +++ b/src/cute.cpp @@ -0,0 +1,127 @@ +#include "cute.h" +#include "cuteControl.h" +#include "control.h" + +void cute::setPlotVisible(Plot plot, bool visible) +{ + CuteControl::get().setPlotVisible((int)plot, visible); +} + +void cute::setPlotTitle(Plot plot, const std::string &title) +{ + CuteControl::get().setPlotTitle((int)plot, title); +} + +/* +void cute::setPlotScale(Plot plot, Scale x, Scale y); +*/ +void cute::setPlotTheme(int themeNumber) +{ + CuteControl::get().setPlotTheme(themeNumber); +} + + +void cute::registerAlgorithm(void (*func)(), const std::string &name) +{ + Control::get().registerAlgorithm(func, name.c_str()); +} + + +/* +void cute::plotPoints(std::vector<Point>& points); + +void cute::plotValues(std::vector<float> &values); + +void cute::plotLines(std::vector<Point> &points); + +void cute::plotLine(Point &a, Point &b); + +void cute::resetPlot(); + + +void cute::addResult(float result); + +void cute::resetResultPlot(); + + +void cute::addRuntime(std::chrono::duration<float, std::milli> duration, int problem_size); + +void cute::addRuntime(float milliseconds, int problem_size); + +void cute::resetRuntimePlot(); +*/ + + +void cute::logMessage(const std::string &message) +{ + CuteControl::get().logMessage(message); +} + +void cute::statusMessage(const std::string &message) +{ + CuteControl::get().statusMessage(message); +} + +void cute::setProgress(int percentage) +{ + CuteControl::get().setProgress(percentage); +} + + +const std::vector<float> &cute::getProblemData1D() +{ + return CuteControl::get().getData1D(); +} + +const std::vector<cute::Point> &cute::getProblemData2D() +{ + return CuteControl::get().getData2D(); +} + + +void cute::setProblemFile(const std::string &path) +{ + CuteControl::get().setProblemFile(path); +} + +void cute::setProblemSize(int n) +{ + CuteControl::get().setProblemSize(n); +} + +void cute::enableAutorun(bool run) +{ + CuteControl::get().enableAutorun(run); +} + + +void cute::delay(int milliseconds) +{ + QThread::msleep(milliseconds); +} + + +int cute::run(void (*setup)()) +{ + return Control::get().run(setup); +} + +bool cute::ok() +{ + return !CuteControl::get().endRequested(); +} + +/* +class Timer +{ + public: + void start(); + void pause(); + void resume(); + void stop(); + float result(); + private: + std::chrono::duration<float, std::milli> duration; +}; +*/ + diff --git a/src/cute.def b/src/cute.def new file mode 100644 index 0000000000000000000000000000000000000000..a1129b168b491b08be9a1f9312e06c7e985d0cd4 --- /dev/null +++ b/src/cute.def @@ -0,0 +1,17 @@ +LIBRARY cute +EXPORTS + logMessage=_ZN4cute10logMessageERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE + setProgress=_ZN4cute11setProgressEi + _ZN4cute12setPlotTitleENS_4PlotERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE + setPlotTheme=_ZN4cute12setPlotThemeEi + enableAutorun=_ZN4cute13enableAutorunEb + _ZN4cute13statusMessageERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE + _ZN4cute14setPlotVisibleENS_4PlotEb + setProblemFile=_ZN4cute14setProblemFileERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEE + setProblemSize=_ZN4cute14setProblemSizeEi + getProblemData1D=_ZN4cute16getProblemData1DEv + getProblemData2D=_ZN4cute16getProblemData2DEv + registerAlgorithm=_ZN4cute17registerAlgorithmEPFvvERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE + ok=_ZN4cute2okEv + run=_ZN4cute3runEPFvvE + delay=_ZN4cute5delayEi diff --git a/src/cuteControl.cpp b/src/cuteControl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d30049503e365334c3babe77d0851f661d404f0 --- /dev/null +++ b/src/cuteControl.cpp @@ -0,0 +1,3 @@ +#include "cuteControl.h" + + diff --git a/src/cuteControl.h b/src/cuteControl.h new file mode 100644 index 0000000000000000000000000000000000000000..5df716f9973f04a9d66c3615195af26287692759 --- /dev/null +++ b/src/cuteControl.h @@ -0,0 +1,148 @@ +#ifndef CUTECONTROL_H +#define CUTECONTROL_H + +#include "cute.h" +#include <QObject> +#include <QString> +#include <QApplication> + + +class CuteControl : public QObject +{ + Q_OBJECT +private: + CuteControl() {} + bool endThread; + bool runningInThread; + std::vector<cute::Point> problem2D; + std::vector<float> problem1D; + +signals: + void s_setProgress(int n); + void s_logMessage(QString message); + void s_statusMessage(QString message); + void s_setPlotTitle(int plot, QString title); + void s_setPlotVisible(int plot, bool visible); + void s_enableAutorun(bool run); + void s_setProblemSize(int n); + void s_setProblemFile(QString path); + void s_setPlotTheme(int themeNumber); + +public: + static CuteControl &getInstance() + { + static CuteControl instance; + return instance; + } + static CuteControl &get() { return getInstance(); } + + void moveToMainThread() + { + moveToThread(QApplication::instance()->thread()); + runningInThread = false; + endThread = false; + } + void moveToWorkerThread(QThread *thread) + { + moveToThread(thread); + runningInThread = true; + } +public: + void setProgress(int percentage) + { + emit s_setProgress(percentage); + } + bool endRequested() + { + QApplication::processEvents(); + return endThread; + } + void logMessage(const std::string &message) + { + emit s_logMessage(message.c_str()); + } + void statusMessage(const std::string &message) + { + emit s_statusMessage(message.c_str()); + } + void setPlotTheme(int themeNumber) + { + emit s_setPlotTheme(themeNumber); + } + + void setPlotTitle(int plot, const std::string &title) + { + emit s_setPlotTitle(plot, title.c_str()); + } + + void setPlotVisible(int plot, bool visible) + { + emit s_setPlotVisible(plot, visible); + + } + void enableAutorun(bool run) + { + emit s_enableAutorun(run); + } + void setProblemSize(int n) + { + emit s_setProblemSize(n); + } + void setProblemFile(const std::string &path) + { + emit s_setProblemFile(path.c_str()); + } + const std::vector<float> &getData1D() + { + return problem1D; + } + const std::vector<cute::Point> &getData2D() + { + return problem2D; + } + void setProblem(const std::vector<cute::Point> &problemVector) + { + if(!runningInThread) + { + problem2D = problemVector; + problem1D.clear(); + problem1D.reserve(problemVector.size()); + for (auto &&point : problemVector) + { + problem1D.push_back(point.x); + } + } + } + +public slots: + void end() + { + endThread = true; + } + +public: + +}; + + + + + + + + + + + + + + + + + + + + + + +#endif // CUTECONTROL_H \ No newline at end of file diff --git a/src/cuteImporter.cpp b/src/cuteImporter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bf0b6c86c37cc8f63333cd689ac8374bf9e53e73 --- /dev/null +++ b/src/cuteImporter.cpp @@ -0,0 +1,149 @@ +#include "cute.h" +#include <windows.h> + +namespace { + // Private variables to hold the DLL handle and function pointers + // Anonymous namespace will not be visible outside of this translation unit + HINSTANCE hDll = nullptr; + + typedef void (*t_setProgress)(int); + typedef void (*t_logMessage)(const std::string&); + typedef void (*t_enableAutorun)(bool); + typedef void (*t_setProblemFile)(const std::string&); + typedef void (*t_setProblemSize)(int); + typedef void (*t_registerAlgorithm)(void (*)(), const std::string&); + typedef void (*t_delay)(int); + typedef int (*t_run)(void (*)()); + typedef bool (*t_ok)(); + typedef const std::vector<float> &(*t_getProblemData1D)(); + typedef const std::vector<cute::Point> &(*t_getProblemData2D)(); + + t_setProgress setProgressImpl = nullptr; + t_logMessage logMessageImpl = nullptr; + t_enableAutorun enableAutorunImpl = nullptr; + t_setProblemFile setProblemFileImpl = nullptr; + t_setProblemSize setProblemSizeImpl = nullptr; + t_registerAlgorithm registerAlgorithmImpl = nullptr; + t_delay delayImpl = nullptr; + t_run runImpl = nullptr; + t_ok okImpl = nullptr; + t_getProblemData1D getProblemData1DImpl = nullptr; + t_getProblemData2D getProblemData2DImpl = nullptr; +} + +// Function implementations hidden from the user +namespace cute { + int core::initialize() { + hDll = LoadLibrary("cute.dll"); + if (!hDll) { + return -2; + } + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcast-function-type" + //#pragma GCC diagnostic ignored "-Wcast-function-type" + // your code for which the warning gets suppressed + setProgressImpl = reinterpret_cast<t_setProgress>(GetProcAddress(hDll, "setProgress")); + logMessageImpl = reinterpret_cast<t_logMessage>(GetProcAddress(hDll, "logMessage")); + enableAutorunImpl = reinterpret_cast<t_enableAutorun>(GetProcAddress(hDll, "enableAutorun")); + setProblemFileImpl = reinterpret_cast<t_setProblemFile>(GetProcAddress(hDll, "setProblemFile")); + setProblemSizeImpl = reinterpret_cast<t_setProblemSize>(GetProcAddress(hDll, "setProblemSize")); + registerAlgorithmImpl = reinterpret_cast<t_registerAlgorithm>(GetProcAddress(hDll, "registerAlgorithm")); + delayImpl = reinterpret_cast<t_delay>(GetProcAddress(hDll, "delay")); + runImpl = reinterpret_cast<t_run>(GetProcAddress(hDll, "run")); + okImpl = reinterpret_cast<t_ok>(GetProcAddress(hDll, "ok")); + getProblemData1DImpl = reinterpret_cast<t_getProblemData1D>(GetProcAddress(hDll, "getProblemData1D")); + getProblemData2DImpl = reinterpret_cast<t_getProblemData2D>(GetProcAddress(hDll, "getProblemData2D")); + #pragma clang diagnostic pop + //#pragma GCC diagnostic pop + + // By checking here, we can spare any future checks and if we exit main() on any errors, we can spare us any exception handling. + if ( + setProgressImpl && + logMessageImpl && + enableAutorunImpl && + setProblemFileImpl && + setProblemSizeImpl && + registerAlgorithmImpl && + delayImpl && + runImpl && + okImpl && + getProblemData1DImpl && + getProblemData2DImpl + ) + { + return 0; + } + else + { + FreeLibrary(hDll); + hDll = nullptr; + return -3; + } + } + + void setProgress(int percentage) + { + return setProgressImpl(percentage); + } + void logMessage(const std::string &message) + { + return logMessageImpl(message); + } + void enableAutorun(bool run) + { + return enableAutorunImpl(run); + } + void setProblemFile(const std::string &path) + { + return setProblemFileImpl(path); + } + void setProblemSize(int n) + { + return setProblemSizeImpl(n); + } + void registerAlgorithm(void (*func)(), const std::string &name) + { + return registerAlgorithmImpl(func, name); + } + void delay(int milliseconds) + { + return delayImpl(milliseconds); + } + int run(void (*setup)()) + { + return runImpl(setup); + } + bool ok() + { + return okImpl(); + } + const std::vector<float> &getProblemData1D() + { + return getProblemData1DImpl(); + } + const std::vector<cute::Point> &getProblemData2D() + { + return getProblemData2DImpl(); + } + + void core::shutdown() + { + if (hDll) + { + FreeLibrary(hDll); + hDll = nullptr; + setProgressImpl = nullptr; + logMessageImpl = nullptr; + enableAutorunImpl = nullptr; + setProblemFileImpl = nullptr; + setProblemSizeImpl = nullptr; + registerAlgorithmImpl = nullptr; + delayImpl = nullptr; + runImpl = nullptr; + okImpl = nullptr; + getProblemData1DImpl = nullptr; + getProblemData2DImpl = nullptr; + } + } +} + diff --git a/src/graphNames.cpp b/src/graphNames.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aa21e041cc12f194171786097c7c2e0056a123ab --- /dev/null +++ b/src/graphNames.cpp @@ -0,0 +1,13 @@ +#include "graphNames.h" + +#include <array> + +QString getGraphName(int index) +{ + constexpr std::array<const char *, 3> names = + { + "MainPlot", + "Result", + "Runtime"}; + return names[index]; +} diff --git a/src/graphNames.h b/src/graphNames.h new file mode 100644 index 0000000000000000000000000000000000000000..a0ab4388dd874d2205a306492769b78ff85e1814 --- /dev/null +++ b/src/graphNames.h @@ -0,0 +1,9 @@ +#ifndef GRAPHNAMES_H +#define GRAPHNAMES_H + +#include <QString> + +QString getGraphName(int index); + + +#endif // GRAPHNAMES_H \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..afd8e81c95e8a1f36d2db2b22612d999810a1baa --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,12 @@ +#include "cute.h" + +extern void setup(); + +int main() +{ + if (cute::core::initialize() != 0) + return 1; + int r = cute::run(setup); + cute::core::shutdown(); + return r; +} diff --git a/src/mainWindow.cpp b/src/mainWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..71c975b0cbd6ec7ee353c360c79ad8406fa946fe --- /dev/null +++ b/src/mainWindow.cpp @@ -0,0 +1,243 @@ +#include "mainWindow.h" +#include "configPanel.h" +#include "chartMenu.h" +#include "graphNames.h" +#include <QMenuBar> +#include <QMenu> +#include <QBoxLayout> +#include <QSplitter> +#include <QFontDatabase> +#include <QTableView> +#include <QTableWidget> +#include <QLabel> +#include <QToolbar> +#include <QSpinBox> +#include <QLineEdit> +#include <QDockWidget> +#include <QStackedWidget> +#include <QSizePolicy> +#include <QChartView.h> +#include <QProxyStyle> +#include <QChart> + +MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) +{ + configPanel = new ConfigPanel(); + addDockWidget(Qt::DockWidgetArea::TopDockWidgetArea, configPanel); + setDockOptions(DockOption::AnimatedDocks); + setDockNestingEnabled(false); + + + + + + /*QTableWidget *T = new QTableWidget(400, 400); + grL->addWidget(T); + T->setLineWidth(0); + T->resizeColumnsToContents(); + T->resizeRowsToContents(); + for (size_t i = 0; i < 400; i++) + { + T->setRowHeight(i, 1); + T->setColumnWidth(i, 1); + }*/ + + setupMenuBar(); + setupStatusBar(); + setupCharts(); + + /*QToolBar *rtb = new QToolBar("random"); + // tb->setFloatable(); + QToolBar *ftb = new QToolBar("file"); + addToolBar(Qt::ToolBarArea::TopToolBarArea, rtb); + addToolBar(Qt::ToolBarArea::TopToolBarArea, ftb); + + rtb->addWidget(new QDoubleSpinBox()); + rtb->addWidget(new QPushButton("Generate")); + ftb->addWidget(new QLineEdit("YourFile")); + ftb->addWidget(new QPushButton("Generate")); + ftb->setLayoutDirection(Qt::LayoutDirection::LeftToRight); + QWidget *sprW1 = new QWidget(); + sprW1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + ftb->addWidget(sprW1); + ftb->addWidget(new QPushButton("Go")); + QWidget *sprW2 = new QWidget(); + sprW2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + rtb->addWidget(sprW2); + rtb->addWidget(new QPushButton("Go")); + + QToolBar *ssb = new QToolBar("ssb"); + ssb->setLayoutDirection(Qt::LayoutDirection::LeftToRight); + ssb->addWidget(new QPushButton("[ ] Start")); + addToolBar(Qt::ToolBarArea::TopToolBarArea, ssb); + ssb->addSeparator(); + rtb->setFloatable(false); + //rtb->setMovable(false); + //ftb->setFloatable(false); + //ftb->setMovable(false); + ssb->setFloatable(false); + //ssb->setMovable(false); + //rtb->hide(); + rtb->addSeparator();*/ + + QDockWidget *tdw = new QDockWidget("Output"); + textEdit = new QTextEdit(); + tdw->setWidget(textEdit); + addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, tdw); + tdw->setAllowedAreas(Qt::DockWidgetArea::BottomDockWidgetArea | Qt::DockWidgetArea::RightDockWidgetArea | Qt::DockWidgetArea::LeftDockWidgetArea); + + textEdit->setReadOnly(true); + QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + textEdit->setCurrentFont(fixedFont); + textEdit->setFontPointSize(12); +} + +void MainWindow::setupMenuBar() +{ + QMenuBar* menubar = new QMenuBar(); + setMenuBar(menubar); + QMenu* probM = new QMenu("Problem"); + menubar->addMenu(probM); + + probMenuRandom = new QAction("Random", this); + probMenuRandom->setCheckable(true); + probMenuRandom->setChecked(true); + probMenuRandom->setDisabled(true); + probM->addAction(probMenuRandom); + connect(probMenuRandom, &QAction::triggered, this, &MainWindow::switchToRandom); + + probMenuFile = new QAction("File", this); + probMenuFile->setCheckable(true); + probMenuFile->setChecked(false); + probM->addAction(probMenuFile); + connect(probMenuFile, &QAction::triggered, this, &MainWindow::switchToFile); + + QAction *probSave = new QAction("Save...", this); + probM->addAction(probSave); + connect(probSave, &QAction::triggered, this, &MainWindow::saveProblem); + + cm = new ChartMenu(graphingWidgets); + cm->setTitle("Charts"); + menubar->addMenu(cm); + connect(cm->themeAction, &QAction::triggered, this, &MainWindow::incrementChartTheme); +} + +void MainWindow::switchToFile() +{ + probMenuFile->setChecked(true); + probMenuRandom->setChecked(false); + probMenuFile->setDisabled(true); + probMenuRandom->setDisabled(false); + configPanel->stackedWidget->setCurrentWidget(configPanel->fileWidget); +} + +void MainWindow::switchToRandom() +{ + probMenuFile->setChecked(false); + probMenuRandom->setChecked(true); + probMenuFile->setDisabled(false); + probMenuRandom->setDisabled(true); + configPanel->stackedWidget->setCurrentWidget(configPanel->randomWidget); +} + + + +void MainWindow::setupCharts() +{ + QWidget* grW = new QWidget(); + setCentralWidget(grW); + QHBoxLayout *layout = new QHBoxLayout(); + grW->setLayout(layout); + + for (size_t i = 0; i < 3; i++) + { + QtCharts::QChartView *v = new QtCharts::QChartView(); + graphingWidgets.push_back(v); + layout->addWidget(v, 1); + + QtCharts::QChart *c = new QtCharts::QChart(); + charts.push_back(c); + v->setChart(c); + c->setTitle(getGraphName(i)); + c->legend()->setVisible(true); + c->setMinimumSize(300, 300); + } + changeChartTheme((int)QtCharts::QChart::ChartTheme::ChartThemeBlueCerulean); +} + +void MainWindow::addAlgorithm(const QString &name) +{ + configPanel->algoBox->addItem(name); +} + + +void MainWindow::setupStatusBar() +{ + statusBar = new QStatusBar(); + setStatusBar(statusBar); + progressBar = new QProgressBar(); + statusBar->addPermanentWidget(progressBar); + statusBar->showMessage("Ready..."); + progressBar->setMinimum(0); + progressBar->setMaximum(100); + progressBar->setValue(0); +} + +void MainWindow::changeChartTheme(int themeNumber) { + if (themeNumber > 7 || themeNumber < 0) { + return; + } + cm->chartThemeChanged(themeNumber); + for (QtCharts::QChart* chart : charts) { + chart->setTheme((QtCharts::QChart::ChartTheme)themeNumber); + } +} + +void MainWindow::incrementChartTheme() { + int n = (int)charts.front()->theme(); + ++n; + if (n > 7) { + n = 0; + } + changeChartTheme(n); +} + + + + + +/* +#include <QApplication> +#include <QGraphicsView> +#include <QGraphicsScene> +#include <QGraphicsRectItem> +#include <QPen> + +class GridView : public QGraphicsView { +public: + GridView(QWidget *parent = nullptr) : QGraphicsView(parent) { + scene = new QGraphicsScene(this); + setScene(scene); + initGrid(); + } + +private: + QGraphicsScene *scene; + + void initGrid() { + int gridSize = 400; + int cellSize = 1; // Adjust for visibility + QPen pen(Qt::darkGreen); // Grid line color + + for (int row = 0; row < gridSize; ++row) { + for (int col = 0; col < gridSize; ++col) { + QGraphicsRectItem *rect = new QGraphicsRectItem(col * cellSize, row * cellSize, cellSize, cellSize); + rect->setPen(pen); + scene->addItem(rect); + } + } + + //setFixedSize(gridSize * cellSize, gridSize * cellSize); + } +}; +}*/ diff --git a/src/mainWindow.h b/src/mainWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..86ebb25bc904139a1529f58df4c86973875b86fa --- /dev/null +++ b/src/mainWindow.h @@ -0,0 +1,51 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include <QMainWindow> +#include <QTextEdit> +#include <QStatusBar> +#include <QProgressBar> +#include <QChartView> +#include <QChart> +#include "chartMenu.h" +#include "configPanel.h" + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +private: + QAction *probMenuFile; + QAction *probMenuRandom; + ChartMenu *cm; + void incrementChartTheme(); + +public: + MainWindow(QWidget *parent = nullptr); + + QStatusBar* statusBar; + QProgressBar *progressBar; + QTextEdit *textEdit; + ConfigPanel *configPanel; + + std::vector<QWidget *> graphingWidgets; + std::vector<QtCharts::QChart *> charts; + + void addAlgorithm(const QString &name); + +private: + void setupStatusBar(); + void setupMenuBar(); + void setupCharts(); + +public slots: + void switchToFile(); + void switchToRandom(); + void changeChartTheme(int themeNumber); + +signals: + void saveProblem(); + +}; + +#endif // MAINWINDOW_H