From 7b0c124f36748b4d821c45078ee84c34075e13cb Mon Sep 17 00:00:00 2001 From: Valery Date: Tue, 17 Sep 2024 12:57:15 +0300 Subject: [PATCH] Gui qt (#129) --- !Format + one_header.bat | 2 + CMakeLists.txt | 6 +- Tests/ArrayCoreTest.cpp | 40 ++- Tests/CMakeLists.txt | 4 +- Tests/CommonUtilsTest.cpp | 48 +++- array_core/array_core.h | 95 +++++-- array_core/configurator.h | 4 +- auto_format.bat | 2 +- common_utils/common_utils.cpp | 73 ++++- common_utils/common_utils.h | 64 ++++- davis_one/davis.cpp | 135 +++++++-- davis_one/davis.h | 166 ++++++++--- gui/CMakeLists.txt | 78 ++++++ gui/about_window.cpp | 83 ++++++ gui/about_window.h | 39 +++ gui/about_window.ui | 264 ++++++++++++++++++ gui/davis_gui.cpp | 174 ++++++++++++ gui/davis_gui.h | 37 +++ gui/davis_gui.ui | 136 +++++++++ gui/main.cpp | 52 ++++ gui/qrc_files_restorer.cpp | 24 ++ gui/qrc_files_restorer.h | 17 ++ gui/res.qrc | 13 + gui/res/Davis.png | Bin 0 -> 52938 bytes .../DevToolsDavis-updown-curves - gray.svg | 36 +++ ...00dp_969696_FILL0_wght300_GRAD0_opsz48.png | Bin 0 -> 17597 bytes ...00dp_969696_FILL0_wght300_GRAD0_opsz48.png | Bin 0 -> 16461 bytes ...00dp_969696_FILL0_wght300_GRAD0_opsz48.png | Bin 0 -> 23339 bytes gui/res/davis.mp3 | Bin 0 -> 3361581 bytes ...00dp_969696_FILL0_wght300_GRAD0_opsz48.png | Bin 0 -> 22753 bytes ...00dp_969696_FILL0_wght300_GRAD0_opsz48.png | Bin 0 -> 20950 bytes make_one_header.bat | 4 + plotly_maker/html_parts.cpp | 2 +- plotly_maker/html_parts.h | 1 + plotly_maker/plotly_maker.cpp | 58 ++-- plotly_maker/plotly_maker.h | 2 + 36 files changed, 1527 insertions(+), 132 deletions(-) create mode 100644 !Format + one_header.bat create mode 100644 gui/CMakeLists.txt create mode 100644 gui/about_window.cpp create mode 100644 gui/about_window.h create mode 100644 gui/about_window.ui create mode 100644 gui/davis_gui.cpp create mode 100644 gui/davis_gui.h create mode 100644 gui/davis_gui.ui create mode 100644 gui/main.cpp create mode 100644 gui/qrc_files_restorer.cpp create mode 100644 gui/qrc_files_restorer.h create mode 100644 gui/res.qrc create mode 100644 gui/res/Davis.png create mode 100644 gui/res/DevToolsDavis-updown-curves - gray.svg create mode 100644 gui/res/check_200dp_969696_FILL0_wght300_GRAD0_opsz48.png create mode 100644 gui/res/chevron_right_200dp_969696_FILL0_wght300_GRAD0_opsz48.png create mode 100644 gui/res/content_copy_200dp_969696_FILL0_wght300_GRAD0_opsz48.png create mode 100644 gui/res/davis.mp3 create mode 100644 gui/res/description_200dp_969696_FILL0_wght300_GRAD0_opsz48.png create mode 100644 gui/res/finance_200dp_969696_FILL0_wght300_GRAD0_opsz48.png create mode 100644 make_one_header.bat diff --git a/!Format + one_header.bat b/!Format + one_header.bat new file mode 100644 index 0000000..bdb2f4b --- /dev/null +++ b/!Format + one_header.bat @@ -0,0 +1,2 @@ +call auto_format.bat +call make_one_header.bat \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 4300005..e70becc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,10 @@ add_subdirectory(plotly_maker) add_subdirectory(array_core) add_subdirectory(common_utils) + +add_subdirectory(gui) + + set(HEADER_FILES davis.h) # tests @@ -23,7 +27,7 @@ enable_testing() add_subdirectory(Tests) include_directories(${RESOURCE_MANAGER_INCLUDE_DIRS}) -rm_embed_resources(RESOURCES "plotly_maker/plotly-2.27.0.min.js") +rm_embed_resources(RESOURCES "plotly_maker/plotly-2.32.0.min.js") add_executable("davis_launcher" davis_launcher.cpp davis.h) diff --git a/Tests/ArrayCoreTest.cpp b/Tests/ArrayCoreTest.cpp index 8d85e76..192863b 100644 --- a/Tests/ArrayCoreTest.cpp +++ b/Tests/ArrayCoreTest.cpp @@ -35,8 +35,8 @@ TEST(ArrayCore, save_to_disk_pseudo_2d) { } } dv::configSaveToDisk conf; - conf.separatorOfCols = "*"; - conf.separatorOfRows = "____"; + conf.separatorOfCols = ";"; + conf.separatorOfRows = "\n"; bool result = dv::save(vals, rows, cols, "./data/test_saving_save_to_disk_pseudo_2d.csv", conf); EXPECT_EQ(result, true); } @@ -78,6 +78,20 @@ TEST(ArrayCore, save_to_disk_container2D) { EXPECT_EQ(result, true); } +TEST(ArrayCore, save_to_disk_XYdata) { + //! 1-dimensional container + vector vecX; + for (size_t i = 0; i < 10; ++i) { + vecX.emplace_back(i * 2); + } + vector vecY; + for (size_t i = 0; i < 10; ++i) { + vecY.emplace_back(i * 3); + } + bool result = dv::save(vecX, vecY, "./data/test_saving_save_to_disk_XYdata.csv"); + EXPECT_EQ(result, true); +} + TEST(ArrayCore, universal_1d_conteiner) { EXPECT_EQ(dvs::isPlotlyScriptExists(), true); std::list vec = {5, 34}; @@ -193,6 +207,28 @@ TEST(ArrayCore, showChart) { EXPECT_EQ(result, true); } +TEST(ArrayCore, showChartXYfromContainerOfConteiners) { + vector> values; + vector vecX = {5, 20, 21, 22, 50}; + vector vecY = {1, 2, 3, 4, 5}; + values.emplace_back(vecX); + values.emplace_back(vecY); + auto config = dv::Config(); + config.chart.title = "ChartXY"; + config.chart.xLabel = "xLabel"; + config.chart.yLabel = "yLabel"; + bool result = dv::show(values, "showChartXY_ContainerOfContainers", config); + EXPECT_EQ(result, true); +} + +TEST(ArrayCore, showChartXYfrom2Containers) { + vector> values; + vector vecX = {5, 20, 21, 22, 50}; + vector vecY = {1, 2, 3, 4, 5}; + bool result = dv::show(vecX, vecY, "showChartXY_2containers"); + EXPECT_EQ(result, true); +} + TEST(ArrayCore, readAndShowMatrixFromFile) { EXPECT_EQ(dvs::isPlotlyScriptExists(), true); vector> values; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index e47c41f..65a5a45 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -11,9 +11,9 @@ set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # Windows specific, for goog # Copy plotly java script to tests MESSAGE("_____________________ Copy Plotlylib to Tests step ___________________________________________") if(WIN32) -file(COPY ${CMAKE_SOURCE_DIR}/plotly_maker/plotly-2.27.0.min.js DESTINATION +file(COPY ${CMAKE_SOURCE_DIR}/plotly_maker/plotly-2.32.0.min.js DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/davis_htmls) -file(COPY ${CMAKE_SOURCE_DIR}/plotly_maker/plotly-2.27.0.min.js DESTINATION +file(COPY ${CMAKE_SOURCE_DIR}/plotly_maker/plotly-2.32.0.min.js DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/davis_htmls) endif(WIN32) diff --git a/Tests/CommonUtilsTest.cpp b/Tests/CommonUtilsTest.cpp index a9bfc43..6d51874 100644 --- a/Tests/CommonUtilsTest.cpp +++ b/Tests/CommonUtilsTest.cpp @@ -1,6 +1,10 @@ #include "gtest/gtest.h" #include "common_utils/common_utils.h" #include +#include +#include +#include +//#include using std::string; @@ -80,15 +84,53 @@ TEST(CommonUtils, CreateStringFantasyArgs) { TEST(CommonUtils, SplitString) { - auto result = dvs::split(not_filled_test_string_1, '%'); - - for (int i = 0; i < result.size(); ++i) { + for (size_t i = 0; i < result.size(); ++i) { TEST_COUT << result[i] << "\n"; } TEST_COUT << not_filled_test_string_1; } +TEST(CommonUtils, FindSeparator) { + char sep; + dvs::find_separator("5.0;6;7;8", sep); + EXPECT_EQ(';', sep); + dvs::find_separator("5.0 6 7 8", sep); + EXPECT_EQ(' ', sep); + dvs::find_separator("5.0\t6\t7\t8", sep); + EXPECT_EQ('\t', sep); +} + +TEST(CommonUtils, htmlPageNameSanitizer) { + std::vector vec = {1, 2, 3, 4}; + std::string name("n-a-m-e 123 e_n_d.,'/now"); + std::string clearName = dvs::removeSpecialCharacters(name); + EXPECT_EQ(clearName, std::string("n-a-m-e_123_e_n_dnow")); +} + +/*std::string Utf8ToCp1251(const std::string& utf8Str) { + int len = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, NULL, 0); + wchar_t* wstr = new wchar_t[len]; + MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, wstr, len); + len = WideCharToMultiByte(1251, 0, wstr, -1, NULL, 0, NULL, NULL); + char* cp1251 = new char[len]; + WideCharToMultiByte(1251, 0, wstr, -1, cp1251, len, NULL, NULL); + std::string result(cp1251); + delete[] wstr; + delete[] cp1251; + return result; +} + +TEST(CommonUtils, RussianFileC) { + + string russian = "файл.txt"; + auto path = Utf8ToCp1251(russian); + std::fstream file; + file.open(path, std::ios::in); + EXPECT_EQ(bool(file), true); + +}*/ + int main(int argc, char* argv[]) { ::testing::InitGoogleTest(&argc, argv); std::ignore = RUN_ALL_TESTS(); diff --git a/array_core/array_core.h b/array_core/array_core.h index c3f4f59..dc834d0 100644 --- a/array_core/array_core.h +++ b/array_core/array_core.h @@ -52,6 +52,19 @@ template> > bool save(C const& container, const string& filename, const configSaveToDisk& configuration = configSaveToDisk()); + +//! Two 1-dimensional container for X-Y plots +template()))>, + typename = std::enable_if_t> > +bool show(C const& containerX, C const& containerY, const string& htmlPageName = dvs::kAppName, const Config& configuration = Config()); + +template()))>, + typename = std::enable_if_t> > +bool save(C const& containerX, C const& containerY, const string& filename, const configSaveToDisk& configuration = configSaveToDisk()); + + //! 2-dimensional container template()))>, @@ -147,12 +160,7 @@ bool save(const T* data, uint64_t count, const string& filename, const configSav template bool show(C const& container, const string& htmlPageName, const Config& configuration) { - vector dblRow(container.size()); - uint64_t i = 0; - for (auto v : container) { - dblRow[i] = v; - ++i; - } + vector dblRow = dvs::vecFromTemplate(container); bool res = false; if (configuration.typeVisual == VISUALTYPE_AUTO || configuration.typeVisual == VISUALTYPE_CHART) @@ -162,35 +170,73 @@ bool show(C const& container, const string& htmlPageName, const Config& configur template bool save(C const& container, const string& filename, const configSaveToDisk& configuration) { - vector row(container.size()); - uint64_t i = 0; - for (auto v : container) { - row[i] = v; - ++i; - } + vector row = dvs::vecFromTemplate(container); bool res = dvs::saveVec(row, filename, configuration); return res; } +template +bool show(C const& containerX, C const& containerY, const string& htmlPageName, const Config& configuration) { + if (containerX.size() != containerY.size()) { + return false; + } + vector dblRowX = dvs::vecFromTemplate(containerX); + vector dblRowY = dvs::vecFromTemplate(containerY); + bool res = dvs::showLineChartInBrowser(dblRowX, dblRowY, htmlPageName, configuration); + return res; +} + +template +bool save(C const& containerX, C const& containerY, const string& filename, const configSaveToDisk& configuration) { + if (containerX.size() != containerY.size()) { + return false; + } + vector rowX = dvs::vecFromTemplate(containerX); + vector rowY = dvs::vecFromTemplate(containerY); + vector> vecVec; + vecVec.emplace_back(rowX); + vecVec.emplace_back(rowY); + configSaveToDisk newConf = configuration; + newConf.isTranspose = !configuration.isTranspose; + bool res = dvs::saveVecVec(vecVec, filename, newConf); + return res; +} + template bool show(C const& container_of_containers, const string& htmlPageName, const Config& configuration) { vector> vecVecDbl; vecVecDbl.reserve(container_of_containers.size()); for (auto row : container_of_containers) { - vector dblRow(row.size()); - uint64_t i = 0; - for (auto v : row) { - dblRow[i] = v; - ++i; - } + vector dblRow = dvs::vecFromTemplate(row); vecVecDbl.emplace_back(dblRow); } bool res = false; - if (configuration.typeVisual == VISUALTYPE_AUTO || - configuration.typeVisual == VISUALTYPE_HEATMAP) { + size_t size1 = vecVecDbl.size(); + size_t size2 = 0; + if (!vecVecDbl.empty()) { + size2 = vecVecDbl[0].size(); + } + if ((configuration.typeVisual == VISUALTYPE_AUTO || //case when we want to plot graph with X and Y vectors + configuration.typeVisual == VISUALTYPE_CHART) && + (size1 == 2 || size2 == 2)) { // it can be or 2-columns-data or 2-rows-data + if (size1 == 2) { + res = dvs::showLineChartInBrowser(vecVecDbl[0], vecVecDbl[1], htmlPageName, configuration); + } else if (size2 == 2) { + vector xVals; + vector yVals; + xVals.reserve(size1); + for (int i = 0; i < size1; ++i) { + xVals.emplace_back(vecVecDbl[i][0]); + yVals.emplace_back(vecVecDbl[i][1]); + } + res = dvs::showLineChartInBrowser(xVals, yVals, htmlPageName, configuration); + } + } else if (configuration.typeVisual == VISUALTYPE_AUTO || + configuration.typeVisual == VISUALTYPE_HEATMAP) { res = dvs::showHeatMapInBrowser(vecVecDbl, htmlPageName, configuration); - } else if (configuration.typeVisual == VISUALTYPE_SURFACE) + } else if (configuration.typeVisual == VISUALTYPE_SURFACE) { res = dvs::showSurfaceInBrowser(vecVecDbl, htmlPageName, configuration); + } return res; } @@ -199,12 +245,7 @@ bool save(C const& container_of_containers, const string& filename, const config vector> vecVec; vecVec.reserve(container_of_containers.size()); for (auto row : container_of_containers) { - vector rowTemp(row.size()); - uint64_t i = 0; - for (auto v : row) { - rowTemp[i] = v; - ++i; - } + vector rowTemp = dvs::vecFromTemplate(row); vecVec.emplace_back(rowTemp); } bool res = dvs::saveVecVec(vecVec, filename, configuration); diff --git a/array_core/configurator.h b/array_core/configurator.h index 0a6fba9..604c624 100644 --- a/array_core/configurator.h +++ b/array_core/configurator.h @@ -74,9 +74,11 @@ struct Config { struct configSaveToDisk { configSaveToDisk(): separatorOfRows("\n"), - separatorOfCols(";") {} + separatorOfCols(";"), + isTranspose(false) {} std::string separatorOfRows; std::string separatorOfCols; + bool isTranspose; //rows-cols or cols-rows }; diff --git a/auto_format.bat b/auto_format.bat index baa4556..5bc9ed3 100644 --- a/auto_format.bat +++ b/auto_format.bat @@ -1,4 +1,4 @@ @echo off echo davis code is formatting... start /B astyle --project ./*.cpp,*.h -pause +ping localhost -n 3 >nul diff --git a/common_utils/common_utils.cpp b/common_utils/common_utils.cpp index 1ddf3d3..ae72a02 100644 --- a/common_utils/common_utils.cpp +++ b/common_utils/common_utils.cpp @@ -7,6 +7,7 @@ #include #include #include +#include //#STOP_GRAB_TO_INCLUDES_LIST namespace dvs { @@ -109,7 +110,8 @@ bool deleteFolder(const char* fname) { } } -bool getDataFromFile(const string& path, string& result) { +bool get_data_from_file(const string& path, + vector& result) { //TODO different scenarious and sanitizing if (!is_file_exists(path)) { @@ -123,7 +125,7 @@ bool getDataFromFile(const string& path, string& result) { if (file.is_open()) { string temp; while (std::getline(file, temp)) { - result.append(temp).append(";"); + result.emplace_back(temp); } } else { return false; @@ -232,5 +234,72 @@ bool make_string(const string& src, return true; } +int find_separator(const std::string& src, + char& separator) { + std::vector ignored_chars = {'+', '-', 'e', '.', '\r'}; + std::set unique_chars; + bool is_service_char = false; + bool is_dot_present = false; + bool is_comma_present = false; + size_t comma_counter = 0; + size_t dot_counter = 0; + + for (size_t i = 0; i < src.size(); ++i) { + + if (isdigit((unsigned char)src[i])) + continue; + is_service_char = false; + + if (src[i] == '.') { + is_dot_present = true; + ++dot_counter; + } else if (src[i] == ',') { + is_comma_present = true; + ++comma_counter; + } + + for (size_t j = 0; j < ignored_chars.size(); ++j) { + if (src[i] == ignored_chars[j]) { + is_service_char = true; + break; + } + } + if (is_service_char) + continue; + unique_chars.insert(src[i]); + } + if (unique_chars.size() == 1 && is_comma_present == false) { + separator = *unique_chars.begin(); + return GOOD_SEPARATOR; + } else if (unique_chars.size() == 1 && is_comma_present == true) { + if (is_dot_present) { + separator = ','; + return MABE_COMMA_MABE_DOT; + } + separator = *unique_chars.begin(); + return GOOD_SEPARATOR; + } else if (unique_chars.size() == 0) { + return NO_SEPARATOR; + } else if (unique_chars.size() > 1) { + return MORE_THAN_ONE_SEPARATOR; + } + return UNDEFINED_BEHAVIOR; +} + +string removeSpecialCharacters(const string& s) { + string t; + for (int i = 0; i < s.length(); i++) { + if (s[i] == ' ') { + t += '_'; + } else if ((s[i] >= 'a' && s[i] <= 'z') + || (s[i] >= 'A' && s[i] <= 'Z') + || (s[i] >= '0' && s[i] <= '9') + || (s[i] == '-') || (s[i] == '_')) { + t += s[i]; + } + } + return t; +} + //#STOP_GRAB_TO_DVS_NAMESPACE }; // namespace dvs diff --git a/common_utils/common_utils.h b/common_utils/common_utils.h index 3926ec5..7bd6d39 100644 --- a/common_utils/common_utils.h +++ b/common_utils/common_utils.h @@ -12,6 +12,13 @@ namespace dvs { //#START_GRAB_TO_DVS_NAMESPACE +enum SEPARATOR_RESULT { + GOOD_SEPARATOR, + MORE_THAN_ONE_SEPARATOR, + NO_SEPARATOR, + MABE_COMMA_MABE_DOT, + UNDEFINED_BEHAVIOR +}; using std::string; using std::vector; @@ -32,7 +39,8 @@ void sleepMs(unsigned long milisec); void openPlotlyHtml(const string& file_name); -bool getDataFromFile(const string& path, string& result); +bool get_data_from_file(const string& path, + vector& result); vector split(const string& target, char c); @@ -46,6 +54,12 @@ bool make_string(const string& src, // Now it doesn't work. bool deleteFolder(const char* fname); +int find_separator(const std::string& src, + char& separator); + +//! remove special characters except letters, numbers and '-', '_'. Spaces -> '_' +string removeSpecialCharacters(const string& s); + //! save to disk vector data template bool saveVec(const vector& vec, const string& filename, dv::configSaveToDisk config) { @@ -77,23 +91,51 @@ bool saveVecVec(const vector>& vecVec, const string& filename, dv::con if (!fout.is_open()) { return false; } - size_t rows = vecVec.size(); - size_t cols = vecVec.at(0).size(); - - for (int i = 0; i < rows; ++i) { - for (int j = 0; j < cols; ++j) { - double val = vecVec.at(i).at(j); - fout << val; - if (j < cols - 1) { // we dont need sep al row end - fout << config.separatorOfCols; + if (config.isTranspose) { + size_t rows = vecVec.at(0).size(); + size_t cols = vecVec.size(); + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + double val = vecVec.at(j).at(i); + fout << val; + if (j < cols - 1) { // we dont need sep at row end + fout << config.separatorOfCols; + } } + fout << config.separatorOfRows; + } + } else { + size_t rows = vecVec.size(); + size_t cols = vecVec.at(0).size(); + for (int i = 0; i < rows; ++i) { + for (int j = 0; j < cols; ++j) { + double val = vecVec.at(i).at(j); + fout << val; + if (j < cols - 1) { // we dont need sep at row end + fout << config.separatorOfCols; + } + } + fout << config.separatorOfRows; } - fout << config.separatorOfRows; } fout.close(); return true; } +//! convert any container to std::vector with G type +template()))>, + typename = std::enable_if_t>> +vector vecFromTemplate(const C& container) { + vector vec(container.size()); + uint64_t i = 0; + for (auto v : container) { + vec[i] = static_cast(v); + ++i; + } + return vec; +} //#STOP_GRAB_TO_DVS_NAMESPACE }; // namespace dvs diff --git a/davis_one/davis.cpp b/davis_one/davis.cpp index 3a68628..a3093f7 100644 --- a/davis_one/davis.cpp +++ b/davis_one/davis.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include #include @@ -30,7 +32,7 @@ namespace dvs { const char kHtmlModel[] = R"( - +
our github or -official plotly site +official plotly site