2024-04-11 16:02:32 -04:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2024-04-25 13:55:59 -04:00
|
|
|
bool FurnaceGUI::loadUserPresets(bool redundancy, String path, bool append) {
|
|
|
|
if (path.empty()) path=e->getConfigPath()+PRESETS_FILE;
|
2024-04-11 16:02:32 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-04-25 13:55:59 -04:00
|
|
|
if (!append) userCategory->systems.clear();
|
2024-04-11 16:02:32 -04:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2024-04-12 04:30:57 -04:00
|
|
|
if (!key.empty()) {
|
2024-04-11 16:02:32 -04:00
|
|
|
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;
|
2024-07-25 21:14:08 -04:00
|
|
|
for (unsigned char j: i.name) {
|
2024-04-11 16:02:32 -04:00
|
|
|
if (beginning && j==' ') continue;
|
|
|
|
if (j=='=') continue;
|
|
|
|
if (j<0x20) continue;
|
|
|
|
safeName+=j;
|
|
|
|
}
|
|
|
|
|
|
|
|
String data;
|
|
|
|
for (int i=0; i<depth; i++) {
|
|
|
|
data+=" ";
|
|
|
|
}
|
2024-04-12 18:26:52 -04:00
|
|
|
data+=fmt::sprintf("%s=%s\n",safeName,taEncodeBase64(i.definition));
|
2024-04-11 16:02:32 -04:00
|
|
|
fputs(data.c_str(),f);
|
|
|
|
|
|
|
|
writeSubEntries(f,i.subDefs,depth+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-25 13:55:59 -04:00
|
|
|
bool FurnaceGUI::saveUserPresets(bool redundancy, String path) {
|
|
|
|
if (path.empty()) path=e->getConfigPath()+PRESETS_FILE;
|
2024-04-11 16:02:32 -04:00
|
|
|
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++) {
|
2024-06-16 02:41:55 -04:00
|
|
|
if (selectedUserPreset[i]<0 || selectedUserPreset[i]>=(int)items.size()) return NULL;
|
2024-04-11 16:02:32 -04:00
|
|
|
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;
|
2024-05-27 18:53:46 -04:00
|
|
|
if (ImGui::Begin("User Systems",&userPresetsOpen,globalWinFlags,_("User Systems"))) {
|
2024-04-11 16:02:32 -04:00
|
|
|
FurnaceGUISysCategory* userCategory=NULL;
|
|
|
|
for (FurnaceGUISysCategory& i: sysCategories) {
|
|
|
|
if (strcmp(i.name,"User")==0) {
|
|
|
|
userCategory=&i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<int> depthStack;
|
|
|
|
|
|
|
|
if (userCategory==NULL) {
|
2024-05-26 20:31:17 -04:00
|
|
|
ImGui::Text(_("Error! User category does not exist!"));
|
2024-04-13 16:08:36 -04:00
|
|
|
} else if (ImGui::BeginTable("UserPresets",2,ImGuiTableFlags_BordersInnerV,ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()))) {
|
2024-04-13 15:10:06 -04:00
|
|
|
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.25f);
|
|
|
|
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.75f);
|
2024-04-11 16:02:32 -04:00
|
|
|
// preset list
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TableNextColumn();
|
2024-04-13 16:08:36 -04:00
|
|
|
if (ImGui::BeginChild("UList",ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()))) {
|
|
|
|
ImGui::AlignTextToFramePadding();
|
2024-05-26 20:31:17 -04:00
|
|
|
ImGui::Text(_("Systems"));
|
2024-04-13 16:08:36 -04:00
|
|
|
ImGui::SameLine();
|
|
|
|
if (ImGui::Button(ICON_FA_PLUS "##AddPreset")) {
|
2024-05-26 20:31:17 -04:00
|
|
|
userCategory->systems.push_back(FurnaceGUISysDef(_("New Preset"),{}));
|
2024-04-13 16:08:36 -04:00
|
|
|
selectedUserPreset.clear();
|
|
|
|
selectedUserPreset.push_back(userCategory->systems.size()-1);
|
|
|
|
}
|
|
|
|
printPresets(userCategory->systems,0,depthStack);
|
2024-04-11 16:02:32 -04:00
|
|
|
}
|
2024-04-13 16:08:36 -04:00
|
|
|
ImGui::EndChild();
|
2024-04-11 16:02:32 -04:00
|
|
|
|
|
|
|
// editor
|
|
|
|
ImGui::TableNextColumn();
|
2024-04-13 16:08:36 -04:00
|
|
|
if (ImGui::BeginChild("UEdit",ImVec2(ImGui::GetContentRegionAvail().x,ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()))) {
|
|
|
|
if (selectedUserPreset.empty()) {
|
2024-05-26 20:31:17 -04:00
|
|
|
ImGui::Text(_("select a preset"));
|
2024-04-13 16:08:36 -04:00
|
|
|
} else {
|
|
|
|
FurnaceGUISysDef* preset=selectPreset(userCategory->systems);
|
|
|
|
bool doRemovePreset=false;
|
2024-04-12 18:26:52 -04:00
|
|
|
|
2024-04-13 16:08:36 -04:00
|
|
|
if (preset!=NULL) {
|
|
|
|
ImGui::AlignTextToFramePadding();
|
2024-05-26 20:31:17 -04:00
|
|
|
ImGui::Text(_("Name"));
|
2024-04-12 18:26:52 -04:00
|
|
|
ImGui::SameLine();
|
2024-05-26 20:31:17 -04:00
|
|
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(_("Remove")).x-ImGui::GetStyle().ItemSpacing.x*2.0-ImGui::GetStyle().ItemInnerSpacing.x*2.0);
|
2024-04-13 16:08:36 -04:00
|
|
|
ImGui::InputText("##PName",&preset->name);
|
2024-04-12 18:26:52 -04:00
|
|
|
ImGui::SameLine();
|
|
|
|
pushDestColor();
|
2024-05-26 20:31:17 -04:00
|
|
|
if (ImGui::Button(_("Remove##UPresetRemove"))) {
|
2024-04-13 16:08:36 -04:00
|
|
|
doRemovePreset=true;
|
2024-04-12 18:26:52 -04:00
|
|
|
}
|
|
|
|
popDestColor();
|
2024-04-13 16:08:36 -04:00
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
int doRemove=-1;
|
|
|
|
bool mustBake=false;
|
|
|
|
|
|
|
|
for (size_t i=0; i<preset->orig.size(); i++) {
|
|
|
|
String tempID;
|
|
|
|
FurnaceGUISysDefChip& chip=preset->orig[i];
|
|
|
|
|
|
|
|
bool doInvert=(chip.vol<0);
|
|
|
|
float vol=fabs(chip.vol);
|
|
|
|
ImGui::PushID(i);
|
|
|
|
|
|
|
|
tempID=fmt::sprintf("%s##USystem",getSystemName(chip.sys));
|
2024-05-26 20:31:17 -04:00
|
|
|
ImGui::Button(tempID.c_str(),ImVec2(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(_("Invert")).x-ImGui::GetFrameHeightWithSpacing()*2.0-ImGui::GetStyle().ItemSpacing.x*2.0,0));
|
2024-04-13 16:08:36 -04:00
|
|
|
if (ImGui::BeginPopupContextItem("SysPickerCU",ImGuiPopupFlags_MouseButtonLeft)) {
|
2024-08-24 05:24:58 -04:00
|
|
|
DivSystem picked=systemPicker(false);
|
2024-04-13 16:08:36 -04:00
|
|
|
if (picked!=DIV_SYSTEM_NULL) {
|
|
|
|
chip.sys=picked;
|
|
|
|
mustBake=true;
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
}
|
|
|
|
ImGui::EndPopup();
|
2024-04-12 18:26:52 -04:00
|
|
|
}
|
|
|
|
|
2024-04-13 16:08:36 -04:00
|
|
|
ImGui::SameLine();
|
2024-05-26 20:31:17 -04:00
|
|
|
if (ImGui::Checkbox(_("Invert"),&doInvert)) {
|
2024-04-13 16:08:36 -04:00
|
|
|
chip.vol=-chip.vol;
|
|
|
|
mustBake=true;
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
pushDestColor();
|
|
|
|
if (ImGui::Button(ICON_FA_MINUS "##USysRemove")) {
|
|
|
|
doRemove=i;
|
|
|
|
mustBake=true;
|
|
|
|
}
|
|
|
|
popDestColor();
|
|
|
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-ImGui::GetFrameHeightWithSpacing()*2.0-ImGui::GetStyle().ItemSpacing.x*2.0);
|
2024-05-26 20:31:17 -04:00
|
|
|
if (CWSliderFloat(_("Volume"),&vol,0.0f,3.0f)) {
|
2024-04-13 16:08:36 -04:00
|
|
|
if (doInvert) {
|
|
|
|
if (vol<0.0001) vol=0.0001;
|
|
|
|
}
|
|
|
|
if (vol<0) vol=0;
|
|
|
|
if (vol>10) vol=10;
|
|
|
|
chip.vol=doInvert?-vol:vol;
|
2024-04-12 18:26:52 -04:00
|
|
|
mustBake=true;
|
2024-04-13 16:08:36 -04:00
|
|
|
} rightClickable
|
|
|
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-ImGui::GetFrameHeightWithSpacing()*2.0-ImGui::GetStyle().ItemSpacing.x*2.0);
|
2024-05-26 20:31:17 -04:00
|
|
|
if (CWSliderFloat(_("Panning"),&chip.pan,-1.0f,1.0f)) {
|
2024-04-13 16:08:36 -04:00
|
|
|
if (chip.pan<-1.0f) chip.pan=-1.0f;
|
|
|
|
if (chip.pan>1.0f) chip.pan=1.0f;
|
|
|
|
mustBake=true;
|
|
|
|
} rightClickable
|
|
|
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-ImGui::GetFrameHeightWithSpacing()*2.0-ImGui::GetStyle().ItemSpacing.x*2.0);
|
2024-05-26 20:31:17 -04:00
|
|
|
if (CWSliderFloat(_("Front/Rear"),&chip.panFR,-1.0f,1.0f)) {
|
2024-04-13 16:08:36 -04:00
|
|
|
if (chip.panFR<-1.0f) chip.panFR=-1.0f;
|
|
|
|
if (chip.panFR>1.0f) chip.panFR=1.0f;
|
|
|
|
mustBake=true;
|
|
|
|
} rightClickable
|
|
|
|
|
2024-05-26 20:31:17 -04:00
|
|
|
if (ImGui::TreeNode(_("Configure"))) {
|
2024-04-13 16:08:36 -04:00
|
|
|
DivConfig sysFlags;
|
2024-04-25 14:30:30 -04:00
|
|
|
sysFlags.loadFromMemory(chip.flags.c_str());
|
2024-04-13 16:08:36 -04:00
|
|
|
if (drawSysConf(-1,i,chip.sys,sysFlags,false)) {
|
2024-04-25 14:30:30 -04:00
|
|
|
chip.flags=sysFlags.toString();
|
2024-04-13 16:08:36 -04:00
|
|
|
mustBake=true;
|
|
|
|
}
|
|
|
|
ImGui::TreePop();
|
2024-04-12 18:26:52 -04:00
|
|
|
}
|
2024-04-13 16:08:36 -04:00
|
|
|
|
|
|
|
ImGui::PopID();
|
2024-04-12 18:26:52 -04:00
|
|
|
}
|
|
|
|
|
2024-04-13 16:08:36 -04:00
|
|
|
if (doRemove>=0) {
|
|
|
|
preset->orig.erase(preset->orig.begin()+doRemove);
|
|
|
|
mustBake=true;
|
|
|
|
}
|
2024-04-12 18:26:52 -04:00
|
|
|
|
2024-04-13 16:08:36 -04:00
|
|
|
ImGui::Button(ICON_FA_PLUS "##SysAddU");
|
|
|
|
if (ImGui::BeginPopupContextItem("SysPickerU",ImGuiPopupFlags_MouseButtonLeft)) {
|
2024-08-24 05:24:58 -04:00
|
|
|
DivSystem picked=systemPicker(false);
|
2024-04-13 16:08:36 -04:00
|
|
|
if (picked!=DIV_SYSTEM_NULL) {
|
|
|
|
preset->orig.push_back(FurnaceGUISysDefChip(picked,1.0f,0.0f,""));
|
|
|
|
mustBake=true;
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
}
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
2024-04-12 18:26:52 -04:00
|
|
|
|
2024-04-13 16:08:36 -04:00
|
|
|
ImGui::Separator();
|
|
|
|
|
2024-05-26 20:31:17 -04:00
|
|
|
ImGui::Text(_("Advanced"));
|
2024-04-13 16:08:36 -04:00
|
|
|
if (ImGui::InputTextMultiline("##UExtra",&preset->extra,ImVec2(ImGui::GetContentRegionAvail().x,120.0f*dpiScale),ImGuiInputTextFlags_UndoRedo)) {
|
2024-04-12 18:26:52 -04:00
|
|
|
mustBake=true;
|
|
|
|
}
|
2024-04-13 17:56:02 -04:00
|
|
|
if (ImGui::IsItemHovered()) {
|
2024-05-26 20:31:17 -04:00
|
|
|
ImGui::SetTooltip(_(
|
2024-04-13 17:56:02 -04:00
|
|
|
"insert additional settings in `option=value` format.\n"
|
|
|
|
"available options:\n"
|
2024-09-02 16:39:35 -04:00
|
|
|
"- tickRate \n"
|
|
|
|
"- chanMask \n"
|
2024-05-26 20:31:17 -04:00
|
|
|
));
|
2024-04-13 17:56:02 -04:00
|
|
|
}
|
2024-04-13 16:08:36 -04:00
|
|
|
|
|
|
|
if (mustBake) preset->bake();
|
|
|
|
} else {
|
|
|
|
selectedUserPreset.clear();
|
2024-04-12 18:26:52 -04:00
|
|
|
}
|
|
|
|
|
2024-04-13 16:08:36 -04:00
|
|
|
if (doRemovePreset) {
|
|
|
|
std::vector<FurnaceGUISysDef>& items=userCategory->systems;
|
|
|
|
FurnaceGUISysDef* target=NULL;
|
|
|
|
for (size_t i=0; i<selectedUserPreset.size(); i++) {
|
|
|
|
if (selectedUserPreset[i]<0 || selectedUserPreset[i]>(int)items.size()) break;
|
|
|
|
target=&items[selectedUserPreset[i]];
|
|
|
|
if (i<selectedUserPreset.size()-1) {
|
|
|
|
items=target->subDefs;
|
|
|
|
} else {
|
|
|
|
items.erase(items.begin()+selectedUserPreset[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
selectedUserPreset.clear();
|
|
|
|
}
|
2024-04-11 16:02:32 -04:00
|
|
|
}
|
|
|
|
}
|
2024-04-13 16:08:36 -04:00
|
|
|
ImGui::EndChild();
|
2024-04-11 16:02:32 -04:00
|
|
|
|
|
|
|
ImGui::EndTable();
|
|
|
|
}
|
|
|
|
|
2024-05-26 20:31:17 -04:00
|
|
|
if (ImGui::Button(_("Save and Close"))) {
|
2024-04-11 16:02:32 -04:00
|
|
|
userPresetsOpen=false;
|
|
|
|
}
|
2024-04-25 13:55:59 -04:00
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::Dummy(ImVec2(8.0f*dpiScale,1.0f));
|
|
|
|
ImGui::SameLine();
|
2024-05-26 20:31:17 -04:00
|
|
|
if (ImGui::Button(_("Import"))) {
|
2024-04-25 13:55:59 -04:00
|
|
|
openFileDialog(GUI_FILE_IMPORT_USER_PRESETS);
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
2024-05-26 20:31:17 -04:00
|
|
|
if (ImGui::Button(_("Import (replace)"))) {
|
2024-04-25 13:55:59 -04:00
|
|
|
openFileDialog(GUI_FILE_IMPORT_USER_PRESETS_REPLACE);
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
2024-05-26 20:31:17 -04:00
|
|
|
if (ImGui::Button(_("Export"))) {
|
2024-04-25 13:55:59 -04:00
|
|
|
openFileDialog(GUI_FILE_EXPORT_USER_PRESETS);
|
|
|
|
}
|
2024-04-11 16:02:32 -04:00
|
|
|
}
|
|
|
|
if (!userPresetsOpen) {
|
|
|
|
saveUserPresets(true);
|
|
|
|
}
|
|
|
|
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_USER_PRESETS;
|
|
|
|
ImGui::End();
|
|
|
|
}
|