/* BodySlide and Outfit Studio See the included LICENSE file */ #include "SliderPresets.h" #include "../utils/PlatformUtil.h" #include "../utils/StringStuff.h" #include #include using namespace tinyxml2; void PresetCollection::Clear() { namedSliderPresets.clear(); presetFileNames.clear(); presetGroups.clear(); } void PresetCollection::ClearSlider(const std::string& presetName, const std::string& sliderName, const bool big) { if (namedSliderPresets.find(presetName) != namedSliderPresets.end()) { if (big) namedSliderPresets[presetName][sliderName].big = -10000.0f; else namedSliderPresets[presetName][sliderName].small = -10000.0f; } } void PresetCollection::GetPresetNames(std::vector& outNames) { for (auto& it : namedSliderPresets) outNames.push_back(it.first); } void PresetCollection::AddEmptyPreset(const std::string& set) { namedSliderPresets.try_emplace(set); } void PresetCollection::SetSliderPreset(const std::string& set, const std::string& slider, float big, float small) { std::map newPreset; SliderPreset sp; if (namedSliderPresets.find(set) == namedSliderPresets.end()) { sp.big = sp.small = -10000.0f; if (big > -10000.0f) sp.big = big; if (small > -10000.0f) sp.small = small; newPreset[slider] = sp; namedSliderPresets[set] = newPreset; } else { if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) { sp.big = sp.small = -10000.0f; if (big > -10000.0f) sp.big = big; if (small > -10000.0f) sp.small = small; namedSliderPresets[set][slider] = sp; } else { if (big > -10000.0f) namedSliderPresets[set][slider].big = big; if (small > -10000.0f) namedSliderPresets[set][slider].small = small; } } } bool PresetCollection::GetSliderExists(const std::string& set, const std::string& slider) { if (namedSliderPresets.find(set) == namedSliderPresets.end()) return false; if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) return false; return true; } bool PresetCollection::GetBigPreset(const std::string& set, const std::string& slider, float& big) { float b; if (namedSliderPresets.find(set) == namedSliderPresets.end()) return false; if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) return false; b = namedSliderPresets[set][slider].big; if (b > -10000.0f) { big = b; return true; } return false; } bool PresetCollection::GetSmallPreset(const std::string& set, const std::string& slider, float& small) { float b; if (namedSliderPresets.find(set) == namedSliderPresets.end()) return false; if (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) return false; b = namedSliderPresets[set][slider].small; if (b > -10000.0f) { small = b; return true; } return false; } std::string PresetCollection::GetPresetFileName(const std::string& set) { auto result = presetFileNames.find(set); if (result != presetFileNames.end()) return result->second; return ""; } void PresetCollection::GetPresetGroups(const std::string& set, std::vector& outGroups) { outGroups.clear(); auto result = presetGroups.find(set); if (result != presetGroups.end()) outGroups = result->second; } bool PresetCollection::LoadPresets(const std::string& basePath, const std::string& sliderSet, std::vector& groupFilter, bool allPresets) { wxArrayString files; wxString path = wxString::FromUTF8(basePath); wxDir::GetAllFiles(path, &files, "*.xml"); for (auto& file : files) LoadPresetFile(file.ToUTF8().data(), sliderSet, groupFilter, allPresets); return 0; } bool PresetCollection::LoadPresetFile(const std::string& filePath, const std::string& sliderSet, std::vector& groupFilter, bool allPresets, std::vector* outLoadedNames) { XMLDocument doc; XMLElement* root; XMLElement* element; XMLElement* g; XMLElement* setSlider; std::string presetName, sliderName, applyTo; float o, b, s; FILE* fp = nullptr; #ifdef _WINDOWS std::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(filePath); int ret = _wfopen_s(&fp, winFileName.c_str(), L"rb"); if (ret || !fp) return false; #else fp = fopen(filePath.c_str(), "rb"); if (!fp) return false; #endif int ret2 = doc.LoadFile(fp); fclose(fp); if (ret2) return false; root = doc.FirstChildElement("SliderPresets"); if (!root) return false; element = root->FirstChildElement("Preset"); while (element) { bool skip = true; std::vector groups; g = element->FirstChildElement("Group"); while (g) { const char* groupNameAttr = g->Attribute("name"); if (!groupNameAttr) { g = g->NextSiblingElement("Group"); continue; } std::string groupName = groupNameAttr; groups.push_back(groupName); for (auto& filter : groupFilter) { if (groupName == filter) { skip = false; break; } } g = g->NextSiblingElement("Group"); } const char* setAttr = element->Attribute("set"); if ((setAttr && setAttr == sliderSet) || allPresets) skip = false; if (skip) { element = element->NextSiblingElement("Preset"); continue; } const char* nameAttr = element->Attribute("name"); if (!nameAttr) { element = element->NextSiblingElement("Preset"); continue; } presetName = nameAttr; if (presetFileNames.find(presetName) != presetFileNames.end()) { element = element->NextSiblingElement("Preset"); continue; } presetFileNames[presetName] = filePath; presetGroups[presetName] = groups; AddEmptyPreset(presetName); if (outLoadedNames) outLoadedNames->push_back(presetName); setSlider = element->FirstChildElement("SetSlider"); while (setSlider) { const char* sliderNameAttr = setSlider->Attribute("name"); const char* sizeAttr = setSlider->Attribute("size"); if (!sliderNameAttr || !sizeAttr) { setSlider = setSlider->NextSiblingElement("SetSlider"); continue; } sliderName = sliderNameAttr; applyTo = sizeAttr; o = setSlider->FloatAttribute("value") / 100.0f; s = b = -10000.0f; if (applyTo == "small") s = o; else if (applyTo == "big") b = o; else if (applyTo == "both") s = b = o; SetSliderPreset(presetName, sliderName, b, s); setSlider = setSlider->NextSiblingElement("SetSlider"); } element = element->NextSiblingElement("Preset"); } return true; } int PresetCollection::SavePreset(const std::string& filePath, const std::string& presetName, const std::string& sliderSetName, std::vector& assignGroups) { XMLElement* newElement = nullptr; XMLDocument outDoc; XMLNode* slidersNode = nullptr; XMLElement* presetElem = nullptr; bool loaded = false; FILE* fp = nullptr; #ifdef _WINDOWS std::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(filePath); int ret = _wfopen_s(&fp, winFileName.c_str(), L"rb"); if (ret == 0 && fp) loaded = true; #else fp = fopen(filePath.c_str(), "rb"); if (fp) loaded = true; #endif if (loaded) { int retDoc = outDoc.LoadFile(fp); fclose(fp); fp = nullptr; if (retDoc != 0) loaded = false; } if (loaded) { // File exists - merge data. slidersNode = outDoc.FirstChildElement("SliderPresets"); presetElem = slidersNode->FirstChildElement("Preset"); while (presetElem) { // Replace preset if found in file. const char* pName = presetElem->Attribute("name"); if (pName && StringsEqualInsens(pName, presetName.c_str())) { XMLElement* tmpElem = presetElem; presetElem = presetElem->NextSiblingElement("Preset"); slidersNode->DeleteChild(tmpElem); } else presetElem = presetElem->NextSiblingElement("Preset"); } } else { newElement = outDoc.NewElement("SliderPresets"); slidersNode = outDoc.InsertEndChild(newElement); } newElement = outDoc.NewElement("Preset"); presetElem = slidersNode->InsertEndChild(newElement)->ToElement(); presetElem->SetAttribute("name", presetName.c_str()); presetElem->SetAttribute("set", sliderSetName.c_str()); XMLElement* sliderElem; for (auto& group : assignGroups) { newElement = outDoc.NewElement("Group"); sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); sliderElem->SetAttribute("name", group.c_str()); } for (auto& p : namedSliderPresets[presetName]) { if (p.second.big > -10000.0f) { newElement = outDoc.NewElement("SetSlider"); sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); sliderElem->SetAttribute("name", p.first.c_str()); sliderElem->SetAttribute("size", "big"); sliderElem->SetAttribute("value", (int)(p.second.big * 100.0f)); } if (p.second.small > -10000.0f) { newElement = outDoc.NewElement("SetSlider"); sliderElem = presetElem->InsertEndChild(newElement)->ToElement(); sliderElem->SetAttribute("name", p.first.c_str()); sliderElem->SetAttribute("size", "small"); sliderElem->SetAttribute("value", (int)(p.second.small * 100.0f)); } } #ifdef _WINDOWS winFileName = PlatformUtil::MultiByteToWideUTF8(filePath); ret = _wfopen_s(&fp, winFileName.c_str(), L"w"); if (ret || !fp) return 1; #else fp = fopen(filePath.c_str(), "w"); if (!fp) return 1; #endif outDoc.SetBOM(true); const tinyxml2::XMLNode* firstChild = outDoc.FirstChild(); if (!firstChild || !firstChild->ToDeclaration()) outDoc.InsertFirstChild(outDoc.NewDeclaration()); int retSaveDoc = outDoc.SaveFile(fp); fclose(fp); if (retSaveDoc) return retSaveDoc; presetFileNames[presetName] = filePath; presetGroups[presetName] = assignGroups; return 0; } int PresetCollection::DeletePreset(const std::string& filePath, const std::string& presetName) { FILE* fp = nullptr; #ifdef _WINDOWS std::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(filePath); int ret = _wfopen_s(&fp, winFileName.c_str(), L"rb"); if (ret || !fp) return -1; #else fp = fopen(filePath.c_str(), "rb"); if (!fp) return -1; #endif XMLDocument doc; int ret2 = doc.LoadFile(fp); fclose(fp); fp = nullptr; if (ret2) return -1; XMLNode* slidersNode = doc.FirstChildElement("SliderPresets"); if (slidersNode) { XMLElement* presetElem = slidersNode->FirstChildElement("Preset"); while (presetElem) { const char* pName = presetElem->Attribute("name"); if (pName && StringsEqualInsens(pName, presetName.c_str())) { slidersNode->DeleteChild(presetElem); break; } else presetElem = presetElem->NextSiblingElement("Preset"); } } #ifdef _WINDOWS winFileName = PlatformUtil::MultiByteToWideUTF8(filePath); ret = _wfopen_s(&fp, winFileName.c_str(), L"w"); if (ret || !fp) return -1; #else fp = fopen(filePath.c_str(), "w"); if (!fp) return -1; #endif doc.SetBOM(true); const tinyxml2::XMLNode* firstChild = doc.FirstChild(); if (!firstChild || !firstChild->ToDeclaration()) doc.InsertFirstChild(doc.NewDeclaration()); int retSaveDoc = doc.SaveFile(fp); fclose(fp); if (retSaveDoc) return retSaveDoc; namedSliderPresets.erase(presetName); presetFileNames.erase(presetName); presetGroups.erase(presetName); return 0; }