Merge branch 'config-dialog'
Adds a configuration program `fc2dconfig` and implements a configuration file system.
This commit is contained in:
commit
d37d49928e
|
@ -27,6 +27,9 @@ find_package( glm REQUIRED )
|
||||||
message (STATUS "Found glm at: " ${GLM_INCLUDE_DIRS} )
|
message (STATUS "Found glm at: " ${GLM_INCLUDE_DIRS} )
|
||||||
find_package( FreeGLUT REQUIRED )
|
find_package( FreeGLUT REQUIRED )
|
||||||
message (STATUS "Found FreeGLUT at: " ${GLUT_INCLUDE_DIR} )
|
message (STATUS "Found FreeGLUT at: " ${GLUT_INCLUDE_DIR} )
|
||||||
|
find_package( wxWidgets REQUIRED core base )
|
||||||
|
message (STATUS "Found wxWidgets at: " ${wxWidgets_USE_FILE} )
|
||||||
|
include( ${wxWidgets_USE_FILE} )
|
||||||
include_directories( ${OpenCV_INCLUDE_DIRS} )
|
include_directories( ${OpenCV_INCLUDE_DIRS} )
|
||||||
include_directories( ${OPENGL_INCLUDE_DIR} )
|
include_directories( ${OPENGL_INCLUDE_DIR} )
|
||||||
include_directories( ${GLEW_INCLUDE_DIRS} )
|
include_directories( ${GLEW_INCLUDE_DIRS} )
|
||||||
|
@ -62,6 +65,16 @@ add_executable( fc2d
|
||||||
src/tomlcpp.cpp
|
src/tomlcpp.cpp
|
||||||
src/error.cpp
|
src/error.cpp
|
||||||
src/eye.cpp
|
src/eye.cpp
|
||||||
|
src/configfile.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries( fc2d ${OpenCV_LIBS} ${OPENGL_LIBRARIES} ${WEBP_LIBRARIES}
|
target_link_libraries( fc2d ${OpenCV_LIBS} ${OPENGL_LIBRARIES} ${WEBP_LIBRARIES}
|
||||||
FreeGLUT::freeglut GLEW::glew zip Boxer fmt )
|
FreeGLUT::freeglut GLEW::glew zip Boxer fmt )
|
||||||
|
add_executable( fc2dconfig
|
||||||
|
src/fc2dconfig.cpp
|
||||||
|
src/paths.cpp
|
||||||
|
src/modellist.cpp
|
||||||
|
src/configfile.cpp
|
||||||
|
src/toml.c
|
||||||
|
src/tomlcpp.cpp
|
||||||
|
)
|
||||||
|
target_link_libraries( fc2dconfig ${wxWidgets_LIBRARIES} )
|
||||||
|
|
25
src/configfile.cpp
Normal file
25
src/configfile.cpp
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <configfile.hpp>
|
||||||
|
#include <paths.hpp>
|
||||||
|
#include <error.hpp>
|
||||||
|
#include <tomlcpp.hpp>
|
||||||
|
|
||||||
|
bool configFileOpen(struct optData* data) {
|
||||||
|
auto configFile = toml::parseFile(prefixConfig + "config.toml");
|
||||||
|
if (!configFile.table) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto useHaarResult = configFile.table->getBool("use_haar");
|
||||||
|
if (useHaarResult.first) {
|
||||||
|
data->useHaar = useHaarResult.second;
|
||||||
|
}
|
||||||
|
auto modelNameResult = configFile.table->getString("model");
|
||||||
|
if (modelNameResult.first) {
|
||||||
|
data->model = modelNameResult.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
8
src/configfile.hpp
Normal file
8
src/configfile.hpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef CONFIGFILE_HPP
|
||||||
|
#define CONFIGFILE_HPP
|
||||||
|
|
||||||
|
#include <args.hpp>
|
||||||
|
|
||||||
|
bool configFileOpen(struct optData* optData);
|
||||||
|
|
||||||
|
#endif
|
120
src/fc2dconfig.cpp
Normal file
120
src/fc2dconfig.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <config.hpp>
|
||||||
|
#include <args.hpp>
|
||||||
|
#include <paths.hpp>
|
||||||
|
#include <modellist.hpp>
|
||||||
|
#include <configfile.hpp>
|
||||||
|
|
||||||
|
#include <wx/wxprec.h>
|
||||||
|
#ifndef WX_PRECOMP
|
||||||
|
#include <wx/wx.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class ConfigurationApp : public wxApp {
|
||||||
|
public:
|
||||||
|
virtual bool OnInit();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfigurationFrame : public wxFrame {
|
||||||
|
public:
|
||||||
|
ConfigurationFrame();
|
||||||
|
private:
|
||||||
|
std::vector<std::string> modelVec;
|
||||||
|
wxCheckBox* useHaarCheckBox;
|
||||||
|
wxChoice* modelNameChoice;
|
||||||
|
void loadExistingConfig(); // loads existing config file and populates controls
|
||||||
|
void OnApply(wxCommandEvent& event);
|
||||||
|
void OnExit(wxCommandEvent& event);
|
||||||
|
};
|
||||||
|
|
||||||
|
wxIMPLEMENT_APP(ConfigurationApp);
|
||||||
|
|
||||||
|
bool ConfigurationApp::OnInit() {
|
||||||
|
initPrefixes();
|
||||||
|
makePaths();
|
||||||
|
|
||||||
|
ConfigurationFrame* frame = new ConfigurationFrame();
|
||||||
|
frame->Show(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigurationFrame::ConfigurationFrame() : wxFrame(NULL, wxID_ANY, "Configure " PROJECT_NAME) {
|
||||||
|
// find models to populate model dropdown
|
||||||
|
modelVec = listModels();
|
||||||
|
wxString modelArray[modelVec.size()];
|
||||||
|
for (int i = 0; i < modelVec.size(); i++) {
|
||||||
|
modelArray[i] = wxString(modelVec[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxPanel* panel = new wxPanel(this, wxID_ANY);
|
||||||
|
|
||||||
|
// define all controls and labels
|
||||||
|
useHaarCheckBox = new wxCheckBox(panel, wxID_ANY, "Disable DNN face detection");
|
||||||
|
wxStaticText* modelNameText = new wxStaticText(panel, wxID_ANY, "Model name:");
|
||||||
|
modelNameChoice = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, modelVec.size(), modelArray);
|
||||||
|
|
||||||
|
wxBoxSizer* modelSizer = new wxBoxSizer(wxHORIZONTAL); // need to put label next to dropdown
|
||||||
|
modelSizer->Add(modelNameText, 0, wxALIGN_CENTER | wxALL, 5);
|
||||||
|
modelSizer->Add(modelNameChoice, 0, wxLEFT, 20);
|
||||||
|
|
||||||
|
wxStaticBoxSizer* generalBoxSizer = new wxStaticBoxSizer(new wxStaticBox(panel, wxID_ANY, "General"), wxVERTICAL);
|
||||||
|
generalBoxSizer->Add(modelSizer, 0, wxALL, 5);
|
||||||
|
|
||||||
|
wxStaticBoxSizer* performanceBoxSizer = new wxStaticBoxSizer(new wxStaticBox(panel, wxID_ANY, "Performance"), wxVERTICAL);
|
||||||
|
performanceBoxSizer->Add(useHaarCheckBox, 0, wxALL, 5);
|
||||||
|
|
||||||
|
// define bottom buttons (Cancel and Apply) and their sizer
|
||||||
|
wxButton* cancelButton = new wxButton(panel, wxID_CANCEL, "Cancel");
|
||||||
|
wxButton* applyButton = new wxButton(panel, wxID_APPLY, "Apply settings");
|
||||||
|
wxBoxSizer* bottomButtonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
bottomButtonSizer->Add(cancelButton, 0, wxALL, 5);
|
||||||
|
bottomButtonSizer->Add(applyButton, 0, wxALL, 5);
|
||||||
|
|
||||||
|
// define main sizer
|
||||||
|
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
sizer->Add(generalBoxSizer, 0, wxALL | wxALIGN_LEFT | wxEXPAND, 10);
|
||||||
|
sizer->Add(performanceBoxSizer, 0, wxALL | wxALIGN_LEFT | wxEXPAND, 10);
|
||||||
|
sizer->AddStretchSpacer(1);
|
||||||
|
sizer->Add(bottomButtonSizer, 0, wxALIGN_RIGHT | wxALL, 10);
|
||||||
|
|
||||||
|
panel->SetSizerAndFit(sizer);
|
||||||
|
|
||||||
|
Bind(wxEVT_BUTTON, &ConfigurationFrame::OnApply, this, wxID_APPLY);
|
||||||
|
Bind(wxEVT_BUTTON, &ConfigurationFrame::OnExit, this, wxID_CANCEL);
|
||||||
|
|
||||||
|
loadExistingConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationFrame::loadExistingConfig() {
|
||||||
|
struct optData configData;
|
||||||
|
configFileOpen(&configData);
|
||||||
|
|
||||||
|
useHaarCheckBox->SetValue(configData.useHaar);
|
||||||
|
for (int i = 0; i < modelVec.size(); i++) {
|
||||||
|
if (modelVec[i] == configData.model) {
|
||||||
|
modelNameChoice->SetSelection(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationFrame::OnApply(wxCommandEvent& event) {
|
||||||
|
// write options to config file
|
||||||
|
std::ofstream configFile;
|
||||||
|
configFile.open(prefixConfig + "config.toml");
|
||||||
|
configFile << "use_haar = " << (useHaarCheckBox->GetValue() ? "true" : "false") << std::endl;
|
||||||
|
// janky edge case lmao
|
||||||
|
// if user did not select any model, don't write the line in the config file!
|
||||||
|
if (modelNameChoice->GetSelection() != wxNOT_FOUND) {
|
||||||
|
configFile << "model = \"" << modelVec[modelNameChoice->GetSelection()] << "\""<< std::endl;
|
||||||
|
}
|
||||||
|
configFile.close();
|
||||||
|
|
||||||
|
Close(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigurationFrame::OnExit(wxCommandEvent& event) {
|
||||||
|
Close(true);
|
||||||
|
}
|
16
src/main.cpp
16
src/main.cpp
|
@ -4,18 +4,26 @@
|
||||||
#include <args.hpp>
|
#include <args.hpp>
|
||||||
#include <config.hpp>
|
#include <config.hpp>
|
||||||
#include <model.hpp>
|
#include <model.hpp>
|
||||||
|
#include <configfile.hpp>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
int main (int argc, char** argv) {
|
int main (int argc, char** argv) {
|
||||||
#ifndef _WIN32
|
|
||||||
argp_parse(&argp, argc, argv, 0, 0, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::cout << PROJECT_NAME " is starting..." << std::endl;
|
std::cout << PROJECT_NAME " is starting..." << std::endl;
|
||||||
|
|
||||||
initPrefixes();
|
initPrefixes();
|
||||||
|
makePaths();
|
||||||
|
|
||||||
|
// load config file and apply it
|
||||||
|
configFileOpen(&optData);
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
// parse arguments and apply them
|
||||||
|
argp_parse(&argp, argc, argv, 0, 0, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
std::cout << "Custom asset prefix: " << prefixCustom << std::endl;
|
std::cout << "Custom asset prefix: " << prefixCustom << std::endl;
|
||||||
std::cout << "Default asset prefix: " << prefixDefault << std::endl;
|
std::cout << "Default asset prefix: " << prefixDefault << std::endl;
|
||||||
|
|
||||||
|
|
35
src/modellist.cpp
Normal file
35
src/modellist.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#include <iostream>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include <paths.hpp>
|
||||||
|
|
||||||
|
#include <modellist.hpp>
|
||||||
|
|
||||||
|
// get models from a given directory and add them to a given vector
|
||||||
|
void getModelsFromDir(std::string path, std::vector<std::string>* vector) {
|
||||||
|
// return if directory doesnt exist
|
||||||
|
if (!std::filesystem::exists(path)) return;
|
||||||
|
|
||||||
|
// iterate through all items in this directory
|
||||||
|
for (auto& p: std::filesystem::directory_iterator(path)) {
|
||||||
|
if (p.path().extension() == ".fma") {
|
||||||
|
vector->push_back(p.path().stem().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> listModels() {
|
||||||
|
std::vector<std::string> modelList;
|
||||||
|
|
||||||
|
getModelsFromDir(prefixCustom + "models", &modelList);
|
||||||
|
getModelsFromDir(prefixDefault + "models", &modelList);
|
||||||
|
getModelsFromDir("models", &modelList);
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < modelList.size(); i++) {
|
||||||
|
std::cout << "Detected model: " << modelList.at(i) << std::endl;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
return modelList;
|
||||||
|
}
|
8
src/modellist.hpp
Normal file
8
src/modellist.hpp
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef MODELLIST_HPP
|
||||||
|
#define MODELLIST_HPP
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
std::vector<std::string> listModels();
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,6 +1,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <filesystem>
|
||||||
#include <paths.hpp>
|
#include <paths.hpp>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -9,22 +10,34 @@
|
||||||
#define READABLE(p) access(p.c_str(),R_OK)==0
|
#define READABLE(p) access(p.c_str(),R_OK)==0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::string prefixCustom;
|
std::string prefixConfig; // directory to store config.toml in
|
||||||
std::string prefixDefault;
|
std::string prefixCustom; // directory for user-accessible models and cvdata
|
||||||
|
std::string prefixDefault; // directory for pre-installed models and cvdata
|
||||||
|
|
||||||
void initPrefixes() {
|
void initPrefixes() {
|
||||||
#if defined (__gnu_linux__)
|
#if defined (__gnu_linux__)
|
||||||
|
prefixConfig = getenv("HOME") + std::string("/.config/facecam2d/");
|
||||||
prefixCustom = getenv("HOME") + std::string("/.local/share/facecam2d/");
|
prefixCustom = getenv("HOME") + std::string("/.local/share/facecam2d/");
|
||||||
prefixDefault = "/usr/share/facecam2d/";
|
prefixDefault = "/usr/share/facecam2d/";
|
||||||
#elif defined (__APPLE__)
|
#elif defined (__APPLE__)
|
||||||
|
// config and supporting files are both stored in Library on MacOS
|
||||||
|
prefixConfig = getenv("HOME") + std::string("/Library/Facecam2D/");
|
||||||
prefixCustom = getenv("HOME") + std::string("/Library/Facecam2D/");
|
prefixCustom = getenv("HOME") + std::string("/Library/Facecam2D/");
|
||||||
prefixDefault = "/Applications/Facecam2D.app/";
|
prefixDefault = "/Applications/Facecam2D.app/";
|
||||||
#elif defined (_WIN32)
|
#elif defined (_WIN32)
|
||||||
prefixCustom = getenv("AppData") + std::string("\\Facecam2D\\");
|
prefixConfig = getenv("AppData") + std::string("\\Roaming\\Facecam2D\\");
|
||||||
|
prefixCustom = getenv("AppData") + std::string("\\Local\\Facecam2D\\");
|
||||||
prefixDefault = getenv("ProgramFiles") + std::string("\\Facecam2D\\");
|
prefixDefault = getenv("ProgramFiles") + std::string("\\Facecam2D\\");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void makePaths() {
|
||||||
|
std::filesystem::create_directories(prefixConfig);
|
||||||
|
std::filesystem::create_directories(prefixCustom + "models/");
|
||||||
|
std::filesystem::create_directories(prefixCustom + "cvdata/");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string resolvePath(const char* path) {
|
std::string resolvePath(const char* path) {
|
||||||
std::string customString = prefixCustom + path;
|
std::string customString = prefixCustom + path;
|
||||||
std::string defaultString = prefixDefault + path;
|
std::string defaultString = prefixDefault + path;
|
||||||
|
|
|
@ -3,11 +3,14 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
extern std::string prefixConfig;
|
||||||
extern std::string prefixCustom;
|
extern std::string prefixCustom;
|
||||||
extern std::string prefixDefault;
|
extern std::string prefixDefault;
|
||||||
|
|
||||||
void initPrefixes();
|
void initPrefixes();
|
||||||
|
|
||||||
|
void makePaths();
|
||||||
|
|
||||||
std::string resolvePath(const char* path);
|
std::string resolvePath(const char* path);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue