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} )
|
||||
find_package( FreeGLUT REQUIRED )
|
||||
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( ${OPENGL_INCLUDE_DIR} )
|
||||
include_directories( ${GLEW_INCLUDE_DIRS} )
|
||||
|
@ -62,6 +65,16 @@ add_executable( fc2d
|
|||
src/tomlcpp.cpp
|
||||
src/error.cpp
|
||||
src/eye.cpp
|
||||
src/configfile.cpp
|
||||
)
|
||||
target_link_libraries( fc2d ${OpenCV_LIBS} ${OPENGL_LIBRARIES} ${WEBP_LIBRARIES}
|
||||
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 <config.hpp>
|
||||
#include <model.hpp>
|
||||
#include <configfile.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
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;
|
||||
|
||||
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 << "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 <iostream>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <paths.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -9,22 +10,34 @@
|
|||
#define READABLE(p) access(p.c_str(),R_OK)==0
|
||||
#endif
|
||||
|
||||
std::string prefixCustom;
|
||||
std::string prefixDefault;
|
||||
std::string prefixConfig; // directory to store config.toml in
|
||||
std::string prefixCustom; // directory for user-accessible models and cvdata
|
||||
std::string prefixDefault; // directory for pre-installed models and cvdata
|
||||
|
||||
void initPrefixes() {
|
||||
#if defined (__gnu_linux__)
|
||||
prefixConfig = getenv("HOME") + std::string("/.config/facecam2d/");
|
||||
prefixCustom = getenv("HOME") + std::string("/.local/share/facecam2d/");
|
||||
prefixDefault = "/usr/share/facecam2d/";
|
||||
#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/");
|
||||
prefixDefault = "/Applications/Facecam2D.app/";
|
||||
#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\\");
|
||||
#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 customString = prefixCustom + path;
|
||||
std::string defaultString = prefixDefault + path;
|
||||
|
|
|
@ -3,11 +3,14 @@
|
|||
|
||||
#include <string>
|
||||
|
||||
extern std::string prefixConfig;
|
||||
extern std::string prefixCustom;
|
||||
extern std::string prefixDefault;
|
||||
|
||||
void initPrefixes();
|
||||
|
||||
void makePaths();
|
||||
|
||||
std::string resolvePath(const char* path);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue