GUI: move user presets to its own file
This commit is contained in:
parent
64bb97532c
commit
17aab13d9a
|
@ -860,6 +860,7 @@ src/gui/sysManager.cpp
|
||||||
src/gui/sysPartNumber.cpp
|
src/gui/sysPartNumber.cpp
|
||||||
src/gui/sysPicker.cpp
|
src/gui/sysPicker.cpp
|
||||||
src/gui/tutorial.cpp
|
src/gui/tutorial.cpp
|
||||||
|
src/gui/userPresets.cpp
|
||||||
src/gui/util.cpp
|
src/gui/util.cpp
|
||||||
src/gui/waveEdit.cpp
|
src/gui/waveEdit.cpp
|
||||||
src/gui/volMeter.cpp
|
src/gui/volMeter.cpp
|
||||||
|
|
|
@ -3156,357 +3156,3 @@ FurnaceGUISysDef::FurnaceGUISysDef(const char* n, const char* def, DivEngine* e)
|
||||||
// extract extra
|
// extract extra
|
||||||
extra=conf.toString();
|
extra=conf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
// functions for loading/saving user presets
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define PRESETS_FILE "\\presets.cfg"
|
|
||||||
#else
|
|
||||||
#define PRESETS_FILE "/presets.cfg"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define REDUNDANCY_NUM_ATTEMPTS 5
|
|
||||||
#define CHECK_BUF_SIZE 8192
|
|
||||||
|
|
||||||
std::vector<FurnaceGUISysDef>* digDeep(std::vector<FurnaceGUISysDef>& entries, int depth) {
|
|
||||||
if (depth==0) return &entries;
|
|
||||||
std::vector<FurnaceGUISysDef>& result=entries;
|
|
||||||
|
|
||||||
for (int i=0; i<depth; i++) {
|
|
||||||
if (result.empty()) {
|
|
||||||
logW("digDeep: %d is as far as it goes!",depth);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result=result.at(result.size()).subDefs;
|
|
||||||
}
|
|
||||||
return &result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FurnaceGUI::loadUserPresets(bool redundancy) {
|
|
||||||
String path=e->getConfigPath()+PRESETS_FILE;
|
|
||||||
String line;
|
|
||||||
logD("opening user presets: %s",path);
|
|
||||||
|
|
||||||
FILE* f=NULL;
|
|
||||||
|
|
||||||
if (redundancy) {
|
|
||||||
unsigned char* readBuf=new unsigned char[CHECK_BUF_SIZE];
|
|
||||||
size_t readBufLen=0;
|
|
||||||
for (int i=0; i<REDUNDANCY_NUM_ATTEMPTS; i++) {
|
|
||||||
bool viable=false;
|
|
||||||
if (i>0) {
|
|
||||||
line=fmt::sprintf("%s.%d",path,i);
|
|
||||||
} else {
|
|
||||||
line=path;
|
|
||||||
}
|
|
||||||
logV("trying: %s",line);
|
|
||||||
|
|
||||||
// try to open config
|
|
||||||
f=ps_fopen(line.c_str(),"rb");
|
|
||||||
// check whether we could open it
|
|
||||||
if (f==NULL) {
|
|
||||||
logV("fopen(): %s",strerror(errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check whether there's something
|
|
||||||
while (!feof(f)) {
|
|
||||||
readBufLen=fread(readBuf,1,CHECK_BUF_SIZE,f);
|
|
||||||
if (ferror(f)) {
|
|
||||||
logV("fread(): %s",strerror(errno));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t j=0; j<readBufLen; j++) {
|
|
||||||
if (readBuf[j]==0) {
|
|
||||||
viable=false;
|
|
||||||
logW("a zero?");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (readBuf[j]!='\r' && readBuf[j]!='\n' && readBuf[j]!=' ') {
|
|
||||||
viable=true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (viable) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// there's something
|
|
||||||
if (viable) {
|
|
||||||
if (fseek(f,0,SEEK_SET)==-1) {
|
|
||||||
logV("fseek(): %s",strerror(errno));
|
|
||||||
viable=false;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// close it (because there's nothing)
|
|
||||||
fclose(f);
|
|
||||||
f=NULL;
|
|
||||||
}
|
|
||||||
delete[] readBuf;
|
|
||||||
|
|
||||||
// we couldn't read at all
|
|
||||||
if (f==NULL) {
|
|
||||||
logD("presets file does not exist");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
f=ps_fopen(path.c_str(),"rb");
|
|
||||||
if (f==NULL) {
|
|
||||||
logD("presets file does not exist");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now read stuff
|
|
||||||
FurnaceGUISysCategory* userCategory=NULL;
|
|
||||||
|
|
||||||
for (FurnaceGUISysCategory& i: sysCategories) {
|
|
||||||
if (strcmp(i.name,"User")==0) {
|
|
||||||
userCategory=&i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userCategory==NULL) {
|
|
||||||
logE("could not find user category!");
|
|
||||||
fclose(f);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
userCategory->systems.clear();
|
|
||||||
|
|
||||||
char nextLine[4096];
|
|
||||||
while (!feof(f)) {
|
|
||||||
if (fgets(nextLine,4095,f)==NULL) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int indent=0;
|
|
||||||
bool readIndent=true;
|
|
||||||
bool keyOrValue=false;
|
|
||||||
String key="";
|
|
||||||
String value="";
|
|
||||||
for (char* i=nextLine; *i; i++) {
|
|
||||||
if ((*i)=='\n') break;
|
|
||||||
if (readIndent) {
|
|
||||||
if ((*i)==' ') {
|
|
||||||
indent++;
|
|
||||||
} else {
|
|
||||||
readIndent=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!readIndent) {
|
|
||||||
if (keyOrValue) {
|
|
||||||
value+=*i;
|
|
||||||
} else {
|
|
||||||
if ((*i)=='=') {
|
|
||||||
keyOrValue=true;
|
|
||||||
} else {
|
|
||||||
key+=*i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
indent>>=1;
|
|
||||||
|
|
||||||
if (!key.empty() && !value.empty()) {
|
|
||||||
std::vector<FurnaceGUISysDef>* where=digDeep(userCategory->systems,indent);
|
|
||||||
where->push_back(FurnaceGUISysDef(key.c_str(),value.c_str(),e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeSubEntries(FILE* f, std::vector<FurnaceGUISysDef>& entries, int depth) {
|
|
||||||
for (FurnaceGUISysDef& i: entries) {
|
|
||||||
String safeName;
|
|
||||||
safeName.reserve(i.name.size());
|
|
||||||
bool beginning=false;
|
|
||||||
for (char j: i.name) {
|
|
||||||
if (beginning && j==' ') continue;
|
|
||||||
if (j=='=') continue;
|
|
||||||
if (j<0x20) continue;
|
|
||||||
safeName+=j;
|
|
||||||
}
|
|
||||||
|
|
||||||
String data;
|
|
||||||
for (int i=0; i<depth; i++) {
|
|
||||||
data+=" ";
|
|
||||||
}
|
|
||||||
data+=fmt::sprintf("%s=%s\n",safeName,i.definition);
|
|
||||||
fputs(data.c_str(),f);
|
|
||||||
|
|
||||||
writeSubEntries(f,i.subDefs,depth+1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FurnaceGUI::saveUserPresets(bool redundancy) {
|
|
||||||
String path=e->getConfigPath()+PRESETS_FILE;
|
|
||||||
FurnaceGUISysCategory* userCategory=NULL;
|
|
||||||
|
|
||||||
for (FurnaceGUISysCategory& i: sysCategories) {
|
|
||||||
if (strcmp(i.name,"User")==0) {
|
|
||||||
userCategory=&i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (userCategory==NULL) {
|
|
||||||
logE("could not find user category!");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (redundancy) {
|
|
||||||
char oldPath[4096];
|
|
||||||
char newPath[4096];
|
|
||||||
|
|
||||||
if (fileExists(path.c_str())==1) {
|
|
||||||
logD("rotating preset files...");
|
|
||||||
for (int i=4; i>=0; i--) {
|
|
||||||
if (i>0) {
|
|
||||||
snprintf(oldPath,4095,"%s.%d",path.c_str(),i);
|
|
||||||
} else {
|
|
||||||
strncpy(oldPath,path.c_str(),4095);
|
|
||||||
}
|
|
||||||
snprintf(newPath,4095,"%s.%d",path.c_str(),i+1);
|
|
||||||
|
|
||||||
if (i>=4) {
|
|
||||||
logV("remove %s",oldPath);
|
|
||||||
deleteFile(oldPath);
|
|
||||||
} else {
|
|
||||||
logV("move %s to %s",oldPath,newPath);
|
|
||||||
moveFiles(oldPath,newPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logD("saving user presets: %s",path);
|
|
||||||
FILE* f=ps_fopen(path.c_str(),"wb");
|
|
||||||
if (f==NULL) {
|
|
||||||
logW("could not write presets! %s",strerror(errno));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
writeSubEntries(f,userCategory->systems,0);
|
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
logD("presets written successfully.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// user presets management
|
|
||||||
void FurnaceGUI::printPresets(std::vector<FurnaceGUISysDef>& items, size_t depth, std::vector<int>& depthStack) {
|
|
||||||
if (depth>0) ImGui::Indent();
|
|
||||||
int index=0;
|
|
||||||
for (FurnaceGUISysDef& i: items) {
|
|
||||||
bool isSelected=(selectedUserPreset.size()==(depth+1));
|
|
||||||
if (isSelected) {
|
|
||||||
for (size_t j=0; j<=depth; j++) {
|
|
||||||
int item=-1;
|
|
||||||
if (j>=depthStack.size()) {
|
|
||||||
item=index;
|
|
||||||
} else {
|
|
||||||
item=depthStack[j];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedUserPreset[j]!=item) {
|
|
||||||
isSelected=false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::PushID(index+1);
|
|
||||||
if (ImGui::Selectable(i.name.c_str(),isSelected)) {
|
|
||||||
selectedUserPreset=depthStack;
|
|
||||||
selectedUserPreset.push_back(index);
|
|
||||||
}
|
|
||||||
ImGui::PopID();
|
|
||||||
if (!i.subDefs.empty()) {
|
|
||||||
depthStack.push_back(index);
|
|
||||||
ImGui::PushID(index);
|
|
||||||
printPresets(i.subDefs,depth+1,depthStack);
|
|
||||||
ImGui::PopID();
|
|
||||||
depthStack.pop_back();
|
|
||||||
}
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
if (depth>0) ImGui::Unindent();
|
|
||||||
}
|
|
||||||
|
|
||||||
FurnaceGUISysDef* FurnaceGUI::selectPreset(std::vector<FurnaceGUISysDef>& items) {
|
|
||||||
FurnaceGUISysDef* ret=NULL;
|
|
||||||
for (size_t i=0; i<selectedUserPreset.size(); i++) {
|
|
||||||
if (selectedUserPreset[i]<0 || selectedUserPreset[i]>(int)items.size()) return NULL;
|
|
||||||
ret=&items[selectedUserPreset[i]];
|
|
||||||
if (i<selectedUserPreset.size()-1) {
|
|
||||||
items=ret->subDefs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FurnaceGUI::drawUserPresets() {
|
|
||||||
if (nextWindow==GUI_WINDOW_USER_PRESETS) {
|
|
||||||
userPresetsOpen=true;
|
|
||||||
ImGui::SetNextWindowFocus();
|
|
||||||
nextWindow=GUI_WINDOW_NOTHING;
|
|
||||||
}
|
|
||||||
if (!userPresetsOpen) return;
|
|
||||||
if (ImGui::Begin("User Presets",&userPresetsOpen,globalWinFlags)) {
|
|
||||||
FurnaceGUISysCategory* userCategory=NULL;
|
|
||||||
for (FurnaceGUISysCategory& i: sysCategories) {
|
|
||||||
if (strcmp(i.name,"User")==0) {
|
|
||||||
userCategory=&i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<int> depthStack;
|
|
||||||
|
|
||||||
if (userCategory==NULL) {
|
|
||||||
ImGui::Text("Error! User category does not exist!");
|
|
||||||
} else if (ImGui::BeginTable("UserPresets",2,ImGuiTableFlags_BordersInnerV)) {
|
|
||||||
// preset list
|
|
||||||
ImGui::TableNextRow();
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
if (ImGui::Button(ICON_FA_PLUS "##AddPreset")) {
|
|
||||||
userCategory->systems.push_back(FurnaceGUISysDef("New Preset",{}));
|
|
||||||
selectedUserPreset.clear();
|
|
||||||
selectedUserPreset.push_back(userCategory->systems.size()-1);
|
|
||||||
}
|
|
||||||
printPresets(userCategory->systems,0,depthStack);
|
|
||||||
|
|
||||||
// editor
|
|
||||||
ImGui::TableNextColumn();
|
|
||||||
if (selectedUserPreset.empty()) {
|
|
||||||
ImGui::Text("select a preset");
|
|
||||||
} else {
|
|
||||||
FurnaceGUISysDef* preset=selectPreset(userCategory->systems);
|
|
||||||
|
|
||||||
if (preset!=NULL) {
|
|
||||||
ImGui::AlignTextToFramePadding();
|
|
||||||
ImGui::Text("Name");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
|
||||||
ImGui::InputText("##PName",&preset->name);
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::Text("the rest...");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndTable();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Button("Save and Close")) {
|
|
||||||
userPresetsOpen=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!userPresetsOpen) {
|
|
||||||
saveUserPresets(true);
|
|
||||||
}
|
|
||||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_USER_PRESETS;
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
379
src/gui/userPresets.cpp
Normal file
379
src/gui/userPresets.cpp
Normal file
|
@ -0,0 +1,379 @@
|
||||||
|
/**
|
||||||
|
* Furnace Tracker - multi-system chiptune tracker
|
||||||
|
* Copyright (C) 2021-2024 tildearrow and contributors
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gui.h"
|
||||||
|
#include "../baseutils.h"
|
||||||
|
#include "../fileutils.h"
|
||||||
|
#include <fmt/printf.h>
|
||||||
|
#include "IconsFontAwesome4.h"
|
||||||
|
#include <imgui.h>
|
||||||
|
#include "misc/cpp/imgui_stdlib.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define PRESETS_FILE "\\presets.cfg"
|
||||||
|
#else
|
||||||
|
#define PRESETS_FILE "/presets.cfg"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define REDUNDANCY_NUM_ATTEMPTS 5
|
||||||
|
#define CHECK_BUF_SIZE 8192
|
||||||
|
|
||||||
|
std::vector<FurnaceGUISysDef>* digDeep(std::vector<FurnaceGUISysDef>& entries, int depth) {
|
||||||
|
if (depth==0) return &entries;
|
||||||
|
std::vector<FurnaceGUISysDef>& result=entries;
|
||||||
|
|
||||||
|
for (int i=0; i<depth; i++) {
|
||||||
|
if (result.empty()) {
|
||||||
|
logW("digDeep: %d is as far as it goes!",depth);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result=result.at(result.size()).subDefs;
|
||||||
|
}
|
||||||
|
return &result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FurnaceGUI::loadUserPresets(bool redundancy) {
|
||||||
|
String path=e->getConfigPath()+PRESETS_FILE;
|
||||||
|
String line;
|
||||||
|
logD("opening user presets: %s",path);
|
||||||
|
|
||||||
|
FILE* f=NULL;
|
||||||
|
|
||||||
|
if (redundancy) {
|
||||||
|
unsigned char* readBuf=new unsigned char[CHECK_BUF_SIZE];
|
||||||
|
size_t readBufLen=0;
|
||||||
|
for (int i=0; i<REDUNDANCY_NUM_ATTEMPTS; i++) {
|
||||||
|
bool viable=false;
|
||||||
|
if (i>0) {
|
||||||
|
line=fmt::sprintf("%s.%d",path,i);
|
||||||
|
} else {
|
||||||
|
line=path;
|
||||||
|
}
|
||||||
|
logV("trying: %s",line);
|
||||||
|
|
||||||
|
// try to open config
|
||||||
|
f=ps_fopen(line.c_str(),"rb");
|
||||||
|
// check whether we could open it
|
||||||
|
if (f==NULL) {
|
||||||
|
logV("fopen(): %s",strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check whether there's something
|
||||||
|
while (!feof(f)) {
|
||||||
|
readBufLen=fread(readBuf,1,CHECK_BUF_SIZE,f);
|
||||||
|
if (ferror(f)) {
|
||||||
|
logV("fread(): %s",strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j=0; j<readBufLen; j++) {
|
||||||
|
if (readBuf[j]==0) {
|
||||||
|
viable=false;
|
||||||
|
logW("a zero?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (readBuf[j]!='\r' && readBuf[j]!='\n' && readBuf[j]!=' ') {
|
||||||
|
viable=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viable) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// there's something
|
||||||
|
if (viable) {
|
||||||
|
if (fseek(f,0,SEEK_SET)==-1) {
|
||||||
|
logV("fseek(): %s",strerror(errno));
|
||||||
|
viable=false;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// close it (because there's nothing)
|
||||||
|
fclose(f);
|
||||||
|
f=NULL;
|
||||||
|
}
|
||||||
|
delete[] readBuf;
|
||||||
|
|
||||||
|
// we couldn't read at all
|
||||||
|
if (f==NULL) {
|
||||||
|
logD("presets file does not exist");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
f=ps_fopen(path.c_str(),"rb");
|
||||||
|
if (f==NULL) {
|
||||||
|
logD("presets file does not exist");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now read stuff
|
||||||
|
FurnaceGUISysCategory* userCategory=NULL;
|
||||||
|
|
||||||
|
for (FurnaceGUISysCategory& i: sysCategories) {
|
||||||
|
if (strcmp(i.name,"User")==0) {
|
||||||
|
userCategory=&i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userCategory==NULL) {
|
||||||
|
logE("could not find user category!");
|
||||||
|
fclose(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
userCategory->systems.clear();
|
||||||
|
|
||||||
|
char nextLine[4096];
|
||||||
|
while (!feof(f)) {
|
||||||
|
if (fgets(nextLine,4095,f)==NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int indent=0;
|
||||||
|
bool readIndent=true;
|
||||||
|
bool keyOrValue=false;
|
||||||
|
String key="";
|
||||||
|
String value="";
|
||||||
|
for (char* i=nextLine; *i; i++) {
|
||||||
|
if ((*i)=='\n') break;
|
||||||
|
if (readIndent) {
|
||||||
|
if ((*i)==' ') {
|
||||||
|
indent++;
|
||||||
|
} else {
|
||||||
|
readIndent=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!readIndent) {
|
||||||
|
if (keyOrValue) {
|
||||||
|
value+=*i;
|
||||||
|
} else {
|
||||||
|
if ((*i)=='=') {
|
||||||
|
keyOrValue=true;
|
||||||
|
} else {
|
||||||
|
key+=*i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indent>>=1;
|
||||||
|
|
||||||
|
if (!key.empty() && !value.empty()) {
|
||||||
|
std::vector<FurnaceGUISysDef>* where=digDeep(userCategory->systems,indent);
|
||||||
|
where->push_back(FurnaceGUISysDef(key.c_str(),value.c_str(),e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSubEntries(FILE* f, std::vector<FurnaceGUISysDef>& entries, int depth) {
|
||||||
|
for (FurnaceGUISysDef& i: entries) {
|
||||||
|
String safeName;
|
||||||
|
safeName.reserve(i.name.size());
|
||||||
|
bool beginning=false;
|
||||||
|
for (char j: i.name) {
|
||||||
|
if (beginning && j==' ') continue;
|
||||||
|
if (j=='=') continue;
|
||||||
|
if (j<0x20) continue;
|
||||||
|
safeName+=j;
|
||||||
|
}
|
||||||
|
|
||||||
|
String data;
|
||||||
|
for (int i=0; i<depth; i++) {
|
||||||
|
data+=" ";
|
||||||
|
}
|
||||||
|
data+=fmt::sprintf("%s=%s\n",safeName,i.definition);
|
||||||
|
fputs(data.c_str(),f);
|
||||||
|
|
||||||
|
writeSubEntries(f,i.subDefs,depth+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FurnaceGUI::saveUserPresets(bool redundancy) {
|
||||||
|
String path=e->getConfigPath()+PRESETS_FILE;
|
||||||
|
FurnaceGUISysCategory* userCategory=NULL;
|
||||||
|
|
||||||
|
for (FurnaceGUISysCategory& i: sysCategories) {
|
||||||
|
if (strcmp(i.name,"User")==0) {
|
||||||
|
userCategory=&i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userCategory==NULL) {
|
||||||
|
logE("could not find user category!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (redundancy) {
|
||||||
|
char oldPath[4096];
|
||||||
|
char newPath[4096];
|
||||||
|
|
||||||
|
if (fileExists(path.c_str())==1) {
|
||||||
|
logD("rotating preset files...");
|
||||||
|
for (int i=4; i>=0; i--) {
|
||||||
|
if (i>0) {
|
||||||
|
snprintf(oldPath,4095,"%s.%d",path.c_str(),i);
|
||||||
|
} else {
|
||||||
|
strncpy(oldPath,path.c_str(),4095);
|
||||||
|
}
|
||||||
|
snprintf(newPath,4095,"%s.%d",path.c_str(),i+1);
|
||||||
|
|
||||||
|
if (i>=4) {
|
||||||
|
logV("remove %s",oldPath);
|
||||||
|
deleteFile(oldPath);
|
||||||
|
} else {
|
||||||
|
logV("move %s to %s",oldPath,newPath);
|
||||||
|
moveFiles(oldPath,newPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logD("saving user presets: %s",path);
|
||||||
|
FILE* f=ps_fopen(path.c_str(),"wb");
|
||||||
|
if (f==NULL) {
|
||||||
|
logW("could not write presets! %s",strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeSubEntries(f,userCategory->systems,0);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
logD("presets written successfully.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// user presets management
|
||||||
|
void FurnaceGUI::printPresets(std::vector<FurnaceGUISysDef>& items, size_t depth, std::vector<int>& depthStack) {
|
||||||
|
if (depth>0) ImGui::Indent();
|
||||||
|
int index=0;
|
||||||
|
for (FurnaceGUISysDef& i: items) {
|
||||||
|
bool isSelected=(selectedUserPreset.size()==(depth+1));
|
||||||
|
if (isSelected) {
|
||||||
|
for (size_t j=0; j<=depth; j++) {
|
||||||
|
int item=-1;
|
||||||
|
if (j>=depthStack.size()) {
|
||||||
|
item=index;
|
||||||
|
} else {
|
||||||
|
item=depthStack[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedUserPreset[j]!=item) {
|
||||||
|
isSelected=false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::PushID(index+1);
|
||||||
|
if (ImGui::Selectable(i.name.c_str(),isSelected)) {
|
||||||
|
selectedUserPreset=depthStack;
|
||||||
|
selectedUserPreset.push_back(index);
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
|
if (!i.subDefs.empty()) {
|
||||||
|
depthStack.push_back(index);
|
||||||
|
ImGui::PushID(index);
|
||||||
|
printPresets(i.subDefs,depth+1,depthStack);
|
||||||
|
ImGui::PopID();
|
||||||
|
depthStack.pop_back();
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
if (depth>0) ImGui::Unindent();
|
||||||
|
}
|
||||||
|
|
||||||
|
FurnaceGUISysDef* FurnaceGUI::selectPreset(std::vector<FurnaceGUISysDef>& items) {
|
||||||
|
FurnaceGUISysDef* ret=NULL;
|
||||||
|
for (size_t i=0; i<selectedUserPreset.size(); i++) {
|
||||||
|
if (selectedUserPreset[i]<0 || selectedUserPreset[i]>(int)items.size()) return NULL;
|
||||||
|
ret=&items[selectedUserPreset[i]];
|
||||||
|
if (i<selectedUserPreset.size()-1) {
|
||||||
|
items=ret->subDefs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FurnaceGUI::drawUserPresets() {
|
||||||
|
if (nextWindow==GUI_WINDOW_USER_PRESETS) {
|
||||||
|
userPresetsOpen=true;
|
||||||
|
ImGui::SetNextWindowFocus();
|
||||||
|
nextWindow=GUI_WINDOW_NOTHING;
|
||||||
|
}
|
||||||
|
if (!userPresetsOpen) return;
|
||||||
|
if (ImGui::Begin("User Presets",&userPresetsOpen,globalWinFlags)) {
|
||||||
|
FurnaceGUISysCategory* userCategory=NULL;
|
||||||
|
for (FurnaceGUISysCategory& i: sysCategories) {
|
||||||
|
if (strcmp(i.name,"User")==0) {
|
||||||
|
userCategory=&i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> depthStack;
|
||||||
|
|
||||||
|
if (userCategory==NULL) {
|
||||||
|
ImGui::Text("Error! User category does not exist!");
|
||||||
|
} else if (ImGui::BeginTable("UserPresets",2,ImGuiTableFlags_BordersInnerV)) {
|
||||||
|
// preset list
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (ImGui::Button(ICON_FA_PLUS "##AddPreset")) {
|
||||||
|
userCategory->systems.push_back(FurnaceGUISysDef("New Preset",{}));
|
||||||
|
selectedUserPreset.clear();
|
||||||
|
selectedUserPreset.push_back(userCategory->systems.size()-1);
|
||||||
|
}
|
||||||
|
printPresets(userCategory->systems,0,depthStack);
|
||||||
|
|
||||||
|
// editor
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (selectedUserPreset.empty()) {
|
||||||
|
ImGui::Text("select a preset");
|
||||||
|
} else {
|
||||||
|
FurnaceGUISysDef* preset=selectPreset(userCategory->systems);
|
||||||
|
|
||||||
|
if (preset!=NULL) {
|
||||||
|
ImGui::AlignTextToFramePadding();
|
||||||
|
ImGui::Text("Name");
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
|
ImGui::InputText("##PName",&preset->name);
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("the rest...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button("Save and Close")) {
|
||||||
|
userPresetsOpen=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!userPresetsOpen) {
|
||||||
|
saveUserPresets(true);
|
||||||
|
}
|
||||||
|
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_USER_PRESETS;
|
||||||
|
ImGui::End();
|
||||||
|
}
|
Loading…
Reference in a new issue