furnace/src/gui/newSong.cpp

271 lines
9.3 KiB
C++
Raw Normal View History

/**
* Furnace Tracker - multi-system chiptune tracker
2024-01-16 21:26:57 -05:00
* 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 "misc/cpp/imgui_stdlib.h"
#include <fmt/printf.h>
#include <algorithm>
String sysDefID;
void FurnaceGUI::drawSysDefs(std::vector<FurnaceGUISysDef>& category, bool& accepted, std::vector<int>& sysDefStack) {
int index=0;
String sysDefIDLeader="##NS";
for (int i: sysDefStack) {
sysDefIDLeader+=fmt::sprintf("/%d",i);
}
2024-03-20 15:49:52 -04:00
for (FurnaceGUISysDef& i: category) {
2024-03-20 15:59:49 -04:00
bool treeNode=false;
2024-03-20 16:06:56 -04:00
bool isHovered=false;
2024-03-20 15:49:52 -04:00
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (!i.subDefs.empty()) {
if (i.orig.empty()) {
sysDefID=fmt::sprintf("%s%s/%dS",i.name,sysDefIDLeader,index);
} else {
sysDefID=fmt::sprintf("%s/%dS",sysDefIDLeader,index);
}
2024-03-20 18:55:49 -04:00
treeNode=ImGui::TreeNodeEx(sysDefID.c_str(),i.orig.empty()?ImGuiTreeNodeFlags_SpanAvailWidth:0);
2024-03-20 15:49:52 -04:00
ImGui::SameLine();
}
if (!i.orig.empty()) {
sysDefID=fmt::sprintf("%s%s/%d",i.name,sysDefIDLeader,index);
if (ImGui::Selectable(sysDefID.c_str(),false,ImGuiSelectableFlags_DontClosePopups)) {
nextDesc=i.definition;
nextDescName=i.name;
accepted=true;
}
if (ImGui::IsItemHovered()) isHovered=true;
} else if (i.subDefs.empty()) {
ImGui::TextUnformatted(i.name.c_str());
if (ImGui::IsItemHovered()) isHovered=true;
2024-03-20 15:49:52 -04:00
}
2024-03-20 15:59:49 -04:00
if (treeNode) {
sysDefStack.push_back(index);
drawSysDefs(i.subDefs,accepted,sysDefStack);
sysDefStack.erase(sysDefStack.end()-1);
2024-03-20 15:59:49 -04:00
ImGui::TreePop();
}
2024-03-20 16:06:56 -04:00
if (isHovered) {
2024-03-20 15:49:52 -04:00
if (ImGui::BeginTooltip()) {
std::map<DivSystem,int> chipCounts;
std::vector<DivSystem> chips;
for (FurnaceGUISysDefChip chip: i.orig) {
if (chipCounts.find(chip.sys)==chipCounts.end()) {
chipCounts[chip.sys]=1;
chips.push_back(chip.sys);
} else {
chipCounts[chip.sys]+=1;
}
}
for (size_t chipIndex=0; chipIndex<chips.size(); chipIndex++) {
DivSystem chip=chips[chipIndex];
const DivSysDef* sysDef=e->getSystemDef(chip);
ImGui::PushTextWrapPos(MIN(scrW*dpiScale,400.0f*dpiScale));
ImGui::Text("%s (x%d): ",sysDef->name,chipCounts[chip]);
ImGui::Text("%s",sysDef->description);
ImGui::PopTextWrapPos();
if (chipIndex+1<chips.size()) {
ImGui::Separator();
}
}
ImGui::EndTooltip();
}
}
index++;
2024-03-20 15:49:52 -04:00
}
}
void FurnaceGUI::drawNewSong() {
bool accepted=false;
std::vector<int> sysDefStack;
ImGui::PushFont(bigFont);
ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize("Choose a System!").x)*0.5);
ImGui::Text("Choose a System!");
ImGui::PopFont();
ImVec2 avail=ImGui::GetContentRegionAvail();
avail.y-=ImGui::GetFrameHeightWithSpacing();
if (ImGui::BeginChild("sysPickerC",avail,false,ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) {
2023-04-03 10:11:26 -04:00
if (newSongFirstFrame)
ImGui::SetKeyboardFocusHere();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputTextWithHint("##SysSearch","Search...",&newSongQuery)) {
String lowerCase=newSongQuery;
for (char& i: lowerCase) {
if (i>='A' && i<='Z') i+='a'-'A';
}
auto lastItem=std::remove_if(lowerCase.begin(),lowerCase.end(),[](char c) {
return (c==' ' || c=='_' || c=='-');
});
lowerCase.erase(lastItem,lowerCase.end());
newSongSearchResults.clear();
for (FurnaceGUISysCategory& i: sysCategories) {
for (FurnaceGUISysDef& j: i.systems) {
String lowerCase1=j.name;
for (char& i: lowerCase1) {
if (i>='A' && i<='Z') i+='a'-'A';
}
auto lastItem=std::remove_if(lowerCase1.begin(),lowerCase1.end(),[](char c) {
return (c==' ' || c=='_' || c=='-');
});
lowerCase1.erase(lastItem,lowerCase1.end());
if (lowerCase1.find(lowerCase)!=String::npos) {
newSongSearchResults.push_back(j);
}
}
std::sort(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) {
return strcmp(a.name.c_str(),b.name.c_str())<0;
});
auto lastItem=std::unique(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) {
return a.name==b.name;
});
newSongSearchResults.erase(lastItem,newSongSearchResults.end());
}
}
if (ImGui::BeginTable("sysPicker",newSongQuery.empty()?2:1,ImGuiTableFlags_BordersInnerV)) {
if (newSongQuery.empty()) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0f);
}
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0f);
if (newSongQuery.empty()) {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::Text("Categories");
ImGui::TableNextColumn();
ImGui::Text("Systems");
}
ImGui::TableNextRow();
// CATEGORIES
if (newSongQuery.empty()) {
ImGui::TableNextColumn();
int index=0;
for (FurnaceGUISysCategory& i: sysCategories) {
2024-03-18 20:45:04 -04:00
if (ImGui::Selectable(i.name,newSongCategory==index,ImGuiSelectableFlags_DontClosePopups)) {
newSongCategory=index;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("%s",i.description);
}
2024-03-20 19:20:12 -04:00
if (strcmp(i.name,"User")==0) ImGui::Separator();
index++;
}
}
// SYSTEMS
ImGui::TableNextColumn();
if (ImGui::BeginTable("Systems",1,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollY)) {
std::vector<FurnaceGUISysDef>& category=(newSongQuery.empty())?(sysCategories[newSongCategory].systems):(newSongSearchResults);
2024-03-20 19:20:12 -04:00
if (category.empty()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (newSongQuery.empty()) {
ImGui::Text("no systems here yet!");
} else {
ImGui::Text("no results");
}
} else {
sysDefStack.push_back(newSongQuery.empty()?newSongCategory:-1);
drawSysDefs(category,accepted,sysDefStack);
sysDefStack.erase(sysDefStack.end()-1);
}
ImGui::EndTable();
}
ImGui::EndTable();
}
}
ImGui::EndChild();
2022-04-29 05:42:18 -04:00
if (ImGui::Button("I'm feeling lucky")) {
if (sysCategories.size()==0) {
2024-03-22 03:20:16 -04:00
showError("no categories available! what in the world.");
2022-04-29 05:42:18 -04:00
ImGui::CloseCurrentPopup();
} else {
2024-03-22 03:20:16 -04:00
int tries=0;
for (tries=0; tries<50; tries++) {
FurnaceGUISysCategory* newSystemCat=&sysCategories[rand()%sysCategories.size()];
if (newSystemCat->systems.empty()) {
continue;
} else {
unsigned int selection=rand()%newSystemCat->systems.size();
if (newSystemCat->systems[selection].orig.empty() && newSystemCat->systems[selection].subDefs.empty()) continue;
if (!newSystemCat->systems[selection].subDefs.empty()) {
if (rand()%2) {
unsigned int subSel=rand()%newSystemCat->systems[selection].subDefs.size();
nextDesc=newSystemCat->systems[selection].subDefs[subSel].definition;
nextDescName=newSystemCat->systems[selection].subDefs[subSel].name;
accepted=true;
} else {
if (newSystemCat->systems[selection].orig.empty()) continue;
nextDesc=newSystemCat->systems[selection].definition;
nextDescName=newSystemCat->systems[selection].name;
accepted=true;
}
} else {
nextDesc=newSystemCat->systems[selection].definition;
nextDescName=newSystemCat->systems[selection].name;
accepted=true;
}
}
if (accepted) break;
}
if (tries>=50) {
showError("it appears you're extremely lucky today!");
2022-04-29 05:42:18 -04:00
ImGui::CloseCurrentPopup();
}
}
}
2022-04-29 04:54:10 -04:00
ImGui::SameLine();
2023-07-03 21:32:54 -04:00
if (ImGui::Button("Cancel") || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
2022-04-29 05:42:18 -04:00
ImGui::CloseCurrentPopup();
2022-04-29 04:54:10 -04:00
}
if (accepted) {
2022-11-13 16:57:47 -05:00
e->createNew(nextDesc.c_str(),nextDescName,false);
undoHist.clear();
redoHist.clear();
curFileName="";
modified=false;
curNibble=false;
orderNibble=false;
orderCursor=-1;
samplePos=0;
updateSampleTex=true;
selStart=SelectionPoint();
selEnd=SelectionPoint();
cursor=SelectionPoint();
updateWindowTitle();
ImGui::CloseCurrentPopup();
}
2023-04-03 10:11:26 -04:00
newSongFirstFrame=false;
2022-04-29 05:42:18 -04:00
}