diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index b86a50de3..168acee83 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -319,6 +319,9 @@ void FurnaceGUI::doAction(int what) { case GUI_ACTION_WINDOW_CS_PLAYER: nextWindow=GUI_WINDOW_CS_PLAYER; break; + case GUI_ACTION_WINDOW_USER_PRESETS: + nextWindow=GUI_WINDOW_USER_PRESETS; + break; case GUI_ACTION_COLLAPSE_WINDOW: collapseWindow=true; @@ -424,6 +427,8 @@ void FurnaceGUI::doAction(int what) { case GUI_WINDOW_CS_PLAYER: csPlayerOpen=false; break; + case GUI_WINDOW_USER_PRESETS: + userPresetsOpen=false; default: break; } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 343cbd151..75d660366 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3479,6 +3479,7 @@ bool FurnaceGUI::loop() { DECLARE_METRIC(regView) DECLARE_METRIC(log) DECLARE_METRIC(effectList) + DECLARE_METRIC(userPresets) DECLARE_METRIC(popup) #ifdef IS_MOBILE @@ -4051,6 +4052,7 @@ bool FurnaceGUI::loop() { IMPORT_CLOSE(xyOscOpen); IMPORT_CLOSE(memoryOpen); IMPORT_CLOSE(csPlayerOpen); + IMPORT_CLOSE(userPresetsOpen); } else if (pendingLayoutImportStep==1) { // let the UI settle } else if (pendingLayoutImportStep==2) { @@ -4383,6 +4385,9 @@ bool FurnaceGUI::loop() { toggleMobileUI(!mobileUI); } #endif + if (ImGui::MenuItem("manage presets...",BIND_FOR(GUI_ACTION_WINDOW_USER_PRESETS))) { + userPresetsOpen=true; + } if (ImGui::MenuItem("settings...",BIND_FOR(GUI_ACTION_WINDOW_SETTINGS))) { syncSettings(); settingsOpen=true; @@ -4664,6 +4669,7 @@ bool FurnaceGUI::loop() { MEASURE(grooves,drawGrooves()); MEASURE(regView,drawRegView()); MEASURE(memory,drawMemory()); + MEASURE(userPresets,drawUserPresets()); } else { globalWinFlags=0; ImGui::DockSpaceOverViewport(NULL,lockLayout?(ImGuiDockNodeFlags_NoWindowMenuButton|ImGuiDockNodeFlags_NoMove|ImGuiDockNodeFlags_NoResize|ImGuiDockNodeFlags_NoCloseButton|ImGuiDockNodeFlags_NoDocking|ImGuiDockNodeFlags_NoDockingSplitMe|ImGuiDockNodeFlags_NoDockingSplitOther):0); @@ -4706,6 +4712,7 @@ bool FurnaceGUI::loop() { MEASURE(regView,drawRegView()); MEASURE(log,drawLog()); MEASURE(effectList,drawEffectList()); + MEASURE(userPresets,drawUserPresets()); } // NEW CODE - REMOVE WHEN DONE @@ -6610,6 +6617,7 @@ bool FurnaceGUI::init() { subSongsOpen=e->getConfBool("subSongsOpen",true); findOpen=e->getConfBool("findOpen",false); spoilerOpen=e->getConfBool("spoilerOpen",false); + userPresetsOpen=e->getConfBool("userPresetsOpen",false); insListDir=e->getConfBool("insListDir",false); waveListDir=e->getConfBool("waveListDir",false); @@ -7007,6 +7015,8 @@ bool FurnaceGUI::init() { ImGui::CreateContext(); rend->initGUI(sdlWin); + loadUserPresets(true); + // NEW CODE - REMOVE WHEN DONE newOscFragment=rend->getStupidFragment(); @@ -7169,6 +7179,7 @@ void FurnaceGUI::commitState() { e->setConf("subSongsOpen",subSongsOpen); e->setConf("findOpen",findOpen); e->setConf("spoilerOpen",spoilerOpen); + e->setConf("userPresetsOpen",userPresetsOpen); // commit dir state e->setConf("insListDir",insListDir); @@ -7271,6 +7282,9 @@ void FurnaceGUI::commitState() { bool FurnaceGUI::finish(bool saveConfig) { commitState(); + if (userPresetsOpen) { + saveUserPresets(true); + } if (saveConfig) { logI("saving config."); e->saveConf(); @@ -7521,6 +7535,7 @@ FurnaceGUI::FurnaceGUI(): xyOscOpen(false), memoryOpen(false), csPlayerOpen(false), + userPresetsOpen(false), shortIntro(false), insListDir(false), waveListDir(false), diff --git a/src/gui/gui.h b/src/gui/gui.h index f73f7fed0..5c39105df 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -485,6 +485,7 @@ enum FurnaceGUIWindows { GUI_WINDOW_INTRO_MON, GUI_WINDOW_MEMORY, GUI_WINDOW_CS_PLAYER, + GUI_WINDOW_USER_PRESETS, GUI_WINDOW_SPOILER }; @@ -677,6 +678,7 @@ enum FurnaceGUIActions { GUI_ACTION_WINDOW_XY_OSC, GUI_ACTION_WINDOW_MEMORY, GUI_ACTION_WINDOW_CS_PLAYER, + GUI_ACTION_WINDOW_USER_PRESETS, GUI_ACTION_COLLAPSE_WINDOW, GUI_ACTION_CLOSE_WINDOW, @@ -2081,7 +2083,7 @@ class FurnaceGUI { bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen; bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen; bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen, clockOpen, speedOpen; - bool groovesOpen, xyOscOpen, memoryOpen, csPlayerOpen; + bool groovesOpen, xyOscOpen, memoryOpen, csPlayerOpen, userPresetsOpen; bool shortIntro; bool insListDir, waveListDir, sampleListDir; @@ -2610,6 +2612,7 @@ class FurnaceGUI { void drawClock(); void drawTutorial(); void drawXYOsc(); + void drawUserPresets(); void parseKeybinds(); void promptKey(int which); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index 08b84dc1f..3c15519b7 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -610,6 +610,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={ D("WINDOW_XY_OSC", "Oscilloscope (X-Y)", 0), D("WINDOW_MEMORY", "Memory Composition", 0), D("WINDOW_CS_PLAYER", "Command Stream Player", 0), + D("WINDOW_USER_PRESETS", "User Presets", 0), D("COLLAPSE_WINDOW", "Collapse/expand current window", 0), D("CLOSE_WINDOW", "Close current window", FURKMOD_SHIFT|SDLK_ESCAPE), diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 9cb370b4f..c114c26ea 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -21,6 +21,7 @@ #include "../baseutils.h" #include "../fileutils.h" #include +#include // add system configurations here. // every entry is written in the following format: @@ -3164,6 +3165,20 @@ FurnaceGUISysDef::FurnaceGUISysDef(const char* n, const char* def, DivEngine* e) #define REDUNDANCY_NUM_ATTEMPTS 5 #define CHECK_BUF_SIZE 8192 +std::vector* digDeep(std::vector& entries, int depth) { + if (depth==0) return &entries; + std::vector& result=entries; + + for (int i=0; igetConfigPath()+PRESETS_FILE; String line; @@ -3231,13 +3246,13 @@ bool FurnaceGUI::loadUserPresets(bool redundancy) { // we couldn't read at all if (f==NULL) { - logD("config does not exist"); + logD("presets file does not exist"); return false; } } else { f=ps_fopen(path.c_str(),"rb"); if (f==NULL) { - logD("config does not exist"); + logD("presets file does not exist"); return false; } } @@ -3258,6 +3273,8 @@ bool FurnaceGUI::loadUserPresets(bool redundancy) { return false; } + userCategory->systems.clear(); + char nextLine[4096]; while (!feof(f)) { if (fgets(nextLine,4095,f)==NULL) { @@ -3289,10 +3306,11 @@ bool FurnaceGUI::loadUserPresets(bool redundancy) { } } } + indent>>=1; - // TODO: nesting if (!key.empty() && !value.empty()) { - userCategory->systems.push_back(FurnaceGUISysDef(key.c_str(),value.c_str(),e)); + std::vector* where=digDeep(userCategory->systems,indent); + where->push_back(FurnaceGUISysDef(key.c_str(),value.c_str(),e)); } } @@ -3300,6 +3318,109 @@ bool FurnaceGUI::loadUserPresets(bool redundancy) { return true; } +void writeSubEntries(FILE* f, std::vector& 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; igetConfigPath()+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::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)) { + if (ImGui::BeginTable("UserPresets",2,ImGuiTableFlags_BordersInnerV)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Presets..."); + ImGui::TableNextColumn(); + ImGui::Text("Edit..."); + + 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(); +} \ No newline at end of file