Merge branch 'config-dialog'

Adds a configuration program `fc2dconfig` and implements a configuration
file system.
This commit is contained in:
Epicalert 2021-07-03 01:54:18 +08:00
commit d37d49928e
No known key found for this signature in database
GPG key ID: CAA46F858D0979BD
9 changed files with 240 additions and 7 deletions

View file

@ -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
View 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
View 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
View 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);
}

View file

@ -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
View 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
View file

@ -0,0 +1,8 @@
#ifndef MODELLIST_HPP
#define MODELLIST_HPP
#include <vector>
std::vector<std::string> listModels();
#endif

View file

@ -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;

View file

@ -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