Merge branch 'master' of https://github.com/tildearrow/furnace into sample_macro
# Conflicts: # src/engine/fileOps.cpp # src/engine/platform/lynx.cpp # src/engine/platform/rf5c68.cpp # src/engine/platform/su.cpp # src/engine/platform/x1_010.h # src/engine/platform/ym2610.cpp # src/engine/platform/ym2610.h # src/engine/platform/ym2610b.cpp # src/engine/platform/ym2610b.h # src/engine/sysDef.cpp # src/gui/insEdit.cpp Add effect command for ADPCM-A global volume, X1-010 Sample bank slot
This commit is contained in:
commit
54dbd0690c
148 changed files with 4114 additions and 3610 deletions
|
|
@ -49,6 +49,7 @@ const char* aboutLine[]={
|
|||
"tildearrow",
|
||||
"BlastBrothers",
|
||||
"Mahbod Karamoozian",
|
||||
"nicco1690",
|
||||
"Raijin",
|
||||
"",
|
||||
"-- documentation --",
|
||||
|
|
@ -67,6 +68,7 @@ const char* aboutLine[]={
|
|||
"AURORA*FIELDS",
|
||||
"BlueElectric05",
|
||||
"breakthetargets",
|
||||
"brickblock369",
|
||||
"CaptainMalware",
|
||||
"DeMOSic",
|
||||
"DevEd",
|
||||
|
|
@ -86,6 +88,7 @@ const char* aboutLine[]={
|
|||
"nicco1690",
|
||||
"NikonTeen",
|
||||
"psdominator",
|
||||
"Raijin",
|
||||
"SuperJet Spade",
|
||||
"TheDuccinator",
|
||||
"theloredev",
|
||||
|
|
|
|||
|
|
@ -139,6 +139,10 @@ void FurnaceGUI::drawCompatFlags() {
|
|||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("if enabled, no checks for the presence of a volume macro will be made.\nthis will cause the last macro value to linger unless a value in the volume column is present.");
|
||||
}
|
||||
ImGui::Checkbox("Treat SN76489 periods under 8 as 1",&e->song.snNoLowPeriods);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("when enabled, any SN period under 8 will be written as 1 instead.\nthis replicates DefleMask behavior, but reduces available period range.");
|
||||
}
|
||||
|
||||
ImGui::Text("Pitch linearity:");
|
||||
if (ImGui::RadioButton("None",e->song.linearPitch==0)) {
|
||||
|
|
@ -189,6 +193,26 @@ void FurnaceGUI::drawCompatFlags() {
|
|||
ImGui::SetTooltip("select to not reset channels on loop.");
|
||||
}
|
||||
|
||||
ImGui::Text("Cut/delay effect policy:");
|
||||
if (ImGui::RadioButton("Strict",e->song.delayBehavior==0)) {
|
||||
e->song.delayBehavior=0;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("only when time is less than speed (like DefleMask/ProTracker)");
|
||||
}
|
||||
if (ImGui::RadioButton("Strict (old)",e->song.delayBehavior==1)) {
|
||||
e->song.delayBehavior=1;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("only when time is less than or equal to speed (original buggy behavior)");
|
||||
}
|
||||
if (ImGui::RadioButton("Lax",e->song.delayBehavior==2)) {
|
||||
e->song.delayBehavior=2;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("no checks (like FamiTracker)");
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::TextWrapped("the following flags are for compatibility with older Furnace versions.");
|
||||
|
|
|
|||
|
|
@ -452,6 +452,12 @@ void FurnaceGUI::drawWaveList() {
|
|||
if (ImGui::Button(ICON_FA_FOLDER_OPEN "##WaveLoad")) {
|
||||
doAction(GUI_ACTION_WAVE_LIST_OPEN);
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("WaveOpenOpt")) {
|
||||
if (ImGui::MenuItem("replace...")) {
|
||||
doAction((curWave>=0 && curWave<(int)e->song.wave.size())?GUI_ACTION_WAVE_LIST_OPEN_REPLACE:GUI_ACTION_WAVE_LIST_OPEN);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_FLOPPY_O "##WaveSave")) {
|
||||
doAction(GUI_ACTION_WAVE_LIST_SAVE);
|
||||
|
|
@ -502,6 +508,19 @@ void FurnaceGUI::drawSampleList() {
|
|||
if (ImGui::Button(ICON_FA_FOLDER_OPEN "##SampleLoad")) {
|
||||
doAction(GUI_ACTION_SAMPLE_LIST_OPEN);
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("SampleOpenOpt")) {
|
||||
if (ImGui::MenuItem("replace...")) {
|
||||
doAction((curSample>=0 && curSample<(int)e->song.sample.size())?GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE:GUI_ACTION_SAMPLE_LIST_OPEN);
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("import raw...")) {
|
||||
doAction(GUI_ACTION_SAMPLE_LIST_OPEN_RAW);
|
||||
}
|
||||
if (ImGui::MenuItem("import raw (replace)...")) {
|
||||
doAction((curSample>=0 && curSample<(int)e->song.sample.size())?GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE_RAW:GUI_ACTION_SAMPLE_LIST_OPEN_RAW);
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_FLOPPY_O "##SampleSave")) {
|
||||
doAction(GUI_ACTION_SAMPLE_LIST_SAVE);
|
||||
|
|
|
|||
|
|
@ -238,6 +238,12 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_WINDOW_CHANNELS:
|
||||
nextWindow=GUI_WINDOW_CHANNELS;
|
||||
break;
|
||||
case GUI_ACTION_WINDOW_PAT_MANAGER:
|
||||
nextWindow=GUI_WINDOW_PAT_MANAGER;
|
||||
break;
|
||||
case GUI_ACTION_WINDOW_SYS_MANAGER:
|
||||
nextWindow=GUI_WINDOW_SYS_MANAGER;
|
||||
break;
|
||||
case GUI_ACTION_WINDOW_REGISTER_VIEW:
|
||||
nextWindow=GUI_WINDOW_REGISTER_VIEW;
|
||||
break;
|
||||
|
|
@ -322,6 +328,12 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_WINDOW_CHANNELS:
|
||||
channelsOpen=false;
|
||||
break;
|
||||
case GUI_WINDOW_PAT_MANAGER:
|
||||
patManagerOpen=false;
|
||||
break;
|
||||
case GUI_WINDOW_SYS_MANAGER:
|
||||
sysManagerOpen=false;
|
||||
break;
|
||||
case GUI_WINDOW_REGISTER_VIEW:
|
||||
regViewOpen=false;
|
||||
break;
|
||||
|
|
@ -648,6 +660,9 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_WAVE_LIST_OPEN:
|
||||
openFileDialog(GUI_FILE_WAVE_OPEN);
|
||||
break;
|
||||
case GUI_ACTION_WAVE_LIST_OPEN_REPLACE:
|
||||
openFileDialog(GUI_FILE_WAVE_OPEN_REPLACE);
|
||||
break;
|
||||
case GUI_ACTION_WAVE_LIST_SAVE:
|
||||
if (curWave>=0 && curWave<(int)e->song.wave.size()) openFileDialog(GUI_FILE_WAVE_SAVE);
|
||||
break;
|
||||
|
|
@ -730,6 +745,15 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_SAMPLE_LIST_OPEN:
|
||||
openFileDialog(GUI_FILE_SAMPLE_OPEN);
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE:
|
||||
openFileDialog(GUI_FILE_SAMPLE_OPEN_REPLACE);
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_OPEN_RAW:
|
||||
openFileDialog(GUI_FILE_SAMPLE_OPEN_RAW);
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE_RAW:
|
||||
openFileDialog(GUI_FILE_SAMPLE_OPEN_REPLACE_RAW);
|
||||
break;
|
||||
case GUI_ACTION_SAMPLE_LIST_SAVE:
|
||||
if (curSample>=0 && curSample<(int)e->song.sample.size()) openFileDialog(GUI_FILE_SAMPLE_SAVE);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include "actionUtil.h"
|
||||
|
||||
const char* noteNameNormal(short note, short octave) {
|
||||
const char* FurnaceGUI::noteNameNormal(short note, short octave) {
|
||||
if (note==100) { // note cut
|
||||
return "OFF";
|
||||
} else if (note==101) { // note off and envelope release
|
||||
|
|
@ -577,7 +577,7 @@ void FurnaceGUI::doChangeIns(int ins) {
|
|||
if (!e->curSubSong->chanShow[iCoarse]) continue;
|
||||
DivPattern* pat=e->curPat[iCoarse].getPattern(e->curOrders->ord[iCoarse][curOrder],true);
|
||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
||||
if (pat->data[j][2]!=-1 || !(pat->data[j][0]==0 && pat->data[j][1]==0)) {
|
||||
if (pat->data[j][2]!=-1 || !((pat->data[j][0]==0 || pat->data[j][0]==100 || pat->data[j][0]==101 || pat->data[j][0]==102) && pat->data[j][1]==0)) {
|
||||
pat->data[j][2]=ins;
|
||||
}
|
||||
}
|
||||
|
|
@ -616,9 +616,9 @@ void FurnaceGUI::doInterpolate() {
|
|||
}
|
||||
} else {
|
||||
for (int j=selStart.y; j<=selEnd.y; j++) {
|
||||
if (pat->data[j][0]!=0 && pat->data[j][1]!=0) {
|
||||
if (pat->data[j][0]!=0 || pat->data[j][1]!=0) {
|
||||
if (pat->data[j][0]!=100 && pat->data[j][0]!=101 && pat->data[j][0]!=102) {
|
||||
points.emplace(points.end(),j,pat->data[j][0]+pat->data[j][1]*12);
|
||||
points.emplace(points.end(),j,pat->data[j][0]+(signed char)pat->data[j][1]*12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ void FurnaceGUI::drawEffectList() {
|
|||
}
|
||||
if (!effectListOpen) return;
|
||||
if (ImGui::Begin("Effect List",&effectListOpen,globalWinFlags)) {
|
||||
ImGui::Text("System at cursor: %s",e->getSystemName(e->sysOfChan[cursor.xCoarse]));
|
||||
ImGui::Text("Chip at cursor: %s",e->getSystemName(e->sysOfChan[cursor.xCoarse]));
|
||||
if (ImGui::BeginTable("effectList",2)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch);
|
||||
|
|
|
|||
|
|
@ -593,11 +593,11 @@ void FurnaceGUI::drawFindReplace() {
|
|||
i.note=0;
|
||||
}
|
||||
if (i.note==130) {
|
||||
snprintf(tempID,1024,"REL");
|
||||
snprintf(tempID,1024,"%s##MREL",macroRelLabel);
|
||||
} else if (i.note==129) {
|
||||
snprintf(tempID,1024,"===");
|
||||
snprintf(tempID,1024,"%s##NREL",noteRelLabel);
|
||||
} else if (i.note==128) {
|
||||
snprintf(tempID,1024,"OFF");
|
||||
snprintf(tempID,1024,"%s##NOFF",noteOffLabel);
|
||||
} else if (i.note>=-60 && i.note<120) {
|
||||
snprintf(tempID,1024,"%s",noteNames[i.note+60]);
|
||||
} else {
|
||||
|
|
@ -613,13 +613,13 @@ void FurnaceGUI::drawFindReplace() {
|
|||
}
|
||||
}
|
||||
if (i.noteMode!=GUI_QUERY_RANGE && i.noteMode!=GUI_QUERY_RANGE_NOT) {
|
||||
if (ImGui::Selectable("OFF",i.note==128)) {
|
||||
if (ImGui::Selectable(noteOffLabel,i.note==128)) {
|
||||
i.note=128;
|
||||
}
|
||||
if (ImGui::Selectable("===",i.note==129)) {
|
||||
if (ImGui::Selectable(noteRelLabel,i.note==129)) {
|
||||
i.note=129;
|
||||
}
|
||||
if (ImGui::Selectable("REL",i.note==130)) {
|
||||
if (ImGui::Selectable(macroRelLabel,i.note==130)) {
|
||||
i.note=130;
|
||||
}
|
||||
}
|
||||
|
|
@ -916,11 +916,11 @@ void FurnaceGUI::drawFindReplace() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (queryReplaceNoteMode==GUI_QUERY_REPLACE_SET) {
|
||||
if (queryReplaceNote==130) {
|
||||
snprintf(tempID,1024,"REL");
|
||||
snprintf(tempID,1024,"%s##MREL",macroRelLabel);
|
||||
} else if (queryReplaceNote==129) {
|
||||
snprintf(tempID,1024,"===");
|
||||
snprintf(tempID,1024,"%s##NREL",noteRelLabel);
|
||||
} else if (queryReplaceNote==128) {
|
||||
snprintf(tempID,1024,"OFF");
|
||||
snprintf(tempID,1024,"%s##NOFF",noteOffLabel);
|
||||
} else if (queryReplaceNote>=-60 && queryReplaceNote<120) {
|
||||
snprintf(tempID,1024,"%s",noteNames[queryReplaceNote+60]);
|
||||
} else {
|
||||
|
|
@ -934,13 +934,13 @@ void FurnaceGUI::drawFindReplace() {
|
|||
queryReplaceNote=j-60;
|
||||
}
|
||||
}
|
||||
if (ImGui::Selectable("OFF",queryReplaceNote==128)) {
|
||||
if (ImGui::Selectable(noteOffLabel,queryReplaceNote==128)) {
|
||||
queryReplaceNote=128;
|
||||
}
|
||||
if (ImGui::Selectable("===",queryReplaceNote==129)) {
|
||||
if (ImGui::Selectable(noteRelLabel,queryReplaceNote==129)) {
|
||||
queryReplaceNote=129;
|
||||
}
|
||||
if (ImGui::Selectable("REL",queryReplaceNote==130)) {
|
||||
if (ImGui::Selectable(macroRelLabel,queryReplaceNote==130)) {
|
||||
queryReplaceNote=130;
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
|
|
|
|||
370
src/gui/gui.cpp
370
src/gui/gui.cpp
|
|
@ -84,13 +84,13 @@ void FurnaceGUI::bindEngine(DivEngine* eng) {
|
|||
|
||||
const char* FurnaceGUI::noteName(short note, short octave) {
|
||||
if (note==100) {
|
||||
return "OFF";
|
||||
return noteOffLabel;
|
||||
} else if (note==101) { // note off and envelope release
|
||||
return "===";
|
||||
return noteRelLabel;
|
||||
} else if (note==102) { // envelope release only
|
||||
return "REL";
|
||||
return macroRelLabel;
|
||||
} else if (octave==0 && note==0) {
|
||||
return "...";
|
||||
return emptyLabel;
|
||||
} else if (note==0 && octave!=0) {
|
||||
return "BUG";
|
||||
}
|
||||
|
|
@ -195,23 +195,30 @@ void FurnaceGUI::decodeKeyMap(std::map<int,int>& map, String source) {
|
|||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex) {
|
||||
void FurnaceGUI::encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex, bool bit30) {
|
||||
target="";
|
||||
char buf[32];
|
||||
for (int i=0; i<macroLen; i++) {
|
||||
if (i==macroLoop) target+="| ";
|
||||
if (i==macroRel) target+="/ ";
|
||||
if (bit30 && ((macro[i]&0xc0000000)==0x40000000 || (macro[i]&0xc0000000)==0x80000000)) target+="@";
|
||||
int macroVal=macro[i];
|
||||
if (macro[i]<0) {
|
||||
if (!(macroVal&0x40000000)) macroVal|=0x40000000;
|
||||
} else {
|
||||
if (macroVal&0x40000000) macroVal&=~0x40000000;
|
||||
}
|
||||
if (hex) {
|
||||
if (i==macroLen-1) {
|
||||
snprintf(buf,31,"%.2X",macro[i]);
|
||||
snprintf(buf,31,"%.2X",macroVal);
|
||||
} else {
|
||||
snprintf(buf,31,"%.2X ",macro[i]);
|
||||
snprintf(buf,31,"%.2X ",macroVal);
|
||||
}
|
||||
} else {
|
||||
if (i==macroLen-1) {
|
||||
snprintf(buf,31,"%d",macro[i]);
|
||||
snprintf(buf,31,"%d",macroVal);
|
||||
} else {
|
||||
snprintf(buf,31,"%d ",macro[i]);
|
||||
snprintf(buf,31,"%d ",macroVal);
|
||||
}
|
||||
}
|
||||
target+=buf;
|
||||
|
|
@ -276,13 +283,14 @@ void FurnaceGUI::decodeMMLStrW(String& source, int* macro, int& macroLen, int ma
|
|||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLen, signed char& macroLoop, int macroMin, int macroMax, signed char& macroRel) {
|
||||
void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel, bool bit30) {
|
||||
int buf=0;
|
||||
bool negaBuf=false;
|
||||
bool setBit30=false;
|
||||
bool hasVal=false;
|
||||
macroLen=0;
|
||||
macroLoop=-1;
|
||||
macroRel=-1;
|
||||
macroLoop=255;
|
||||
macroRel=255;
|
||||
for (char& i: source) {
|
||||
switch (i) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
|
|
@ -297,6 +305,11 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe
|
|||
negaBuf=true;
|
||||
}
|
||||
break;
|
||||
case '@':
|
||||
if (bit30) {
|
||||
setBit30=true;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
if (hasVal) {
|
||||
hasVal=false;
|
||||
|
|
@ -304,6 +317,8 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe
|
|||
negaBuf=false;
|
||||
if (macro[macroLen]<macroMin) macro[macroLen]=macroMin;
|
||||
if (macro[macroLen]>macroMax) macro[macroLen]=macroMax;
|
||||
if (setBit30) macro[macroLen]^=0x40000000;
|
||||
setBit30=false;
|
||||
macroLen++;
|
||||
buf=0;
|
||||
}
|
||||
|
|
@ -315,10 +330,12 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe
|
|||
negaBuf=false;
|
||||
if (macro[macroLen]<macroMin) macro[macroLen]=macroMin;
|
||||
if (macro[macroLen]>macroMax) macro[macroLen]=macroMax;
|
||||
if (setBit30) macro[macroLen]^=0x40000000;
|
||||
setBit30=false;
|
||||
macroLen++;
|
||||
buf=0;
|
||||
}
|
||||
if (macroLoop==-1) {
|
||||
if (macroLoop==255) {
|
||||
macroLoop=macroLen;
|
||||
}
|
||||
break;
|
||||
|
|
@ -329,22 +346,26 @@ void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLe
|
|||
negaBuf=false;
|
||||
if (macro[macroLen]<macroMin) macro[macroLen]=macroMin;
|
||||
if (macro[macroLen]>macroMax) macro[macroLen]=macroMax;
|
||||
if (setBit30) macro[macroLen]^=0x40000000;
|
||||
setBit30=false;
|
||||
macroLen++;
|
||||
buf=0;
|
||||
}
|
||||
if (macroRel==-1) {
|
||||
if (macroRel==255) {
|
||||
macroRel=macroLen;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (macroLen>=128) break;
|
||||
if (macroLen>=255) break;
|
||||
}
|
||||
if (hasVal && macroLen<128) {
|
||||
if (hasVal && macroLen<255) {
|
||||
hasVal=false;
|
||||
macro[macroLen]=negaBuf?-buf:buf;
|
||||
negaBuf=false;
|
||||
if (macro[macroLen]<macroMin) macro[macroLen]=macroMin;
|
||||
if (macro[macroLen]>macroMax) macro[macroLen]=macroMax;
|
||||
if (setBit30) macro[macroLen]^=0x40000000;
|
||||
setBit30=false;
|
||||
macroLen++;
|
||||
buf=0;
|
||||
}
|
||||
|
|
@ -1267,6 +1288,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
hasOpened=fileDialog->openLoad(
|
||||
"Load Instrument",
|
||||
// TODO supply loadable formats in a dynamic, scalable, "DRY" way.
|
||||
// thank the author of IGFD for making things impossible
|
||||
{"all compatible files", "*.fui *.dmp *.tfi *.vgi *.s3i *.sbi *.opli *.opni *.y12 *.bnk *.ff *.gyb *.opm *.wopl *.wopn",
|
||||
"Furnace instrument", "*.fui",
|
||||
"DefleMask preset", "*.dmp",
|
||||
|
|
@ -1313,13 +1335,15 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
if (!dirExists(workingDirIns)) workingDirIns=getHomeDir();
|
||||
hasOpened=fileDialog->openSave(
|
||||
"Save Instrument",
|
||||
{"Furnace instrument", "*.fui"},
|
||||
"Furnace instrument{.fui}",
|
||||
{"Furnace instrument", "*.fui",
|
||||
"DefleMask preset", "*.dmp"},
|
||||
"Furnace instrument{.fui},DefleMask preset{.dmp}",
|
||||
workingDirIns,
|
||||
dpiScale
|
||||
);
|
||||
break;
|
||||
case GUI_FILE_WAVE_OPEN:
|
||||
case GUI_FILE_WAVE_OPEN_REPLACE:
|
||||
if (!dirExists(workingDirWave)) workingDirWave=getHomeDir();
|
||||
hasOpened=fileDialog->openLoad(
|
||||
"Load Wavetable",
|
||||
|
|
@ -1334,13 +1358,16 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
if (!dirExists(workingDirWave)) workingDirWave=getHomeDir();
|
||||
hasOpened=fileDialog->openSave(
|
||||
"Save Wavetable",
|
||||
{"Furnace wavetable", ".fuw"},
|
||||
"Furnace wavetable{.fuw}",
|
||||
{"Furnace wavetable", ".fuw",
|
||||
"DefleMask wavetable", ".dmw",
|
||||
"raw data", ".raw"},
|
||||
"Furnace wavetable{.fuw},DefleMask wavetable{.dmw},raw data{.raw}",
|
||||
workingDirWave,
|
||||
dpiScale
|
||||
);
|
||||
break;
|
||||
case GUI_FILE_SAMPLE_OPEN:
|
||||
case GUI_FILE_SAMPLE_OPEN_REPLACE:
|
||||
if (!dirExists(workingDirSample)) workingDirSample=getHomeDir();
|
||||
hasOpened=fileDialog->openLoad(
|
||||
"Load Sample",
|
||||
|
|
@ -1351,6 +1378,17 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
dpiScale
|
||||
);
|
||||
break;
|
||||
case GUI_FILE_SAMPLE_OPEN_RAW:
|
||||
case GUI_FILE_SAMPLE_OPEN_REPLACE_RAW:
|
||||
if (!dirExists(workingDirSample)) workingDirSample=getHomeDir();
|
||||
hasOpened=fileDialog->openLoad(
|
||||
"Load Raw Sample",
|
||||
{"all files", ".*"},
|
||||
".*",
|
||||
workingDirSample,
|
||||
dpiScale
|
||||
);
|
||||
break;
|
||||
case GUI_FILE_SAMPLE_SAVE:
|
||||
if (!dirExists(workingDirSample)) workingDirSample=getHomeDir();
|
||||
hasOpened=fileDialog->openSave(
|
||||
|
|
@ -1741,8 +1779,35 @@ void FurnaceGUI::showError(String what) {
|
|||
displayError=true;
|
||||
}
|
||||
|
||||
// what monster did I just create here?
|
||||
#define B30(tt) (macroDragBit30?((((tt)&0xc0000000)==0x40000000 || ((tt)&0xc0000000)==0x80000000)?0x40000000:0):0)
|
||||
|
||||
#define MACRO_DRAG(t) \
|
||||
if (macroDragBitMode) { \
|
||||
if (macroDragSettingBit30) { \
|
||||
if (macroDragLastX!=x || macroDragLastY!=y) { \
|
||||
macroDragLastX=x; \
|
||||
macroDragLastY=y; \
|
||||
if (macroDragInitialValueSet) { \
|
||||
if (!macroDragInitialValue) { \
|
||||
if (t[x]&0x80000000) { \
|
||||
t[x]&=~0x40000000; \
|
||||
} else { \
|
||||
t[x]|=0x40000000; \
|
||||
} \
|
||||
} else { \
|
||||
if (t[x]&0x80000000) { \
|
||||
t[x]|=0x40000000; \
|
||||
} else { \
|
||||
t[x]&=~0x40000000; \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
macroDragInitialValue=(((t[x])&0xc0000000)==0x40000000 || ((t[x])&0xc0000000)==0x80000000); \
|
||||
macroDragInitialValueSet=true; \
|
||||
t[x]^=0x40000000; \
|
||||
} \
|
||||
} \
|
||||
} else if (macroDragBitMode) { \
|
||||
if (macroDragLastX!=x || macroDragLastY!=y) { \
|
||||
macroDragLastX=x; \
|
||||
macroDragLastY=y; \
|
||||
|
|
@ -1773,25 +1838,25 @@ void FurnaceGUI::showError(String what) {
|
|||
} \
|
||||
if (macroDragMouseMoved) { \
|
||||
if ((int)round(x-macroDragLineInitial.x)==0) { \
|
||||
t[x]=macroDragLineInitial.y; \
|
||||
t[x]=B30(t[x])^(int)(macroDragLineInitial.y); \
|
||||
} else { \
|
||||
if ((int)round(x-macroDragLineInitial.x)<0) { \
|
||||
for (int i=0; i<=(int)round(macroDragLineInitial.x-x); i++) { \
|
||||
int index=(int)round(x+i); \
|
||||
if (index<0) continue; \
|
||||
t[index]=y+(macroDragLineInitial.y-y)*((float)i/(float)(macroDragLineInitial.x-x)); \
|
||||
t[index]=B30(t[index])^(int)(y+(macroDragLineInitial.y-y)*((float)i/(float)(macroDragLineInitial.x-x))); \
|
||||
} \
|
||||
} else { \
|
||||
for (int i=0; i<=(int)round(x-macroDragLineInitial.x); i++) { \
|
||||
int index=(int)round(i+macroDragLineInitial.x); \
|
||||
if (index<0) continue; \
|
||||
t[index]=macroDragLineInitial.y+(y-macroDragLineInitial.y)*((float)i/(x-macroDragLineInitial.x)); \
|
||||
t[index]=B30(t[index])^(int)(macroDragLineInitial.y+(y-macroDragLineInitial.y)*((float)i/(x-macroDragLineInitial.x))); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
t[x]=y; \
|
||||
t[x]=B30(t[x])^(y); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
|
@ -1876,20 +1941,6 @@ void FurnaceGUI::processDrags(int dragX, int dragY) {
|
|||
}
|
||||
}
|
||||
|
||||
#define sysAddOption(x) \
|
||||
if (ImGui::MenuItem(getSystemName(x))) { \
|
||||
if (!e->addSystem(x)) { \
|
||||
showError("cannot add chip! ("+e->getLastError()+")"); \
|
||||
} \
|
||||
updateWindowTitle(); \
|
||||
}
|
||||
|
||||
#define sysChangeOption(x,y) \
|
||||
if (ImGui::MenuItem(getSystemName(y),NULL,e->song.system[x]==y)) { \
|
||||
e->changeSystem(x,y,preserveChanPos); \
|
||||
updateWindowTitle(); \
|
||||
}
|
||||
|
||||
#define checkExtension(x) \
|
||||
String lowerCase=fileName; \
|
||||
for (char& i: lowerCase) { \
|
||||
|
|
@ -1908,6 +1959,15 @@ void FurnaceGUI::processDrags(int dragX, int dragY) {
|
|||
fileName+=fallback; \
|
||||
}
|
||||
|
||||
#define checkExtensionTriple(x,y,z,fallback) \
|
||||
String lowerCase=fileName; \
|
||||
for (char& i: lowerCase) { \
|
||||
if (i>='A' && i<='Z') i+='a'-'A'; \
|
||||
} \
|
||||
if (lowerCase.size()<4 || (lowerCase.rfind(x)!=lowerCase.size()-4 && lowerCase.rfind(y)!=lowerCase.size()-4 && lowerCase.rfind(z)!=lowerCase.size()-4)) { \
|
||||
fileName+=fallback; \
|
||||
}
|
||||
|
||||
#define drawOpMask(m) \
|
||||
ImGui::PushFont(patFont); \
|
||||
ImGui::PushID("om_" #m); \
|
||||
|
|
@ -2630,6 +2690,8 @@ bool FurnaceGUI::loop() {
|
|||
case SDL_DROPFILE:
|
||||
if (ev.drop.file!=NULL) {
|
||||
std::vector<DivInstrument*> instruments=e->instrumentFromFile(ev.drop.file);
|
||||
DivWavetable* droppedWave=NULL;
|
||||
DivSample* droppedSample=NULL;;
|
||||
if (!instruments.empty()) {
|
||||
if (!e->getWarnings().empty()) {
|
||||
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
||||
|
|
@ -2639,10 +2701,12 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
nextWindow=GUI_WINDOW_INS_LIST;
|
||||
MARK_MODIFIED;
|
||||
} else if (e->addWaveFromFile(ev.drop.file,false)) {
|
||||
} else if ((droppedWave=e->waveFromFile(ev.drop.file,false))!=NULL) {
|
||||
e->addWavePtr(droppedWave);
|
||||
nextWindow=GUI_WINDOW_WAVE_LIST;
|
||||
MARK_MODIFIED;
|
||||
} else if (e->addSampleFromFile(ev.drop.file)!=-1) {
|
||||
} else if ((droppedSample=e->sampleFromFile(ev.drop.file))!=NULL) {
|
||||
e->addSamplePtr(droppedSample);
|
||||
nextWindow=GUI_WINDOW_SAMPLE_LIST;
|
||||
MARK_MODIFIED;
|
||||
} else if (modified) {
|
||||
|
|
@ -2973,9 +3037,13 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginMenu("add chip...")) {
|
||||
for (int j=0; availableSystems[j]; j++) {
|
||||
if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY)) continue;
|
||||
sysAddOption((DivSystem)availableSystems[j]);
|
||||
DivSystem picked=systemPicker();
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
if (!e->addSystem(picked)) {
|
||||
showError("cannot add chip! ("+e->getLastError()+")");
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
updateWindowTitle();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
|
@ -2992,9 +3060,11 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::Checkbox("Preserve channel positions",&preserveChanPos);
|
||||
for (int i=0; i<e->song.systemLen; i++) {
|
||||
if (ImGui::BeginMenu(fmt::sprintf("%d. %s##_SYSC%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
|
||||
for (int j=0; availableSystems[j]; j++) {
|
||||
if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY)) continue;
|
||||
sysChangeOption(i,(DivSystem)availableSystems[j]);
|
||||
DivSystem picked=systemPicker();
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
e->changeSystem(i,picked,preserveChanPos);
|
||||
updateWindowTitle();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
|
@ -3077,6 +3147,8 @@ bool FurnaceGUI::loop() {
|
|||
if (ImGui::MenuItem("pattern",BIND_FOR(GUI_ACTION_WINDOW_PATTERN),patternOpen)) patternOpen=!patternOpen;
|
||||
if (ImGui::MenuItem("mixer",BIND_FOR(GUI_ACTION_WINDOW_MIXER),mixerOpen)) mixerOpen=!mixerOpen;
|
||||
if (ImGui::MenuItem("channels",BIND_FOR(GUI_ACTION_WINDOW_CHANNELS),channelsOpen)) channelsOpen=!channelsOpen;
|
||||
if (ImGui::MenuItem("pattern manager",BIND_FOR(GUI_ACTION_WINDOW_PAT_MANAGER),patManagerOpen)) patManagerOpen=!patManagerOpen;
|
||||
if (ImGui::MenuItem("chip manager",BIND_FOR(GUI_ACTION_WINDOW_SYS_MANAGER),sysManagerOpen)) sysManagerOpen=!sysManagerOpen;
|
||||
if (ImGui::MenuItem("compatibility flags",BIND_FOR(GUI_ACTION_WINDOW_COMPAT_FLAGS),compatFlagsOpen)) compatFlagsOpen=!compatFlagsOpen;
|
||||
if (ImGui::MenuItem("song comments",BIND_FOR(GUI_ACTION_WINDOW_NOTES),notesOpen)) notesOpen=!notesOpen;
|
||||
ImGui::Separator();
|
||||
|
|
@ -3211,6 +3283,8 @@ bool FurnaceGUI::loop() {
|
|||
drawPiano();
|
||||
drawNotes();
|
||||
drawChannels();
|
||||
drawPatManager();
|
||||
drawSysManager();
|
||||
drawRegView();
|
||||
drawLog();
|
||||
drawEffectList();
|
||||
|
|
@ -3269,10 +3343,14 @@ bool FurnaceGUI::loop() {
|
|||
workingDirIns=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||
break;
|
||||
case GUI_FILE_WAVE_OPEN:
|
||||
case GUI_FILE_WAVE_OPEN_REPLACE:
|
||||
case GUI_FILE_WAVE_SAVE:
|
||||
workingDirWave=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||
break;
|
||||
case GUI_FILE_SAMPLE_OPEN:
|
||||
case GUI_FILE_SAMPLE_OPEN_RAW:
|
||||
case GUI_FILE_SAMPLE_OPEN_REPLACE:
|
||||
case GUI_FILE_SAMPLE_OPEN_REPLACE_RAW:
|
||||
case GUI_FILE_SAMPLE_SAVE:
|
||||
workingDirSample=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||
break;
|
||||
|
|
@ -3344,10 +3422,21 @@ bool FurnaceGUI::loop() {
|
|||
checkExtension(".wav");
|
||||
}
|
||||
if (curFileDialog==GUI_FILE_INS_SAVE) {
|
||||
checkExtension(".fui");
|
||||
// we can't tell whether the user chose .fui or .dmp in the system file picker
|
||||
const char* fallbackExt=(settings.sysFileDialog || ImGuiFileDialog::Instance()->GetCurrentFilter()=="Furnace instrument")?".fui":".dmp";
|
||||
checkExtensionDual(".fui",".dmp",fallbackExt);
|
||||
}
|
||||
if (curFileDialog==GUI_FILE_WAVE_SAVE) {
|
||||
checkExtension(".fuw");
|
||||
// same thing here
|
||||
const char* fallbackExt=".fuw";
|
||||
if (!settings.sysFileDialog) {
|
||||
if (ImGuiFileDialog::Instance()->GetCurrentFilter()=="raw data") {
|
||||
fallbackExt=".raw";
|
||||
} else if (ImGuiFileDialog::Instance()->GetCurrentFilter()=="DefleMask wavetable") {
|
||||
fallbackExt=".dmw";
|
||||
}
|
||||
}
|
||||
checkExtensionTriple(".fuw",".dmw",".raw",fallbackExt);
|
||||
}
|
||||
if (curFileDialog==GUI_FILE_EXPORT_VGM) {
|
||||
checkExtension(".vgm");
|
||||
|
|
@ -3430,21 +3519,75 @@ bool FurnaceGUI::loop() {
|
|||
break;
|
||||
case GUI_FILE_INS_SAVE:
|
||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) {
|
||||
e->song.ins[curIns]->save(copyOfName.c_str());
|
||||
String lowerCase=fileName;
|
||||
for (char& i: lowerCase) {
|
||||
if (i>='A' && i<='Z') i+='a'-'A';
|
||||
}
|
||||
if ((lowerCase.size()<4 || lowerCase.rfind(".dmp")!=lowerCase.size()-4)) {
|
||||
e->song.ins[curIns]->save(copyOfName.c_str());
|
||||
} else {
|
||||
if (!e->song.ins[curIns]->saveDMP(copyOfName.c_str())) {
|
||||
showError("error while saving instrument! make sure your instrument is compatible.");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GUI_FILE_WAVE_SAVE:
|
||||
if (curWave>=0 && curWave<(int)e->song.wave.size()) {
|
||||
e->song.wave[curWave]->save(copyOfName.c_str());
|
||||
String lowerCase=fileName;
|
||||
for (char& i: lowerCase) {
|
||||
if (i>='A' && i<='Z') i+='a'-'A';
|
||||
}
|
||||
if (lowerCase.size()<4) {
|
||||
e->song.wave[curWave]->save(copyOfName.c_str());
|
||||
} else if (lowerCase.rfind(".dmw")==lowerCase.size()-4) {
|
||||
e->song.wave[curWave]->saveDMW(copyOfName.c_str());
|
||||
} else if (lowerCase.rfind(".raw")==lowerCase.size()-4) {
|
||||
e->song.wave[curWave]->saveRaw(copyOfName.c_str());
|
||||
} else {
|
||||
e->song.wave[curWave]->save(copyOfName.c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GUI_FILE_SAMPLE_OPEN:
|
||||
if (e->addSampleFromFile(copyOfName.c_str())==-1) {
|
||||
case GUI_FILE_SAMPLE_OPEN: {
|
||||
DivSample* s=e->sampleFromFile(copyOfName.c_str());
|
||||
if (s==NULL) {
|
||||
showError(e->getLastError());
|
||||
} else {
|
||||
MARK_MODIFIED;
|
||||
if (e->addSamplePtr(s)==-1) {
|
||||
showError(e->getLastError());
|
||||
} else {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GUI_FILE_SAMPLE_OPEN_REPLACE: {
|
||||
DivSample* s=e->sampleFromFile(copyOfName.c_str());
|
||||
if (s==NULL) {
|
||||
showError(e->getLastError());
|
||||
} else {
|
||||
if (curSample>=0 && curSample<(int)e->song.sample.size()) {
|
||||
e->lockEngine([this,s]() {
|
||||
// if it crashes here please tell me...
|
||||
DivSample* oldSample=e->song.sample[curSample];
|
||||
e->song.sample[curSample]=s;
|
||||
delete oldSample;
|
||||
e->renderSamples();
|
||||
MARK_MODIFIED;
|
||||
});
|
||||
} else {
|
||||
showError("...but you haven't selected a sample!");
|
||||
delete s;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GUI_FILE_SAMPLE_OPEN_RAW:
|
||||
case GUI_FILE_SAMPLE_OPEN_REPLACE_RAW:
|
||||
pendingRawSample=copyOfName;
|
||||
displayPendingRawSample=true;
|
||||
break;
|
||||
case GUI_FILE_SAMPLE_SAVE:
|
||||
if (curSample>=0 && curSample<(int)e->song.sample.size()) {
|
||||
e->song.sample[curSample]->save(copyOfName.c_str());
|
||||
|
|
@ -3508,13 +3651,36 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case GUI_FILE_WAVE_OPEN:
|
||||
if (!e->addWaveFromFile(copyOfName.c_str())) {
|
||||
case GUI_FILE_WAVE_OPEN: {
|
||||
DivWavetable* wave=e->waveFromFile(copyOfName.c_str());
|
||||
if (wave==NULL) {
|
||||
showError("cannot load wavetable! ("+e->getLastError()+")");
|
||||
} else {
|
||||
MARK_MODIFIED;
|
||||
if (e->addWavePtr(wave)==-1) {
|
||||
showError("cannot load wavetable! ("+e->getLastError()+")");
|
||||
} else {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GUI_FILE_WAVE_OPEN_REPLACE: {
|
||||
DivWavetable* wave=e->waveFromFile(copyOfName.c_str());
|
||||
if (wave==NULL) {
|
||||
showError("cannot load wavetable! ("+e->getLastError()+")");
|
||||
} else {
|
||||
if (curWave>=0 && curWave<(int)e->song.wave.size()) {
|
||||
e->lockEngine([this,wave]() {
|
||||
*e->song.wave[curWave]=*wave;
|
||||
MARK_MODIFIED;
|
||||
});
|
||||
} else {
|
||||
showError("...but you haven't selected a wavetable!");
|
||||
}
|
||||
delete wave;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GUI_FILE_EXPORT_VGM: {
|
||||
SafeWriter* w=e->saveVGM(willExport,vgmExportLoop,vgmExportVersion,vgmExportPatternHints);
|
||||
if (w!=NULL) {
|
||||
|
|
@ -3641,6 +3807,11 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::OpenPopup("Select Instrument");
|
||||
}
|
||||
|
||||
if (displayPendingRawSample) {
|
||||
displayPendingRawSample=false;
|
||||
ImGui::OpenPopup("Import Raw Sample");
|
||||
}
|
||||
|
||||
if (displayExporting) {
|
||||
displayExporting=false;
|
||||
ImGui::OpenPopup("Rendering...");
|
||||
|
|
@ -3982,6 +4153,16 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
break;
|
||||
case GUI_WARN_SYSTEM_DEL:
|
||||
if (ImGui::Button("Yes")) {
|
||||
e->removeSystem(sysToDelete,preserveChanPos);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("No")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
break;
|
||||
case GUI_WARN_GENERIC:
|
||||
if (ImGui::Button("OK")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
|
@ -4071,6 +4252,53 @@ bool FurnaceGUI::loop() {
|
|||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopupModal("Import Raw Sample",NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::Text("Data type:");
|
||||
for (int i=0; i<DIV_SAMPLE_DEPTH_MAX; i++) {
|
||||
if (sampleDepths[i]==NULL) continue;
|
||||
if (ImGui::RadioButton(sampleDepths[i],pendingRawSampleDepth==i)) pendingRawSampleDepth=i;
|
||||
}
|
||||
|
||||
if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
pendingRawSampleChannels=1;
|
||||
}
|
||||
if (pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT) {
|
||||
pendingRawSampleBigEndian=false;
|
||||
}
|
||||
|
||||
ImGui::BeginDisabled(pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_8BIT && pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||
ImGui::Text("Channels");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::InputInt("##RSChans",&pendingRawSampleChannels)) {
|
||||
}
|
||||
ImGui::Text("(will be mixed down to mono)");
|
||||
ImGui::Checkbox("Unsigned",&pendingRawSampleUnsigned);
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::BeginDisabled(pendingRawSampleDepth!=DIV_SAMPLE_DEPTH_16BIT);
|
||||
ImGui::Checkbox("Big endian",&pendingRawSampleBigEndian);
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (ImGui::Button("OK")) {
|
||||
DivSample* s=e->sampleFromFileRaw(pendingRawSample.c_str(),(DivSampleDepth)pendingRawSampleDepth,pendingRawSampleChannels,pendingRawSampleBigEndian,pendingRawSampleUnsigned);
|
||||
if (s==NULL) {
|
||||
showError(e->getLastError());
|
||||
} else {
|
||||
if (e->addSamplePtr(s)==-1) {
|
||||
showError(e->getLastError());
|
||||
} else {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel")) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
layoutTimeEnd=SDL_GetPerformanceCounter();
|
||||
|
||||
// backup trigger
|
||||
|
|
@ -4187,6 +4415,8 @@ bool FurnaceGUI::init() {
|
|||
pianoOpen=e->getConfBool("pianoOpen",false);
|
||||
notesOpen=e->getConfBool("notesOpen",false);
|
||||
channelsOpen=e->getConfBool("channelsOpen",false);
|
||||
patManagerOpen=e->getConfBool("patManagerOpen",false);
|
||||
sysManagerOpen=e->getConfBool("sysManagerOpen",false);
|
||||
regViewOpen=e->getConfBool("regViewOpen",false);
|
||||
logOpen=e->getConfBool("logOpen",false);
|
||||
effectListOpen=e->getConfBool("effectListOpen",false);
|
||||
|
|
@ -4429,6 +4659,8 @@ bool FurnaceGUI::finish() {
|
|||
e->setConf("pianoOpen",pianoOpen);
|
||||
e->setConf("notesOpen",notesOpen);
|
||||
e->setConf("channelsOpen",channelsOpen);
|
||||
e->setConf("patManagerOpen",patManagerOpen);
|
||||
e->setConf("sysManagerOpen",sysManagerOpen);
|
||||
e->setConf("regViewOpen",regViewOpen);
|
||||
e->setConf("logOpen",logOpen);
|
||||
e->setConf("effectListOpen",effectListOpen);
|
||||
|
|
@ -4521,10 +4753,16 @@ FurnaceGUI::FurnaceGUI():
|
|||
noteInputPoly(true),
|
||||
displayPendingIns(false),
|
||||
pendingInsSingle(false),
|
||||
displayPendingRawSample(false),
|
||||
vgmExportVersion(0x171),
|
||||
drawHalt(10),
|
||||
macroPointSize(16),
|
||||
waveEditStyle(0),
|
||||
curSysSection(NULL),
|
||||
pendingRawSampleDepth(8),
|
||||
pendingRawSampleChannels(1),
|
||||
pendingRawSampleUnsigned(false),
|
||||
pendingRawSampleBigEndian(false),
|
||||
globalWinFlags(0),
|
||||
curFileDialog(GUI_FILE_OPEN),
|
||||
warnAction(GUI_WARN_OPEN),
|
||||
|
|
@ -4603,6 +4841,8 @@ FurnaceGUI::FurnaceGUI():
|
|||
subSongsOpen(true),
|
||||
findOpen(false),
|
||||
spoilerOpen(false),
|
||||
patManagerOpen(false),
|
||||
sysManagerOpen(false),
|
||||
selecting(false),
|
||||
selectingFull(false),
|
||||
dragging(false),
|
||||
|
|
@ -4679,6 +4919,8 @@ FurnaceGUI::FurnaceGUI():
|
|||
macroDragInitialValueSet(false),
|
||||
macroDragInitialValue(false),
|
||||
macroDragChar(false),
|
||||
macroDragBit30(false),
|
||||
macroDragSettingBit30(false),
|
||||
macroDragLineMode(false),
|
||||
macroDragMouseMoved(false),
|
||||
macroDragLineInitial(0,0),
|
||||
|
|
@ -4717,6 +4959,8 @@ FurnaceGUI::FurnaceGUI():
|
|||
eventTimeEnd(0),
|
||||
eventTimeDelta(0),
|
||||
chanToMove(-1),
|
||||
sysToMove(-1),
|
||||
sysToDelete(-1),
|
||||
transposeAmount(0),
|
||||
randomizeMin(0),
|
||||
randomizeMax(255),
|
||||
|
|
@ -4888,4 +5132,16 @@ FurnaceGUI::FurnaceGUI():
|
|||
memset(queryReplaceEffectValDo,0,sizeof(bool)*8);
|
||||
|
||||
chanOscGrad.bgColor=ImVec4(0.0f,0.0f,0.0f,1.0f);
|
||||
|
||||
memset(noteOffLabel,0,32);
|
||||
memset(noteRelLabel,0,32);
|
||||
memset(macroRelLabel,0,32);
|
||||
memset(emptyLabel,0,32);
|
||||
memset(emptyLabel2,0,32);
|
||||
|
||||
strncpy(noteOffLabel,"OFF",32);
|
||||
strncpy(noteRelLabel,"===",32);
|
||||
strncpy(macroRelLabel,"REL",32);
|
||||
strncpy(emptyLabel,"...",32);
|
||||
strncpy(emptyLabel2,"..",32);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,6 +208,13 @@ enum FurnaceGUIColors {
|
|||
GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_MISC,
|
||||
|
||||
GUI_COLOR_PAT_MANAGER_NULL,
|
||||
GUI_COLOR_PAT_MANAGER_USED,
|
||||
GUI_COLOR_PAT_MANAGER_OVERUSED,
|
||||
GUI_COLOR_PAT_MANAGER_EXTREMELY_OVERUSED,
|
||||
GUI_COLOR_PAT_MANAGER_COMBO_BREAKER,
|
||||
GUI_COLOR_PAT_MANAGER_UNUSED,
|
||||
|
||||
GUI_COLOR_PIANO_BACKGROUND,
|
||||
GUI_COLOR_PIANO_KEY_BOTTOM,
|
||||
GUI_COLOR_PIANO_KEY_TOP,
|
||||
|
|
@ -250,6 +257,8 @@ enum FurnaceGUIWindows {
|
|||
GUI_WINDOW_PIANO,
|
||||
GUI_WINDOW_NOTES,
|
||||
GUI_WINDOW_CHANNELS,
|
||||
GUI_WINDOW_PAT_MANAGER,
|
||||
GUI_WINDOW_SYS_MANAGER,
|
||||
GUI_WINDOW_REGISTER_VIEW,
|
||||
GUI_WINDOW_LOG,
|
||||
GUI_WINDOW_EFFECT_LIST,
|
||||
|
|
@ -267,8 +276,12 @@ enum FurnaceGUIFileDialogs {
|
|||
GUI_FILE_INS_OPEN_REPLACE,
|
||||
GUI_FILE_INS_SAVE,
|
||||
GUI_FILE_WAVE_OPEN,
|
||||
GUI_FILE_WAVE_OPEN_REPLACE,
|
||||
GUI_FILE_WAVE_SAVE,
|
||||
GUI_FILE_SAMPLE_OPEN,
|
||||
GUI_FILE_SAMPLE_OPEN_RAW,
|
||||
GUI_FILE_SAMPLE_OPEN_REPLACE,
|
||||
GUI_FILE_SAMPLE_OPEN_REPLACE_RAW,
|
||||
GUI_FILE_SAMPLE_SAVE,
|
||||
GUI_FILE_EXPORT_AUDIO_ONE,
|
||||
GUI_FILE_EXPORT_AUDIO_PER_SYS,
|
||||
|
|
@ -305,6 +318,7 @@ enum FurnaceGUIWarnings {
|
|||
GUI_WARN_CLOSE_SETTINGS,
|
||||
GUI_WARN_CLEAR,
|
||||
GUI_WARN_SUBSONG_DEL,
|
||||
GUI_WARN_SYSTEM_DEL,
|
||||
GUI_WARN_GENERIC
|
||||
};
|
||||
|
||||
|
|
@ -365,6 +379,8 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_WINDOW_PIANO,
|
||||
GUI_ACTION_WINDOW_NOTES,
|
||||
GUI_ACTION_WINDOW_CHANNELS,
|
||||
GUI_ACTION_WINDOW_PAT_MANAGER,
|
||||
GUI_ACTION_WINDOW_SYS_MANAGER,
|
||||
GUI_ACTION_WINDOW_REGISTER_VIEW,
|
||||
GUI_ACTION_WINDOW_LOG,
|
||||
GUI_ACTION_WINDOW_EFFECT_LIST,
|
||||
|
|
@ -459,6 +475,7 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_WAVE_LIST_ADD,
|
||||
GUI_ACTION_WAVE_LIST_DUPLICATE,
|
||||
GUI_ACTION_WAVE_LIST_OPEN,
|
||||
GUI_ACTION_WAVE_LIST_OPEN_REPLACE,
|
||||
GUI_ACTION_WAVE_LIST_SAVE,
|
||||
GUI_ACTION_WAVE_LIST_MOVE_UP,
|
||||
GUI_ACTION_WAVE_LIST_MOVE_DOWN,
|
||||
|
|
@ -472,6 +489,9 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_SAMPLE_LIST_ADD,
|
||||
GUI_ACTION_SAMPLE_LIST_DUPLICATE,
|
||||
GUI_ACTION_SAMPLE_LIST_OPEN,
|
||||
GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE,
|
||||
GUI_ACTION_SAMPLE_LIST_OPEN_RAW,
|
||||
GUI_ACTION_SAMPLE_LIST_OPEN_REPLACE_RAW,
|
||||
GUI_ACTION_SAMPLE_LIST_SAVE,
|
||||
GUI_ACTION_SAMPLE_LIST_MOVE_UP,
|
||||
GUI_ACTION_SAMPLE_LIST_MOVE_DOWN,
|
||||
|
|
@ -858,10 +878,10 @@ struct FurnaceGUIMacroDesc {
|
|||
const char* modeName;
|
||||
ImVec4 color;
|
||||
unsigned int bitOffset;
|
||||
bool isBitfield, blockMode;
|
||||
bool isBitfield, blockMode, bit30;
|
||||
String (*hoverFunc)(int,float);
|
||||
|
||||
FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, const char* mName=NULL, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0):
|
||||
FurnaceGUIMacroDesc(const char* name, DivInstrumentMacro* m, int macroMin, int macroMax, float macroHeight, ImVec4 col=ImVec4(1.0f,1.0f,1.0f,1.0f), bool block=false, const char* mName=NULL, String (*hf)(int,float)=NULL, bool bitfield=false, const char** bfVal=NULL, unsigned int bitOff=0, bool bit30Special=false):
|
||||
macro(m),
|
||||
height(macroHeight),
|
||||
displayName(name),
|
||||
|
|
@ -871,6 +891,7 @@ struct FurnaceGUIMacroDesc {
|
|||
bitOffset(bitOff),
|
||||
isBitfield(bitfield),
|
||||
blockMode(block),
|
||||
bit30(bit30Special),
|
||||
hoverFunc(hf) {
|
||||
// MSVC -> hell
|
||||
this->min=macroMin;
|
||||
|
|
@ -956,22 +977,30 @@ class FurnaceGUI {
|
|||
int sampleTexW, sampleTexH;
|
||||
bool updateSampleTex;
|
||||
|
||||
String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile;
|
||||
String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile, sysSearchQuery, newSongQuery;
|
||||
String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport;
|
||||
String workingDirVGMExport, workingDirROMExport, workingDirFont, workingDirColors, workingDirKeybinds;
|
||||
String workingDirLayout, workingDirROM, workingDirTest;
|
||||
String mmlString[32];
|
||||
String mmlStringW;
|
||||
|
||||
std::vector<DivSystem> sysSearchResults;
|
||||
std::vector<FurnaceGUISysDef> newSongSearchResults;
|
||||
|
||||
bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints;
|
||||
bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu;
|
||||
bool displayNew, fullScreen, preserveChanPos, wantScrollList, noteInputPoly;
|
||||
bool displayPendingIns, pendingInsSingle;
|
||||
bool displayPendingIns, pendingInsSingle, displayPendingRawSample;
|
||||
bool willExport[32];
|
||||
int vgmExportVersion;
|
||||
int drawHalt;
|
||||
int macroPointSize;
|
||||
int waveEditStyle;
|
||||
const int* curSysSection;
|
||||
|
||||
String pendingRawSample;
|
||||
int pendingRawSampleDepth, pendingRawSampleChannels;
|
||||
bool pendingRawSampleUnsigned, pendingRawSampleBigEndian;
|
||||
|
||||
ImGuiWindowFlags globalWinFlags;
|
||||
|
||||
|
|
@ -1013,6 +1042,12 @@ class FurnaceGUI {
|
|||
ImU32 sysCmd1Grad[256];
|
||||
ImU32 sysCmd2Grad[256];
|
||||
|
||||
char noteOffLabel[32];
|
||||
char noteRelLabel[32];
|
||||
char macroRelLabel[32];
|
||||
char emptyLabel[32];
|
||||
char emptyLabel2[32];
|
||||
|
||||
struct Settings {
|
||||
int mainFontSize, patFontSize, iconSize;
|
||||
int audioEngine;
|
||||
|
|
@ -1064,6 +1099,8 @@ class FurnaceGUI {
|
|||
int roundedMenus;
|
||||
int loadJapanese;
|
||||
int loadChinese;
|
||||
int loadChineseTraditional;
|
||||
int loadKorean;
|
||||
int fmLayout;
|
||||
int sampleLayout;
|
||||
int waveLayout;
|
||||
|
|
@ -1107,6 +1144,12 @@ class FurnaceGUI {
|
|||
int unsignedDetune;
|
||||
int noThreadedInput;
|
||||
int clampSamples;
|
||||
int saveUnusedPatterns;
|
||||
int channelColors;
|
||||
int channelTextColors;
|
||||
int channelStyle;
|
||||
int channelVolStyle;
|
||||
int channelFeedbackStyle;
|
||||
unsigned int maxUndoSteps;
|
||||
String mainFontPath;
|
||||
String patFontPath;
|
||||
|
|
@ -1115,6 +1158,11 @@ class FurnaceGUI {
|
|||
String midiOutDevice;
|
||||
String c163Name;
|
||||
String initialSysName;
|
||||
String noteOffLabel;
|
||||
String noteRelLabel;
|
||||
String macroRelLabel;
|
||||
String emptyLabel;
|
||||
String emptyLabel2;
|
||||
std::vector<int> initialSys;
|
||||
|
||||
Settings():
|
||||
|
|
@ -1170,6 +1218,8 @@ class FurnaceGUI {
|
|||
roundedMenus(0),
|
||||
loadJapanese(0),
|
||||
loadChinese(0),
|
||||
loadChineseTraditional(0),
|
||||
loadKorean(0),
|
||||
fmLayout(0),
|
||||
sampleLayout(0),
|
||||
waveLayout(0),
|
||||
|
|
@ -1213,6 +1263,12 @@ class FurnaceGUI {
|
|||
unsignedDetune(0),
|
||||
noThreadedInput(0),
|
||||
clampSamples(0),
|
||||
saveUnusedPatterns(0),
|
||||
channelColors(1),
|
||||
channelTextColors(0),
|
||||
channelStyle(0),
|
||||
channelVolStyle(0),
|
||||
channelFeedbackStyle(1),
|
||||
maxUndoSteps(100),
|
||||
mainFontPath(""),
|
||||
patFontPath(""),
|
||||
|
|
@ -1220,7 +1276,12 @@ class FurnaceGUI {
|
|||
midiInDevice(""),
|
||||
midiOutDevice(""),
|
||||
c163Name(""),
|
||||
initialSysName("Sega Genesis/Mega Drive") {}
|
||||
initialSysName("Sega Genesis/Mega Drive"),
|
||||
noteOffLabel("OFF"),
|
||||
noteRelLabel("==="),
|
||||
macroRelLabel("REL"),
|
||||
emptyLabel("..."),
|
||||
emptyLabel2("..") {}
|
||||
} settings;
|
||||
|
||||
char finalLayoutPath[4096];
|
||||
|
|
@ -1237,7 +1298,7 @@ class FurnaceGUI {
|
|||
bool waveListOpen, waveEditOpen, sampleListOpen, sampleEditOpen, aboutOpen, settingsOpen;
|
||||
bool mixerOpen, debugOpen, inspectorOpen, oscOpen, volMeterOpen, statsOpen, compatFlagsOpen;
|
||||
bool pianoOpen, notesOpen, channelsOpen, regViewOpen, logOpen, effectListOpen, chanOscOpen;
|
||||
bool subSongsOpen, findOpen, spoilerOpen;
|
||||
bool subSongsOpen, findOpen, spoilerOpen, patManagerOpen, sysManagerOpen;
|
||||
|
||||
SelectionPoint selStart, selEnd, cursor, cursorDrag, dragStart, dragEnd;
|
||||
bool selecting, selectingFull, dragging, curNibble, orderNibble, followOrders, followPattern, changeAllOrders, mobileUI;
|
||||
|
|
@ -1352,6 +1413,8 @@ class FurnaceGUI {
|
|||
bool macroDragInitialValueSet;
|
||||
bool macroDragInitialValue;
|
||||
bool macroDragChar;
|
||||
bool macroDragBit30;
|
||||
bool macroDragSettingBit30;
|
||||
bool macroDragLineMode;
|
||||
bool macroDragMouseMoved;
|
||||
ImVec2 macroDragLineInitial;
|
||||
|
|
@ -1363,7 +1426,7 @@ class FurnaceGUI {
|
|||
|
||||
ImVec2 macroLoopDragStart;
|
||||
ImVec2 macroLoopDragAreaSize;
|
||||
signed char* macroLoopDragTarget;
|
||||
unsigned char* macroLoopDragTarget;
|
||||
int macroLoopDragLen;
|
||||
bool macroLoopDragActive;
|
||||
|
||||
|
|
@ -1383,7 +1446,7 @@ class FurnaceGUI {
|
|||
int renderTimeBegin, renderTimeEnd, renderTimeDelta;
|
||||
int eventTimeBegin, eventTimeEnd, eventTimeDelta;
|
||||
|
||||
int chanToMove;
|
||||
int chanToMove, sysToMove, sysToDelete;
|
||||
|
||||
ImVec2 patWindowPos, patWindowSize;
|
||||
|
||||
|
|
@ -1546,6 +1609,8 @@ class FurnaceGUI {
|
|||
void drawPiano();
|
||||
void drawNotes();
|
||||
void drawChannels();
|
||||
void drawPatManager();
|
||||
void drawSysManager();
|
||||
void drawRegView();
|
||||
void drawAbout();
|
||||
void drawSettings();
|
||||
|
|
@ -1613,6 +1678,7 @@ class FurnaceGUI {
|
|||
void doReplace();
|
||||
void doDrag();
|
||||
void editOptions(bool topMenu);
|
||||
DivSystem systemPicker();
|
||||
void noteInput(int num, int key, int vol=-1);
|
||||
void valueInput(int num, bool direct=false, int target=-1);
|
||||
|
||||
|
|
@ -1641,8 +1707,8 @@ class FurnaceGUI {
|
|||
void applyUISettings(bool updateFonts=true);
|
||||
void initSystemPresets();
|
||||
|
||||
void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false);
|
||||
void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, signed char& macroLoop, int macroMin, int macroMax, signed char& macroRel);
|
||||
void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel, bool hex=false, bool bit30=false);
|
||||
void decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned char& macroRel, bool bit30=false);
|
||||
void decodeMMLStrW(String& source, int* macro, int& macroLen, int macroMax, bool hex=false);
|
||||
|
||||
String encodeKeyMap(std::map<int,int>& map);
|
||||
|
|
@ -1653,6 +1719,7 @@ class FurnaceGUI {
|
|||
public:
|
||||
void showWarning(String what, FurnaceGUIWarnings type);
|
||||
void showError(String what);
|
||||
const char* noteNameNormal(short note, short octave);
|
||||
const char* noteName(short note, short octave);
|
||||
bool decodeNote(const char* what, short& note, short& octave);
|
||||
void bindEngine(DivEngine* eng);
|
||||
|
|
|
|||
|
|
@ -501,6 +501,8 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("WINDOW_PIANO", "Piano", 0),
|
||||
D("WINDOW_NOTES", "Song Comments", 0),
|
||||
D("WINDOW_CHANNELS", "Channels", 0),
|
||||
D("WINDOW_PAT_MANAGER", "Pattern Manager", 0),
|
||||
D("WINDOW_SYS_MANAGER", "Chip Manager", 0),
|
||||
D("WINDOW_REGISTER_VIEW", "Register View", 0),
|
||||
D("WINDOW_LOG", "Log Viewer", 0),
|
||||
D("EFFECT_LIST", "Effect List", 0),
|
||||
|
|
@ -595,6 +597,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("WAVE_LIST_ADD", "Add", SDLK_INSERT),
|
||||
D("WAVE_LIST_DUPLICATE", "Duplicate", FURKMOD_CMD|SDLK_d),
|
||||
D("WAVE_LIST_OPEN", "Open", 0),
|
||||
D("WAVE_LIST_OPEN_REPLACE", "Open (replace current)", 0),
|
||||
D("WAVE_LIST_SAVE", "Save", 0),
|
||||
D("WAVE_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP),
|
||||
D("WAVE_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN),
|
||||
|
|
@ -608,6 +611,9 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("SAMPLE_LIST_ADD", "Add", SDLK_INSERT),
|
||||
D("SAMPLE_LIST_DUPLICATE", "Duplicate", FURKMOD_CMD|SDLK_d),
|
||||
D("SAMPLE_LIST_OPEN", "Open", 0),
|
||||
D("SAMPLE_LIST_OPEN_REPLACE", "Open (replace current)", 0),
|
||||
D("SAMPLE_LIST_OPEN_RAW", "Import raw data", 0),
|
||||
D("SAMPLE_LIST_OPEN_REPLACE_RAW", "Import raw data (replace current)", 0),
|
||||
D("SAMPLE_LIST_SAVE", "Save", 0),
|
||||
D("SAMPLE_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP),
|
||||
D("SAMPLE_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN),
|
||||
|
|
@ -829,6 +835,13 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
D(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,"",ImVec4(0.0f,1.0f,0.5f,1.0f)),
|
||||
D(GUI_COLOR_PATTERN_EFFECT_MISC,"",ImVec4(0.3f,0.3f,1.0f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_PAT_MANAGER_NULL,"",ImVec4(0.15f,0.15f,0.15f,1.0f)),
|
||||
D(GUI_COLOR_PAT_MANAGER_USED,"",ImVec4(0.15f,1.0f,0.15f,1.0f)),
|
||||
D(GUI_COLOR_PAT_MANAGER_OVERUSED,"",ImVec4(1.0f,1.0f,0.15f,1.0f)),
|
||||
D(GUI_COLOR_PAT_MANAGER_EXTREMELY_OVERUSED,"",ImVec4(1.0f,0.5f,0.15f,1.0f)),
|
||||
D(GUI_COLOR_PAT_MANAGER_COMBO_BREAKER,"",ImVec4(1.0f,0.15f,1.0f,1.0f)),
|
||||
D(GUI_COLOR_PAT_MANAGER_UNUSED,"",ImVec4(1.0f,0.15f,0.15f,1.0f)),
|
||||
|
||||
D(GUI_COLOR_PIANO_BACKGROUND,"",ImVec4(0.0f,0.0f,0.0f,1.0f)),
|
||||
D(GUI_COLOR_PIANO_KEY_BOTTOM,"",ImVec4(1.0f,1.0f,1.0f,1.0f)),
|
||||
D(GUI_COLOR_PIANO_KEY_TOP,"",ImVec4(0.0f,0.0f,0.0f,1.0f)),
|
||||
|
|
@ -848,7 +861,9 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
|
|||
};
|
||||
#undef D
|
||||
|
||||
// define systems.
|
||||
// define chips here
|
||||
|
||||
// all chips
|
||||
const int availableSystems[]={
|
||||
DIV_SYSTEM_YM2612,
|
||||
DIV_SYSTEM_YM2612_EXT,
|
||||
|
|
@ -920,3 +935,115 @@ const int availableSystems[]={
|
|||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
// FM
|
||||
const int chipsFM[]={
|
||||
DIV_SYSTEM_YM2612,
|
||||
DIV_SYSTEM_YM2612_EXT,
|
||||
DIV_SYSTEM_YM2612_FRAC,
|
||||
DIV_SYSTEM_YM2612_FRAC_EXT,
|
||||
DIV_SYSTEM_YM2151,
|
||||
DIV_SYSTEM_YM2610,
|
||||
DIV_SYSTEM_YM2610_EXT,
|
||||
DIV_SYSTEM_YM2610_FULL,
|
||||
DIV_SYSTEM_YM2610_FULL_EXT,
|
||||
DIV_SYSTEM_YM2610B,
|
||||
DIV_SYSTEM_YM2610B_EXT,
|
||||
DIV_SYSTEM_YMU759,
|
||||
DIV_SYSTEM_OPN,
|
||||
DIV_SYSTEM_OPN_EXT,
|
||||
DIV_SYSTEM_PC98,
|
||||
DIV_SYSTEM_PC98_EXT,
|
||||
DIV_SYSTEM_OPLL,
|
||||
DIV_SYSTEM_OPLL_DRUMS,
|
||||
DIV_SYSTEM_VRC7,
|
||||
DIV_SYSTEM_OPL,
|
||||
DIV_SYSTEM_OPL_DRUMS,
|
||||
DIV_SYSTEM_Y8950,
|
||||
DIV_SYSTEM_Y8950_DRUMS,
|
||||
DIV_SYSTEM_OPL2,
|
||||
DIV_SYSTEM_OPL2_DRUMS,
|
||||
DIV_SYSTEM_OPL3,
|
||||
DIV_SYSTEM_OPL3_DRUMS,
|
||||
DIV_SYSTEM_OPZ,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
// square
|
||||
const int chipsSquare[]={
|
||||
DIV_SYSTEM_SMS,
|
||||
DIV_SYSTEM_AY8910,
|
||||
DIV_SYSTEM_PCSPKR,
|
||||
DIV_SYSTEM_SAA1099,
|
||||
DIV_SYSTEM_VIC20,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
// wavetable
|
||||
const int chipsWave[]={
|
||||
DIV_SYSTEM_PCE,
|
||||
DIV_SYSTEM_X1_010,
|
||||
DIV_SYSTEM_SWAN,
|
||||
DIV_SYSTEM_BUBSYS_WSG,
|
||||
DIV_SYSTEM_N163,
|
||||
DIV_SYSTEM_FDS,
|
||||
DIV_SYSTEM_SCC,
|
||||
DIV_SYSTEM_SCC_PLUS,
|
||||
DIV_SYSTEM_NAMCO,
|
||||
DIV_SYSTEM_NAMCO_15XX,
|
||||
DIV_SYSTEM_NAMCO_CUS30,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
// specialized
|
||||
const int chipsSpecial[]={
|
||||
DIV_SYSTEM_GB,
|
||||
DIV_SYSTEM_NES,
|
||||
DIV_SYSTEM_C64_8580,
|
||||
DIV_SYSTEM_C64_6581,
|
||||
DIV_SYSTEM_SFX_BEEPER,
|
||||
DIV_SYSTEM_DUMMY,
|
||||
DIV_SYSTEM_SOUND_UNIT,
|
||||
DIV_SYSTEM_TIA,
|
||||
DIV_SYSTEM_AY8930,
|
||||
DIV_SYSTEM_LYNX,
|
||||
DIV_SYSTEM_VERA,
|
||||
DIV_SYSTEM_PET,
|
||||
DIV_SYSTEM_VRC6,
|
||||
DIV_SYSTEM_MMC5,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
// sample
|
||||
const int chipsSample[]={
|
||||
DIV_SYSTEM_SEGAPCM,
|
||||
DIV_SYSTEM_SEGAPCM_COMPAT,
|
||||
DIV_SYSTEM_AMIGA,
|
||||
DIV_SYSTEM_QSOUND,
|
||||
DIV_SYSTEM_X1_010,
|
||||
DIV_SYSTEM_YMZ280B,
|
||||
DIV_SYSTEM_MSM6258,
|
||||
DIV_SYSTEM_MSM6295,
|
||||
DIV_SYSTEM_RF5C68,
|
||||
DIV_SYSTEM_PCM_DAC,
|
||||
0 // don't remove this last one!
|
||||
};
|
||||
|
||||
const int* chipCategories[]={
|
||||
availableSystems,
|
||||
chipsFM,
|
||||
chipsSquare,
|
||||
chipsWave,
|
||||
chipsSpecial,
|
||||
chipsSample,
|
||||
NULL
|
||||
};
|
||||
|
||||
const char* chipCategoryNames[]={
|
||||
"All chips",
|
||||
"FM",
|
||||
"Square",
|
||||
"Wavetable",
|
||||
"Special",
|
||||
"Sample",
|
||||
NULL
|
||||
};
|
||||
|
|
@ -43,7 +43,14 @@ extern const char* insTypes[];
|
|||
extern const char* sampleLoopModes[];
|
||||
extern const char* sampleDepths[];
|
||||
extern const char* resampleStrats[];
|
||||
extern const char* chipCategoryNames[];
|
||||
extern const int availableSystems[];
|
||||
extern const int chipsFM[];
|
||||
extern const int chipsSquare[];
|
||||
extern const int chipsWavetable[];
|
||||
extern const int chipsSpecial[];
|
||||
extern const int chipsSample[];
|
||||
extern const int* chipCategories[];
|
||||
extern const FurnaceGUIActionDef guiActions[];
|
||||
extern const FurnaceGUIColorDef guiColors[];
|
||||
extern const int altValues[24];
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "gui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "../engine/macroInt.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
#include "guiConst.h"
|
||||
|
|
@ -305,10 +306,14 @@ const char* gbHWSeqCmdTypes[6]={
|
|||
"Loop until Release"
|
||||
};
|
||||
|
||||
// do not change these!
|
||||
// anything other than a checkbox will look ugly!
|
||||
//
|
||||
// if you really need to, and have a good rationale (and by good I mean a VERY
|
||||
// good one), please tell me and we'll sort it out.
|
||||
const char* macroAbsoluteMode="Fixed";
|
||||
const char* macroRelativeMode="Relative";
|
||||
const char* macroQSoundMode="QSound";
|
||||
|
||||
const char* macroDummyMode="Bug";
|
||||
|
||||
String macroHoverNote(int id, float val) {
|
||||
|
|
@ -326,6 +331,11 @@ String macroHoverLoop(int id, float val) {
|
|||
return "";
|
||||
}
|
||||
|
||||
String macroHoverBit30(int id, float val) {
|
||||
if (val>0) return "Fixed";
|
||||
return "Relative";
|
||||
}
|
||||
|
||||
String macroHoverES5506FilterMode(int id, float val) {
|
||||
String mode="???";
|
||||
switch (((int)val)&3) {
|
||||
|
|
@ -1187,10 +1197,22 @@ String genericGuide(float value) {
|
|||
return fmt::sprintf("%d",(int)value);
|
||||
}
|
||||
|
||||
inline int deBit30(const int val) {
|
||||
if ((val&0xc0000000)==0x40000000 || (val&0xc0000000)==0x80000000) return val^0x40000000;
|
||||
return val;
|
||||
}
|
||||
|
||||
inline bool enBit30(const int val) {
|
||||
if ((val&0xc0000000)==0x40000000 || (val&0xc0000000)==0x80000000) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
||||
float asFloat[256];
|
||||
int asInt[256];
|
||||
float loopIndicator[256];
|
||||
float bit30Indicator[256];
|
||||
bool doHighlight[256];
|
||||
int index=0;
|
||||
|
||||
float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize;
|
||||
|
|
@ -1209,14 +1231,14 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
}
|
||||
ImGui::TableNextColumn();
|
||||
float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace;
|
||||
int totalFit=MIN(128,availableWidth/MAX(1,macroPointSize*dpiScale));
|
||||
if (macroDragScroll>128-totalFit) {
|
||||
macroDragScroll=128-totalFit;
|
||||
int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale));
|
||||
if (macroDragScroll>255-totalFit) {
|
||||
macroDragScroll=255-totalFit;
|
||||
}
|
||||
ImGui::SetNextItemWidth(availableWidth);
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,128-totalFit,"")) {
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) {
|
||||
if (macroDragScroll<0) macroDragScroll=0;
|
||||
if (macroDragScroll>128-totalFit) macroDragScroll=128-totalFit;
|
||||
if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit;
|
||||
}
|
||||
|
||||
// draw macros
|
||||
|
|
@ -1233,9 +1255,36 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
}
|
||||
if (i.macro->open) {
|
||||
ImGui::SetNextItemWidth(lenAvail);
|
||||
if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,&i.macro->len,&_ONE,&_THREE)) { MARK_MODIFIED
|
||||
if (i.macro->len>128) i.macro->len=128;
|
||||
int macroLen=i.macro->len;
|
||||
if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED
|
||||
if (macroLen<0) macroLen=0;
|
||||
if (macroLen>255) macroLen=255;
|
||||
i.macro->len=macroLen;
|
||||
}
|
||||
if (ImGui::Button(ICON_FA_BAR_CHART "##IMacroType")) {
|
||||
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Coming soon!");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Delay/Step Length");
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) {
|
||||
if (i.macro->speed<1) i.macro->speed=1;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
// do not change this!
|
||||
// anything other than a checkbox will look ugly!
|
||||
// if you really need more than two macro modes please tell me.
|
||||
if (i.modeName!=NULL) {
|
||||
bool modeVal=i.macro->mode;
|
||||
String modeName=fmt::sprintf("%s##IMacroMode",i.modeName);
|
||||
|
|
@ -1248,17 +1297,19 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
// macro area
|
||||
ImGui::TableNextColumn();
|
||||
for (int j=0; j<256; j++) {
|
||||
bit30Indicator[j]=0;
|
||||
if (j+macroDragScroll>=i.macro->len) {
|
||||
asFloat[j]=0;
|
||||
asInt[j]=0;
|
||||
} else {
|
||||
asFloat[j]=i.macro->val[j+macroDragScroll];
|
||||
asInt[j]=i.macro->val[j+macroDragScroll]+i.bitOffset;
|
||||
asFloat[j]=deBit30(i.macro->val[j+macroDragScroll]);
|
||||
asInt[j]=deBit30(i.macro->val[j+macroDragScroll])+i.bitOffset;
|
||||
if (i.bit30) bit30Indicator[j]=enBit30(i.macro->val[j+macroDragScroll]);
|
||||
}
|
||||
if (j+macroDragScroll>=i.macro->len || (j+macroDragScroll>i.macro->rel && i.macro->loop<i.macro->rel)) {
|
||||
loopIndicator[j]=0;
|
||||
} else {
|
||||
loopIndicator[j]=((i.macro->loop!=-1 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=-1 && (j+macroDragScroll)==i.macro->rel)<<1);
|
||||
loopIndicator[j]=((i.macro->loop!=255 && (j+macroDragScroll)>=i.macro->loop))|((i.macro->rel!=255 && (j+macroDragScroll)==i.macro->rel)<<1);
|
||||
}
|
||||
}
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0.0f,0.0f));
|
||||
|
|
@ -1278,11 +1329,33 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
if (i.macro->vZoom>(i.max-i.min)) {
|
||||
i.macro->vZoom=i.max-i.min;
|
||||
}
|
||||
|
||||
|
||||
memset(doHighlight,0,256*sizeof(bool));
|
||||
if (e->isRunning()) for (int j=0; j<e->getTotalChannelCount(); j++) {
|
||||
DivChannelState* chanState=e->getChanState(j);
|
||||
if (chanState==NULL) continue;
|
||||
|
||||
if (chanState->keyOff) continue;
|
||||
if (chanState->lastIns!=curIns) continue;
|
||||
|
||||
DivMacroInt* macroInt=e->getMacroInt(j);
|
||||
if (macroInt==NULL) continue;
|
||||
|
||||
DivMacroStruct* macroStruct=macroInt->structByName(i.macro->name);
|
||||
if (macroStruct==NULL) continue;
|
||||
|
||||
if (macroStruct->lastPos>i.macro->len) continue;
|
||||
if (macroStruct->lastPos<macroDragScroll) continue;
|
||||
if (macroStruct->lastPos>255) continue;
|
||||
if (!macroStruct->actualHad) continue;
|
||||
|
||||
doHighlight[macroStruct->lastPos-macroDragScroll]=true;
|
||||
}
|
||||
|
||||
if (i.isBitfield) {
|
||||
PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)));
|
||||
PlotBitfield("##IMacro",asInt,totalFit,0,i.bitfieldBits,i.max,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),doHighlight);
|
||||
} else {
|
||||
PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.blockMode,i.macro->open?genericGuide:NULL);
|
||||
PlotCustom("##IMacro",asFloat,totalFit,macroDragScroll,NULL,i.min+i.macro->vScroll,i.min+i.macro->vScroll+i.macro->vZoom,ImVec2(availableWidth,(i.macro->open)?(i.height*dpiScale):(32.0f*dpiScale)),sizeof(float),i.color,i.macro->len-macroDragScroll,i.hoverFunc,i.blockMode,i.macro->open?genericGuide:NULL,doHighlight);
|
||||
}
|
||||
if (i.macro->open && (ImGui::IsItemClicked(ImGuiMouseButton_Left) || ImGui::IsItemClicked(ImGuiMouseButton_Right))) {
|
||||
macroDragStart=ImGui::GetItemRectMin();
|
||||
|
|
@ -1300,6 +1373,8 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
macroDragInitialValue=false;
|
||||
macroDragLen=totalFit;
|
||||
macroDragActive=true;
|
||||
macroDragBit30=i.bit30;
|
||||
macroDragSettingBit30=false;
|
||||
macroDragTarget=i.macro->val;
|
||||
macroDragChar=false;
|
||||
macroDragLineMode=(i.isBitfield)?false:ImGui::IsItemClicked(ImGuiMouseButton_Right);
|
||||
|
|
@ -1367,6 +1442,27 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
}
|
||||
}
|
||||
|
||||
// bit 30 area
|
||||
if (i.bit30) {
|
||||
PlotCustom("##IMacroBit30",bit30Indicator,totalFit,macroDragScroll,NULL,0,1,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverBit30);
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
|
||||
macroDragStart=ImGui::GetItemRectMin();
|
||||
macroDragAreaSize=ImVec2(availableWidth,12.0f*dpiScale);
|
||||
macroDragInitialValueSet=false;
|
||||
macroDragInitialValue=false;
|
||||
macroDragLen=totalFit;
|
||||
macroDragActive=true;
|
||||
macroDragBit30=i.bit30;
|
||||
macroDragSettingBit30=true;
|
||||
macroDragTarget=i.macro->val;
|
||||
macroDragChar=false;
|
||||
macroDragLineMode=false;
|
||||
macroDragLineInitial=ImVec2(0,0);
|
||||
lastMacroDesc=i;
|
||||
processDrags(ImGui::GetMousePos().x,ImGui::GetMousePos().y);
|
||||
}
|
||||
}
|
||||
|
||||
// loop area
|
||||
PlotCustom("##IMacroLoop",loopIndicator,totalFit,macroDragScroll,NULL,0,2,ImVec2(availableWidth,12.0f*dpiScale),sizeof(float),i.color,i.macro->len-macroDragScroll,¯oHoverLoop);
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) {
|
||||
|
|
@ -1383,18 +1479,18 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
}
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
if (ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) {
|
||||
i.macro->rel=-1;
|
||||
i.macro->rel=255;
|
||||
} else {
|
||||
i.macro->loop=-1;
|
||||
i.macro->loop=255;
|
||||
}
|
||||
}
|
||||
ImGui::SetNextItemWidth(availableWidth);
|
||||
String& mmlStr=mmlString[index];
|
||||
if (ImGui::InputText("##IMacroMML",&mmlStr)) {
|
||||
decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel);
|
||||
decodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.min,(i.isBitfield)?((1<<(i.isBitfield?i.max:0))-1):i.max,i.macro->rel,i.bit30);
|
||||
}
|
||||
if (!ImGui::IsItemActive()) {
|
||||
encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel);
|
||||
encodeMMLStr(mmlStr,i.macro->val,i.macro->len,i.macro->loop,i.macro->rel,false,i.bit30);
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
|
|
@ -1406,9 +1502,9 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(availableWidth);
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,128-totalFit,"")) {
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) {
|
||||
if (macroDragScroll<0) macroDragScroll=0;
|
||||
if (macroDragScroll>128-totalFit) macroDragScroll=128-totalFit;
|
||||
if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit;
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
|
@ -3002,24 +3098,60 @@ void FurnaceGUI::drawInsEdit() {
|
|||
P(ImGui::Checkbox("Initialize envelope on every note",&ins->gb.alwaysInit));
|
||||
|
||||
ImGui::BeginDisabled(ins->gb.softEnv);
|
||||
P(CWSliderScalar("Volume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
P(CWSliderScalar("Envelope Length",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN)); rightClickable
|
||||
P(CWSliderScalar("Sound Length",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d")); rightClickable
|
||||
ImGui::Text("Envelope Direction:");
|
||||
if (ImGui::BeginTable("GBParams",2)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.6f);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.4f);
|
||||
|
||||
bool goesUp=ins->gb.envDir;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Up",goesUp)) { PARAMETER
|
||||
goesUp=true;
|
||||
ins->gb.envDir=goesUp;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Down",!goesUp)) { PARAMETER
|
||||
goesUp=false;
|
||||
ins->gb.envDir=goesUp;
|
||||
}
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::BeginTable("GBParamsI",2)) {
|
||||
ImGui::TableSetupColumn("ci0",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("ci1",ImGuiTableColumnFlags_WidthStretch);
|
||||
|
||||
drawGBEnv(ins->gb.envVol,ins->gb.envLen,ins->gb.soundLen,ins->gb.envDir,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale));
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Volume");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(CWSliderScalar("##GBVolume",ImGuiDataType_U8,&ins->gb.envVol,&_ZERO,&_FIFTEEN)); rightClickable
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Length");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(CWSliderScalar("##GBEnvLen",ImGuiDataType_U8,&ins->gb.envLen,&_ZERO,&_SEVEN)); rightClickable
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Sound Length");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
P(CWSliderScalar("##GBSoundLen",ImGuiDataType_U8,&ins->gb.soundLen,&_ZERO,&_SIXTY_FOUR,ins->gb.soundLen>63?"Infinity":"%d")); rightClickable
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Direction");
|
||||
ImGui::TableNextColumn();
|
||||
bool goesUp=ins->gb.envDir;
|
||||
if (ImGui::RadioButton("Up",goesUp)) { PARAMETER
|
||||
goesUp=true;
|
||||
ins->gb.envDir=goesUp;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::RadioButton("Down",!goesUp)) { PARAMETER
|
||||
goesUp=false;
|
||||
ins->gb.envDir=goesUp;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
drawGBEnv(ins->gb.envVol,ins->gb.envLen,ins->gb.soundLen,ins->gb.envDir,ImVec2(ImGui::GetContentRegionAvail().x,100.0f*dpiScale));
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
if (ImGui::BeginChild("HWSeq",ImGui::GetContentRegionAvail(),true,ImGuiWindowFlags_MenuBar)) {
|
||||
ImGui::BeginMenuBar();
|
||||
|
|
@ -3175,13 +3307,13 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ImGui::Button(ICON_FA_CHEVRON_DOWN "##HWCmdDown")) {
|
||||
if (i<ins->gb.hwSeqLen-1) {
|
||||
e->lockEngine([ins,i]() {
|
||||
ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd;
|
||||
ins->gb.hwSeq[i].cmd^=ins->gb.hwSeq[i-1].cmd;
|
||||
ins->gb.hwSeq[i-1].cmd^=ins->gb.hwSeq[i].cmd;
|
||||
ins->gb.hwSeq[i+1].cmd^=ins->gb.hwSeq[i].cmd;
|
||||
ins->gb.hwSeq[i].cmd^=ins->gb.hwSeq[i+1].cmd;
|
||||
ins->gb.hwSeq[i+1].cmd^=ins->gb.hwSeq[i].cmd;
|
||||
|
||||
ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data;
|
||||
ins->gb.hwSeq[i].data^=ins->gb.hwSeq[i-1].data;
|
||||
ins->gb.hwSeq[i-1].data^=ins->gb.hwSeq[i].data;
|
||||
ins->gb.hwSeq[i+1].data^=ins->gb.hwSeq[i].data;
|
||||
ins->gb.hwSeq[i].data^=ins->gb.hwSeq[i+1].data;
|
||||
ins->gb.hwSeq[i+1].data^=ins->gb.hwSeq[i].data;
|
||||
});
|
||||
}
|
||||
MARK_MODIFIED;
|
||||
|
|
@ -3206,7 +3338,6 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ins->gb.hwSeqLen++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::EndDisabled();
|
||||
|
|
@ -4166,7 +4297,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (volMax>0) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(volumeLabel,&ins->std.volMacro,volMin,volMax,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
|
||||
}
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroAbsoluteMode,ins->std.arpMacro.mode?(¯oHoverNote):NULL));
|
||||
macroList.push_back(FurnaceGUIMacroDesc("Arpeggio",&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,NULL,false,NULL,0,true));
|
||||
if (dutyMax>0) {
|
||||
if (ins->type==DIV_INS_MIKEY) {
|
||||
macroList.push_back(FurnaceGUIMacroDesc(dutyLabel,&ins->std.dutyMacro,0,dutyMax,160,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true,mikeyFeedbackBits));
|
||||
|
|
@ -4342,8 +4473,8 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("clear")) {
|
||||
lastMacroDesc.macro->len=0;
|
||||
lastMacroDesc.macro->loop=-1;
|
||||
lastMacroDesc.macro->rel=-1;
|
||||
lastMacroDesc.macro->loop=255;
|
||||
lastMacroDesc.macro->rel=255;
|
||||
for (int i=0; i<256; i++) {
|
||||
lastMacroDesc.macro->val[i]=0;
|
||||
}
|
||||
|
|
@ -4372,15 +4503,15 @@ void FurnaceGUI::drawInsEdit() {
|
|||
lastMacroDesc.macro->val[i]=val;
|
||||
}
|
||||
|
||||
if (lastMacroDesc.macro->loop>=0 && lastMacroDesc.macro->loop<lastMacroDesc.macro->len) {
|
||||
if (lastMacroDesc.macro->loop<lastMacroDesc.macro->len) {
|
||||
lastMacroDesc.macro->loop+=macroOffX;
|
||||
} else {
|
||||
lastMacroDesc.macro->loop=-1;
|
||||
lastMacroDesc.macro->loop=255;
|
||||
}
|
||||
if ((lastMacroDesc.macro->rel+macroOffX)>=0 && (lastMacroDesc.macro->rel+macroOffX)<lastMacroDesc.macro->len) {
|
||||
lastMacroDesc.macro->rel+=macroOffX;
|
||||
} else {
|
||||
lastMacroDesc.macro->rel=-1;
|
||||
lastMacroDesc.macro->rel=255;
|
||||
}
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@
|
|||
*/
|
||||
|
||||
#include "gui.h"
|
||||
#include <imgui.h>
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
#include <algorithm>
|
||||
|
||||
void FurnaceGUI::drawNewSong() {
|
||||
bool accepted=false;
|
||||
|
|
@ -32,35 +33,76 @@ void FurnaceGUI::drawNewSong() {
|
|||
avail.y-=ImGui::GetFrameHeightWithSpacing();
|
||||
|
||||
if (ImGui::BeginChild("sysPickerC",avail,false,ImGuiWindowFlags_NoScrollWithMouse|ImGuiWindowFlags_NoScrollbar)) {
|
||||
if (ImGui::BeginTable("sysPicker",2,ImGuiTableFlags_BordersInnerV)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0f);
|
||||
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,b.name)<0;
|
||||
});
|
||||
auto lastItem=std::unique(newSongSearchResults.begin(),newSongSearchResults.end(),[](const FurnaceGUISysDef& a, const FurnaceGUISysDef& b) {
|
||||
return strcmp(a.name,b.name)==0;
|
||||
});
|
||||
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);
|
||||
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Categories");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Systems");
|
||||
if (newSongQuery.empty()) {
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Categories");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Systems");
|
||||
}
|
||||
|
||||
ImGui::TableNextRow();
|
||||
|
||||
// CATEGORIES
|
||||
ImGui::TableNextColumn();
|
||||
int index=0;
|
||||
for (FurnaceGUISysCategory& i: sysCategories) {
|
||||
if (ImGui::Selectable(i.name,newSongCategory==index,ImGuiSelectableFlags_DontClosePopups)) { \
|
||||
newSongCategory=index;
|
||||
if (newSongQuery.empty()) {
|
||||
ImGui::TableNextColumn();
|
||||
int index=0;
|
||||
for (FurnaceGUISysCategory& i: sysCategories) {
|
||||
if (ImGui::Selectable(i.name,newSongCategory==index,ImGuiSelectableFlags_DontClosePopups)) { \
|
||||
newSongCategory=index;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s",i.description);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s",i.description);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
// SYSTEMS
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::BeginTable("Systems",1,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollY)) {
|
||||
for (FurnaceGUISysDef& i: sysCategories[newSongCategory].systems) {
|
||||
std::vector<FurnaceGUISysDef>& category=(newSongQuery.empty())?(sysCategories[newSongCategory].systems):(newSongSearchResults);
|
||||
for (FurnaceGUISysDef& i: category) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) {
|
||||
|
|
|
|||
113
src/gui/patManager.cpp
Normal file
113
src/gui/patManager.cpp
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 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 "IconsFontAwesome4.h"
|
||||
#include <imgui.h>
|
||||
|
||||
void FurnaceGUI::drawPatManager() {
|
||||
if (nextWindow==GUI_WINDOW_PAT_MANAGER) {
|
||||
patManagerOpen=true;
|
||||
ImGui::SetNextWindowFocus();
|
||||
nextWindow=GUI_WINDOW_NOTHING;
|
||||
}
|
||||
if (!patManagerOpen) return;
|
||||
char id[1024];
|
||||
unsigned char isUsed[256];
|
||||
bool isNull[256];
|
||||
if (ImGui::Begin("Pattern Manager",&patManagerOpen,globalWinFlags)) {
|
||||
ImGui::Text("Global Tasks");
|
||||
|
||||
if (ImGui::Button("De-duplicate patterns")) {
|
||||
e->lockEngine([this]() {
|
||||
e->curSubSong->optimizePatterns();
|
||||
});
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Re-arrange patterns")) {
|
||||
e->lockEngine([this]() {
|
||||
e->curSubSong->rearrangePatterns();
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::BeginTable("PatManTable",257,ImGuiTableFlags_ScrollX|ImGuiTableFlags_SizingFixedFit)) {
|
||||
ImGui::PushFont(patFont);
|
||||
|
||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||
ImGui::TableNextRow();
|
||||
memset(isUsed,0,256);
|
||||
memset(isNull,0,256*sizeof(bool));
|
||||
for (int j=0; j<e->curSubSong->ordersLen; j++) {
|
||||
isUsed[e->curSubSong->orders.ord[i][j]]++;
|
||||
}
|
||||
for (int j=0; j<256; j++) {
|
||||
isNull[j]=(e->curSubSong->pat[i].data[j]==NULL);
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",e->getChannelShortName(i));
|
||||
|
||||
ImGui::PushID(1000+i);
|
||||
for (int k=0; k<256; k++) {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
snprintf(id,1023,"%.2X",k);
|
||||
if (isNull[k]) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_NULL]);
|
||||
} else if (isUsed[k]>=e->curSubSong->ordersLen) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_COMBO_BREAKER]);
|
||||
} else if (isUsed[k]>=0.7*(double)e->curSubSong->ordersLen) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_EXTREMELY_OVERUSED]);
|
||||
} else if (isUsed[k]>=0.4*(double)e->curSubSong->ordersLen) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_OVERUSED]);
|
||||
} else if (isUsed[k]) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_USED]);
|
||||
} else {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PAT_MANAGER_UNUSED]);
|
||||
}
|
||||
ImGui::Selectable(id,isUsed[k]);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::PushFont(mainFont);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_TEXT]);
|
||||
if (isNull[k]) {
|
||||
ImGui::SetTooltip("Pattern %.2X\n- not allocated",k);
|
||||
} else {
|
||||
ImGui::SetTooltip("Pattern %.2X\n- use count: %d (%.0f%%)\n\nright-click to erase",k,isUsed[k],100.0*(double)isUsed[k]/(double)e->curSubSong->ordersLen);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopFont();
|
||||
}
|
||||
if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
|
||||
e->lockEngine([this,i,k]() {
|
||||
delete e->curSubSong->pat[i].data[k];
|
||||
e->curSubSong->pat[i].data[k]=NULL;
|
||||
});
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PopFont();
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PAT_MANAGER;
|
||||
ImGui::End();
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ void FurnaceGUI::popPartBlend() {
|
|||
|
||||
// draw a pattern row
|
||||
inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel) {
|
||||
static char id[32];
|
||||
static char id[64];
|
||||
bool selectedRow=(i>=sel1.y && i<=sel2.y && !inhibitSel);
|
||||
ImGui::TableNextRow(0,lineHeight);
|
||||
ImGui::TableNextColumn();
|
||||
|
|
@ -114,9 +114,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
ImGui::PushStyleColor(ImGuiCol_Text,rowIndexColor);
|
||||
|
||||
if (settings.patRowsBase==1) {
|
||||
snprintf(id,31," %.2X ##PR_%d",i,i);
|
||||
snprintf(id,63," %.2X ##PR_%d",i,i);
|
||||
} else {
|
||||
snprintf(id,31,"%3d ##PR_%d",i,i);
|
||||
snprintf(id,63,"%3d ##PR_%d",i,i);
|
||||
}
|
||||
ImGui::Selectable(id,false,ImGuiSelectableFlags_NoPadWithHalfSpacing,fourChars);
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) {
|
||||
|
|
@ -151,7 +151,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
bool cursorVol=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==2 && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
|
||||
// note
|
||||
sprintf(id,"%s##PN_%d_%d",noteName(pat->data[i][0],pat->data[i][1]),i,j);
|
||||
snprintf(id,63,"%.31s##PN_%d_%d",noteName(pat->data[i][0],pat->data[i][1]),i,j);
|
||||
if (pat->data[i][0]==0 && pat->data[i][1]==0) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
} else {
|
||||
|
|
@ -182,7 +182,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
// instrument
|
||||
if (pat->data[i][2]==-1) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
sprintf(id,"..##PI_%d_%d",i,j);
|
||||
snprintf(id,63,"%.31s##PI_%d_%d",emptyLabel2,i,j);
|
||||
} else {
|
||||
if (pat->data[i][2]<0 || pat->data[i][2]>=e->song.insLen) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS_ERROR]);
|
||||
|
|
@ -194,7 +194,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_INS]);
|
||||
}
|
||||
}
|
||||
sprintf(id,"%.2X##PI_%d_%d",pat->data[i][2],i,j);
|
||||
snprintf(id,63,"%.2X##PI_%d_%d",pat->data[i][2],i,j);
|
||||
}
|
||||
ImGui::SameLine(0.0f,0.0f);
|
||||
if (cursorIns) {
|
||||
|
|
@ -221,13 +221,13 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
if (e->curSubSong->chanCollapse[j]<2) {
|
||||
// volume
|
||||
if (pat->data[i][3]==-1) {
|
||||
sprintf(id,"..##PV_%d_%d",i,j);
|
||||
snprintf(id,63,"%.31s##PV_%d_%d",emptyLabel2,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
} else {
|
||||
int volColor=(pat->data[i][3]*127)/chanVolMax;
|
||||
if (volColor>127) volColor=127;
|
||||
if (volColor<0) volColor=0;
|
||||
sprintf(id,"%.2X##PV_%d_%d",pat->data[i][3],i,j);
|
||||
snprintf(id,63,"%.2X##PV_%d_%d",pat->data[i][3],i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,volColors[volColor]);
|
||||
}
|
||||
ImGui::SameLine(0.0f,0.0f);
|
||||
|
|
@ -263,15 +263,15 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
|
||||
// effect
|
||||
if (pat->data[i][index]==-1) {
|
||||
sprintf(id,"..##PE%d_%d_%d",k,i,j);
|
||||
snprintf(id,63,"%.31s##PE%d_%d_%d",emptyLabel2,k,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
} else {
|
||||
if (pat->data[i][index]>0xff) {
|
||||
sprintf(id,"??##PE%d_%d_%d",k,i,j);
|
||||
snprintf(id,63,"??##PE%d_%d_%d",k,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PATTERN_EFFECT_INVALID]);
|
||||
} else {
|
||||
const unsigned char data=pat->data[i][index];
|
||||
sprintf(id,"%.2X##PE%d_%d_%d",data,k,i,j);
|
||||
snprintf(id,63,"%.2X##PE%d_%d_%d",data,k,i,j);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,uiColors[fxColors[data]]);
|
||||
}
|
||||
}
|
||||
|
|
@ -297,9 +297,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
|
||||
// effect value
|
||||
if (pat->data[i][index+1]==-1) {
|
||||
sprintf(id,"..##PF%d_%d_%d",k,i,j);
|
||||
snprintf(id,63,"%.31s##PF%d_%d_%d",emptyLabel2,k,i,j);
|
||||
} else {
|
||||
sprintf(id,"%.2X##PF%d_%d_%d",pat->data[i][index+1],k,i,j);
|
||||
snprintf(id,63,"%.2X##PF%d_%d_%d",pat->data[i][index+1],k,i,j);
|
||||
}
|
||||
ImGui::SameLine(0.0f,0.0f);
|
||||
if (cursorEffectVal) {
|
||||
|
|
@ -701,6 +701,15 @@ void FurnaceGUI::drawPattern() {
|
|||
if (i.cmd==DIV_CMD_SAMPLE_BANK) continue;
|
||||
if (i.cmd==DIV_CMD_GET_VOLUME) continue;
|
||||
if (i.cmd==DIV_ALWAYS_SET_VOLUME) continue;
|
||||
if (i.cmd==DIV_CMD_HINT_VOLUME ||
|
||||
i.cmd==DIV_CMD_HINT_PORTA ||
|
||||
i.cmd==DIV_CMD_HINT_LEGATO ||
|
||||
i.cmd==DIV_CMD_HINT_VOL_SLIDE ||
|
||||
i.cmd==DIV_CMD_HINT_ARPEGGIO ||
|
||||
i.cmd==DIV_CMD_HINT_PITCH ||
|
||||
i.cmd==DIV_CMD_HINT_VIBRATO ||
|
||||
i.cmd==DIV_CMD_HINT_VIBRATO_RANGE ||
|
||||
i.cmd==DIV_CMD_HINT_VIBRATO_SHAPE) continue;
|
||||
|
||||
float width=patChanX[i.chan+1]-patChanX[i.chan];
|
||||
float speedX=0.0f;
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ void PlotNoLerp(const char* label, const float* values, int values_count, int va
|
|||
PlotNoLerpEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
|
||||
}
|
||||
|
||||
int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char** overlay_text, int bits, ImVec2 frame_size)
|
||||
int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx), void* data, int values_count, int values_offset, const char** overlay_text, int bits, ImVec2 frame_size, const bool* values_highlight, ImVec4 highlightColor)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
|
|
@ -253,7 +253,11 @@ int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx),
|
|||
if (pos1.y <= pos0.y - 2.0f)
|
||||
pos1.y += 1.0f;
|
||||
if (v1&(1<<o)) {
|
||||
window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base);
|
||||
ImU32 rCol=(idx_hovered == v1_idx ? col_hovered : col_base);
|
||||
if (values_highlight!=NULL) {
|
||||
if (values_highlight[v1_idx]) rCol=ImGui::GetColorU32(highlightColor);
|
||||
}
|
||||
window->DrawList->AddRectFilled(pos0, pos1, rCol);
|
||||
}
|
||||
}
|
||||
tp0 = tp1;
|
||||
|
|
@ -283,13 +287,13 @@ int PlotBitfieldEx(const char* label, int (*values_getter)(void* data, int idx),
|
|||
return idx_hovered;
|
||||
}
|
||||
|
||||
void PlotBitfield(const char* label, const int* values, int values_count, int values_offset, const char** overlay_text, int bits, ImVec2 graph_size, int stride)
|
||||
void PlotBitfield(const char* label, const int* values, int values_count, int values_offset, const char** overlay_text, int bits, ImVec2 graph_size, int stride, const bool* values_highlight, ImVec4 highlightColor)
|
||||
{
|
||||
FurnacePlotIntArrayGetterData data(values, stride);
|
||||
PlotBitfieldEx(label, &Plot_IntArrayGetter, (void*)&data, values_count, values_offset, overlay_text, bits, graph_size);
|
||||
PlotBitfieldEx(label, &Plot_IntArrayGetter, (void*)&data, values_count, values_offset, overlay_text, bits, graph_size, values_highlight, highlightColor);
|
||||
}
|
||||
|
||||
int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_display_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float))
|
||||
int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_getter)(void* data, int idx), void* data, int values_count, int values_display_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 frame_size, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float), const bool* values_highlight, ImVec4 highlightColor)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
|
|
@ -413,7 +417,11 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett
|
|||
pos0.y-=(inner_bb.Max.y-inner_bb.Min.y)*inv_scale;
|
||||
//pos1.y+=1.0f;
|
||||
}
|
||||
window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base);
|
||||
ImU32 rCol=(idx_hovered == v1_idx ? col_hovered : col_base);
|
||||
if (values_highlight!=NULL) {
|
||||
if (values_highlight[v1_idx]) rCol=ImGui::GetColorU32(highlightColor);
|
||||
}
|
||||
window->DrawList->AddRectFilled(pos0, pos1, rCol);
|
||||
}
|
||||
|
||||
t0 = t1;
|
||||
|
|
@ -451,8 +459,8 @@ int PlotCustomEx(ImGuiPlotType plot_type, const char* label, float (*values_gett
|
|||
return idx_hovered;
|
||||
}
|
||||
|
||||
void PlotCustom(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float))
|
||||
void PlotCustom(const char* label, const float* values, int values_count, int values_offset, const char* overlay_text, float scale_min, float scale_max, ImVec2 graph_size, int stride, ImVec4 color, int highlight, std::string (*hoverFunc)(int,float), bool blockMode, std::string (*guideFunc)(float), const bool* values_highlight, ImVec4 highlightColor)
|
||||
{
|
||||
FurnacePlotArrayGetterData data(values, stride);
|
||||
PlotCustomEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, color, highlight, hoverFunc, blockMode, guideFunc);
|
||||
PlotCustomEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size, color, highlight, hoverFunc, blockMode, guideFunc, values_highlight, highlightColor);
|
||||
}
|
||||
|
|
@ -21,5 +21,5 @@
|
|||
#include <string>
|
||||
|
||||
void PlotNoLerp(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
|
||||
void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float));
|
||||
void PlotCustom(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), ImVec4 fgColor = ImVec4(1.0f,1.0f,1.0f,1.0f), int highlight = 0, std::string (*hoverFunc)(int,float) = NULL, bool blockMode=false, std::string (*guideFunc)(float) = NULL);
|
||||
void PlotBitfield(const char* label, const int* values, int values_count, int values_offset = 0, const char** overlay_text = NULL, int bits = 8, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f));
|
||||
void PlotCustom(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float), ImVec4 fgColor = ImVec4(1.0f,1.0f,1.0f,1.0f), int highlight = 0, std::string (*hoverFunc)(int,float) = NULL, bool blockMode=false, std::string (*guideFunc)(float) = NULL, const bool* values_highlight = NULL, ImVec4 highlightColor = ImVec4(1.0f,1.0f,1.0f,1.0f));
|
||||
|
|
@ -854,6 +854,41 @@ void FurnaceGUI::initSystemPresets() {
|
|||
0
|
||||
}
|
||||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"MSX + Neotron", {
|
||||
DIV_SYSTEM_AY8910, 64, 0, 16,
|
||||
DIV_SYSTEM_YM2610_FULL, 64, 0, 0,
|
||||
0
|
||||
}
|
||||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"MSX + Neotron (extended channel 2)", {
|
||||
DIV_SYSTEM_AY8910, 64, 0, 16,
|
||||
DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0,
|
||||
0
|
||||
}
|
||||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"MSX + Neotron (with YM2610B)", {
|
||||
DIV_SYSTEM_AY8910, 64, 0, 16,
|
||||
DIV_SYSTEM_YM2610B, 64, 0, 0,
|
||||
0
|
||||
}
|
||||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"MSX + Neotron (with YM2610B; extended channel 3)", {
|
||||
DIV_SYSTEM_AY8910, 64, 0, 16,
|
||||
DIV_SYSTEM_YM2610B_EXT, 64, 0, 0,
|
||||
0
|
||||
}
|
||||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"MSX + SIMPL", {
|
||||
DIV_SYSTEM_AY8910, 64, 0, 16,
|
||||
DIV_SYSTEM_PCM_DAC, 64, 0, 55929|(7<<16), // variable rate, Mono DAC
|
||||
0
|
||||
}
|
||||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"NEC PC-98 (with PC-9801-26/K)", {
|
||||
DIV_SYSTEM_OPN, 64, 0, 4, // 3.9936MHz but some compatible card has 4MHz
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include "fonts.h"
|
||||
#include "../ta-log.h"
|
||||
#include "../fileutils.h"
|
||||
#include "../utfutils.h"
|
||||
#include "util.h"
|
||||
#include "guiConst.h"
|
||||
#include "intConst.h"
|
||||
|
|
@ -513,6 +514,11 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.blankIns=blankInsB;
|
||||
}
|
||||
|
||||
bool saveUnusedPatternsB=settings.saveUnusedPatterns;
|
||||
if (ImGui::Checkbox("Save unused patterns",&saveUnusedPatternsB)) {
|
||||
settings.saveUnusedPatterns=saveUnusedPatternsB;
|
||||
}
|
||||
|
||||
ImGui::Text("Note preview behavior:");
|
||||
if (ImGui::RadioButton("Never##npb0",settings.notePreviewBehavior==0)) {
|
||||
settings.notePreviewBehavior=0;
|
||||
|
|
@ -1079,6 +1085,41 @@ void FurnaceGUI::drawSettings() {
|
|||
);
|
||||
}
|
||||
|
||||
bool loadChineseTraditionalB=settings.loadChineseTraditional;
|
||||
if (ImGui::Checkbox("Display Chinese (Traditional) characters",&loadChineseTraditionalB)) {
|
||||
settings.loadChineseTraditional=loadChineseTraditionalB;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Only toggle this option if you have enough graphics memory.\n"
|
||||
"This is a temporary solution until dynamic font atlas is implemented in Dear ImGui.\n\n"
|
||||
"請在確保你有足夠的顯存后再啟動此設定\n"
|
||||
"這是一個在ImGui實現動態字體加載之前的臨時解決方案"
|
||||
);
|
||||
}
|
||||
|
||||
bool loadKoreanB=settings.loadKorean;
|
||||
if (ImGui::Checkbox("Display Korean characters",&loadKoreanB)) {
|
||||
settings.loadKorean=loadKoreanB;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(
|
||||
"Only toggle this option if you have enough graphics memory.\n"
|
||||
"This is a temporary solution until dynamic font atlas is implemented in Dear ImGui.\n\n"
|
||||
"그래픽 메모리가 충분한 경우에만 이 옵션을 선택하십시오.\n"
|
||||
"이 옵션은 Dear ImGui에 동적 글꼴 아틀라스가 구현될 때까지 임시 솔루션입니다."
|
||||
);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Pattern view labels:");
|
||||
ImGui::InputTextWithHint("Note off (3-char)","OFF",&settings.noteOffLabel);
|
||||
ImGui::InputTextWithHint("Note release (3-char)","===",&settings.noteRelLabel);
|
||||
ImGui::InputTextWithHint("Macro release (3-char)","REL",&settings.macroRelLabel);
|
||||
ImGui::InputTextWithHint("Empty field (3-char)","...",&settings.emptyLabel);
|
||||
ImGui::InputTextWithHint("Empty field (2-char)","..",&settings.emptyLabel2);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Orders row number format:");
|
||||
|
|
@ -1207,6 +1248,79 @@ void FurnaceGUI::drawSettings() {
|
|||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Channel colors:");
|
||||
if (ImGui::RadioButton("Single##CHC0",settings.channelColors==0)) {
|
||||
settings.channelColors=0;
|
||||
}
|
||||
if (ImGui::RadioButton("Channel type##CHC1",settings.channelColors==1)) {
|
||||
settings.channelColors=1;
|
||||
}
|
||||
if (ImGui::RadioButton("Instrument type##CHC2",settings.channelColors==2)) {
|
||||
settings.channelColors=2;
|
||||
}
|
||||
|
||||
ImGui::Text("Channel name colors:");
|
||||
if (ImGui::RadioButton("Single##CTC0",settings.channelColors==0)) {
|
||||
settings.channelColors=0;
|
||||
}
|
||||
if (ImGui::RadioButton("Channel type##CTC1",settings.channelColors==1)) {
|
||||
settings.channelColors=1;
|
||||
}
|
||||
if (ImGui::RadioButton("Instrument type##CTC2",settings.channelColors==2)) {
|
||||
settings.channelColors=2;
|
||||
}
|
||||
|
||||
ImGui::Text("Channel style:");
|
||||
if (ImGui::RadioButton("Classic##CHS0",settings.channelStyle==0)) {
|
||||
settings.channelStyle=0;
|
||||
}
|
||||
if (ImGui::RadioButton("Line##CHS1",settings.channelStyle==1)) {
|
||||
settings.channelStyle=1;
|
||||
}
|
||||
if (ImGui::RadioButton("Round##CHS2",settings.channelStyle==2)) {
|
||||
settings.channelStyle=2;
|
||||
}
|
||||
if (ImGui::RadioButton("Split button##CHS3",settings.channelStyle==3)) {
|
||||
settings.channelStyle=3;
|
||||
}
|
||||
if (ImGui::RadioButton("Square border##CH42",settings.channelStyle==4)) {
|
||||
settings.channelStyle=4;
|
||||
}
|
||||
if (ImGui::RadioButton("Round border##CHS5",settings.channelStyle==5)) {
|
||||
settings.channelStyle=5;
|
||||
}
|
||||
|
||||
ImGui::Text("Channel volume bar:");
|
||||
if (ImGui::RadioButton("None##CHV0",settings.channelVolStyle==0)) {
|
||||
settings.channelVolStyle=0;
|
||||
}
|
||||
if (ImGui::RadioButton("Simple##CHV1",settings.channelVolStyle==1)) {
|
||||
settings.channelVolStyle=1;
|
||||
}
|
||||
if (ImGui::RadioButton("Stereo##CHV2",settings.channelVolStyle==2)) {
|
||||
settings.channelVolStyle=2;
|
||||
}
|
||||
if (ImGui::RadioButton("Real##CHV3",settings.channelVolStyle==3)) {
|
||||
settings.channelVolStyle=3;
|
||||
}
|
||||
|
||||
ImGui::Text("Channel feedback style:");
|
||||
|
||||
if (ImGui::RadioButton("Off##CHF0",settings.channelFeedbackStyle==0)) {
|
||||
settings.channelFeedbackStyle=0;
|
||||
}
|
||||
if (ImGui::RadioButton("Note##CHF1",settings.channelFeedbackStyle==1)) {
|
||||
settings.channelFeedbackStyle=1;
|
||||
}
|
||||
if (ImGui::RadioButton("Volume##CHF2",settings.channelFeedbackStyle==2)) {
|
||||
settings.channelFeedbackStyle=2;
|
||||
}
|
||||
if (ImGui::RadioButton("Active##CHF3",settings.channelFeedbackStyle==3)) {
|
||||
settings.channelFeedbackStyle=3;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
bool insEditColorizeB=settings.insEditColorize;
|
||||
if (ImGui::Checkbox("Colorize instrument editor using instrument type",&insEditColorizeB)) {
|
||||
settings.insEditColorize=insEditColorizeB;
|
||||
|
|
@ -1577,6 +1691,15 @@ void FurnaceGUI::drawSettings() {
|
|||
UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Pattern Manager")) {
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_NULL,"Unallocated");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_UNUSED,"Unused");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_USED,"Used");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_OVERUSED,"Overused");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_EXTREMELY_OVERUSED,"Really overused");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PAT_MANAGER_COMBO_BREAKER,"Combo Breaker");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
if (ImGui::TreeNode("Piano")) {
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PIANO_BACKGROUND,"Background");
|
||||
UI_COLOR_CONFIG(GUI_COLOR_PIANO_KEY_TOP,"Upper key");
|
||||
|
|
@ -2083,6 +2206,8 @@ void FurnaceGUI::syncSettings() {
|
|||
settings.roundedMenus=e->getConfInt("roundedMenus",0);
|
||||
settings.loadJapanese=e->getConfInt("loadJapanese",0);
|
||||
settings.loadChinese=e->getConfInt("loadChinese",0);
|
||||
settings.loadChineseTraditional=e->getConfInt("loadChineseTraditional",0);
|
||||
settings.loadKorean=e->getConfInt("loadKorean",0);
|
||||
settings.fmLayout=e->getConfInt("fmLayout",0);
|
||||
settings.sampleLayout=e->getConfInt("sampleLayout",0);
|
||||
settings.waveLayout=e->getConfInt("waveLayout",0);
|
||||
|
|
@ -2127,6 +2252,17 @@ void FurnaceGUI::syncSettings() {
|
|||
settings.noThreadedInput=e->getConfInt("noThreadedInput",0);
|
||||
settings.initialSysName=e->getConfString("initialSysName","");
|
||||
settings.clampSamples=e->getConfInt("clampSamples",0);
|
||||
settings.noteOffLabel=e->getConfString("noteOffLabel","OFF");
|
||||
settings.noteRelLabel=e->getConfString("noteRelLabel","===");
|
||||
settings.macroRelLabel=e->getConfString("macroRelLabel","REL");
|
||||
settings.emptyLabel=e->getConfString("emptyLabel","...");
|
||||
settings.emptyLabel2=e->getConfString("emptyLabel2","..");
|
||||
settings.saveUnusedPatterns=e->getConfInt("saveUnusedPatterns",0);
|
||||
settings.channelColors=e->getConfInt("channelColors",1);
|
||||
settings.channelTextColors=e->getConfInt("channelTextColors",0);
|
||||
settings.channelStyle=e->getConfInt("channelStyle",0);
|
||||
settings.channelVolStyle=e->getConfInt("channelVolStyle",0);
|
||||
settings.channelFeedbackStyle=e->getConfInt("channelFeedbackStyle",1);
|
||||
|
||||
clampSetting(settings.mainFontSize,2,96);
|
||||
clampSetting(settings.patFontSize,2,96);
|
||||
|
|
@ -2176,6 +2312,8 @@ void FurnaceGUI::syncSettings() {
|
|||
clampSetting(settings.roundedMenus,0,1);
|
||||
clampSetting(settings.loadJapanese,0,1);
|
||||
clampSetting(settings.loadChinese,0,1);
|
||||
clampSetting(settings.loadChineseTraditional,0,1);
|
||||
clampSetting(settings.loadKorean,0,1);
|
||||
clampSetting(settings.fmLayout,0,6);
|
||||
clampSetting(settings.susPosition,0,1);
|
||||
clampSetting(settings.effectCursorDir,0,2);
|
||||
|
|
@ -2215,6 +2353,12 @@ void FurnaceGUI::syncSettings() {
|
|||
clampSetting(settings.unsignedDetune,0,1);
|
||||
clampSetting(settings.noThreadedInput,0,1);
|
||||
clampSetting(settings.clampSamples,0,1);
|
||||
clampSetting(settings.saveUnusedPatterns,0,1);
|
||||
clampSetting(settings.channelColors,0,2);
|
||||
clampSetting(settings.channelTextColors,0,2);
|
||||
clampSetting(settings.channelStyle,0,5);
|
||||
clampSetting(settings.channelVolStyle,0,3);
|
||||
clampSetting(settings.channelFeedbackStyle,0,3);
|
||||
|
||||
settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys",""));
|
||||
if (settings.initialSys.size()<4) {
|
||||
|
|
@ -2309,6 +2453,8 @@ void FurnaceGUI::commitSettings() {
|
|||
e->setConf("roundedMenus",settings.roundedMenus);
|
||||
e->setConf("loadJapanese",settings.loadJapanese);
|
||||
e->setConf("loadChinese",settings.loadChinese);
|
||||
e->setConf("loadChineseTraditional",settings.loadChineseTraditional);
|
||||
e->setConf("loadKorean",settings.loadKorean);
|
||||
e->setConf("fmLayout",settings.fmLayout);
|
||||
e->setConf("sampleLayout",settings.sampleLayout);
|
||||
e->setConf("waveLayout",settings.waveLayout);
|
||||
|
|
@ -2354,6 +2500,17 @@ void FurnaceGUI::commitSettings() {
|
|||
e->setConf("unsignedDetune",settings.unsignedDetune);
|
||||
e->setConf("noThreadedInput",settings.noThreadedInput);
|
||||
e->setConf("clampSamples",settings.clampSamples);
|
||||
e->setConf("noteOffLabel",settings.noteOffLabel);
|
||||
e->setConf("noteRelLabel",settings.noteRelLabel);
|
||||
e->setConf("macroRelLabel",settings.macroRelLabel);
|
||||
e->setConf("emptyLabel",settings.emptyLabel);
|
||||
e->setConf("emptyLabel2",settings.emptyLabel2);
|
||||
e->setConf("saveUnusedPatterns",settings.saveUnusedPatterns);
|
||||
e->setConf("channelColors",settings.channelColors);
|
||||
e->setConf("channelTextColors",settings.channelTextColors);
|
||||
e->setConf("channelStyle",settings.channelStyle);
|
||||
e->setConf("channelVolStyle",settings.channelVolStyle);
|
||||
e->setConf("channelFeedbackStyle",settings.channelFeedbackStyle);
|
||||
|
||||
// colors
|
||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||
|
|
@ -2766,6 +2923,20 @@ void FurnaceGUI::popAccentColors() {
|
|||
#define SYSTEM_PAT_FONT_PATH_3 "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf"
|
||||
#endif
|
||||
|
||||
void setupLabel(const char* lStr, char* label, int len) {
|
||||
memset(label,0,32);
|
||||
for (int i=0, p=0; i<len; i++) {
|
||||
signed char cl;
|
||||
if (lStr[p]==0) {
|
||||
strncat(label," ",32);
|
||||
} else {
|
||||
decodeUTF8((const unsigned char*)&lStr[p],cl);
|
||||
memcpy(label+p,lStr+p,cl);
|
||||
p+=cl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::applyUISettings(bool updateFonts) {
|
||||
ImGuiStyle sty;
|
||||
if (settings.guiColorsBase) {
|
||||
|
|
@ -2774,6 +2945,12 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
ImGui::StyleColorsDark(&sty);
|
||||
}
|
||||
|
||||
setupLabel(settings.noteOffLabel.c_str(),noteOffLabel,3);
|
||||
setupLabel(settings.noteRelLabel.c_str(),noteRelLabel,3);
|
||||
setupLabel(settings.macroRelLabel.c_str(),macroRelLabel,3);
|
||||
setupLabel(settings.emptyLabel.c_str(),emptyLabel,3);
|
||||
setupLabel(settings.emptyLabel2.c_str(),emptyLabel2,2);
|
||||
|
||||
if (settings.dpiScale>=0.5f) dpiScale=settings.dpiScale;
|
||||
|
||||
// colors
|
||||
|
|
@ -2928,6 +3105,12 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
if (settings.loadChinese) {
|
||||
range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon());
|
||||
}
|
||||
if (settings.loadChineseTraditional) {
|
||||
range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesChineseFull());
|
||||
}
|
||||
if (settings.loadKorean) {
|
||||
range.AddRanges(ImGui::GetIO().Fonts->GetGlyphRangesKorean());
|
||||
}
|
||||
// I'm terribly sorry
|
||||
range.UsedChars[0x80>>5]=0;
|
||||
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ void FurnaceGUI::drawSongInfo() {
|
|||
float setHz=tempoView?e->curSubSong->hz*2.5:e->curSubSong->hz;
|
||||
if (ImGui::InputFloat("##Rate",&setHz,1.0f,1.0f,"%g")) { MARK_MODIFIED
|
||||
if (tempoView) setHz/=2.5;
|
||||
if (setHz<10) setHz=10;
|
||||
if (setHz<1) setHz=1;
|
||||
if (setHz>999) setHz=999;
|
||||
e->setSongRate(setHz,setHz<52);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,13 +135,20 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool
|
|||
if (ImGui::RadioButton("5.95MHz (PAL)",(flags&3)==1)) {
|
||||
copyOfFlags=(flags&(~3))|1;
|
||||
}
|
||||
ImGui::Text("Chip revision (sample memory):");
|
||||
if (ImGui::RadioButton("A/B/E (8K)",(flags&16)==0)) {
|
||||
ImGui::Text("Sample memory:");
|
||||
if (ImGui::RadioButton("8K (rev A/B/E)",(flags&16)==0)) {
|
||||
copyOfFlags=(flags&(~16))|0;
|
||||
}
|
||||
if (ImGui::RadioButton("D/F (64K)",(flags&16)==16)) {
|
||||
if (ImGui::RadioButton("64K (rev D/F)",(flags&16)==16)) {
|
||||
copyOfFlags=(flags&(~16))|16;
|
||||
}
|
||||
ImGui::Text("DAC resolution");
|
||||
if (ImGui::RadioButton("16-bit (rev A/B/D/F)",(flags&32)==0)) {
|
||||
copyOfFlags=(flags&(~32))|0;
|
||||
}
|
||||
if (ImGui::RadioButton("1-bit PDM (rev C/E)",(flags&32)==32)) {
|
||||
copyOfFlags=(flags&(~32))|32;
|
||||
}
|
||||
bool echo=flags&4;
|
||||
if (ImGui::Checkbox("Enable echo",&echo)) {
|
||||
copyOfFlags=(flags&(~4))|(echo<<2);
|
||||
|
|
|
|||
124
src/gui/sysManager.cpp
Normal file
124
src/gui/sysManager.cpp
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 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 "IconsFontAwesome4.h"
|
||||
#include <fmt/printf.h>
|
||||
#include <imgui.h>
|
||||
|
||||
void FurnaceGUI::drawSysManager() {
|
||||
if (nextWindow==GUI_WINDOW_SYS_MANAGER) {
|
||||
sysManagerOpen=true;
|
||||
ImGui::SetNextWindowFocus();
|
||||
nextWindow=GUI_WINDOW_NOTHING;
|
||||
}
|
||||
if (!sysManagerOpen) return;
|
||||
if (ImGui::Begin("Chip Manager",&sysManagerOpen,globalWinFlags)) {
|
||||
ImGui::Checkbox("Preserve channel order",&preserveChanPos);
|
||||
if (ImGui::BeginTable("SystemList",3)) {
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed);
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Name");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("Actions");
|
||||
for (unsigned char i=0; i<e->song.systemLen; i++) {
|
||||
ImGui::PushID(i);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Button(ICON_FA_ARROWS)) {
|
||||
}
|
||||
if (ImGui::BeginDragDropSource()) {
|
||||
sysToMove=i;
|
||||
ImGui::SetDragDropPayload("FUR_SYS",NULL,0,ImGuiCond_Once);
|
||||
ImGui::Button(ICON_FA_ARROWS "##SysDrag");
|
||||
ImGui::EndDragDropSource();
|
||||
} else if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("(drag to swap chips)");
|
||||
}
|
||||
if (ImGui::BeginDragDropTarget()) {
|
||||
const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_SYS");
|
||||
if (dragItem!=NULL) {
|
||||
if (dragItem->IsDataType("FUR_SYS")) {
|
||||
if (sysToMove!=i && sysToMove>=0) {
|
||||
e->swapSystem(sysToMove,i,preserveChanPos);
|
||||
}
|
||||
sysToMove=-1;
|
||||
}
|
||||
}
|
||||
ImGui::EndDragDropTarget();
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSM%d",i+1,getSystemName(e->song.system[i]),i).c_str())) {
|
||||
drawSysConf(i,e->song.system[i],e->song.systemFlags[i],true);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Button(ICON_FA_CHEVRON_DOWN "##SysChange");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Change");
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("SysPickerC",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
DivSystem picked=systemPicker();
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
e->changeSystem(i,picked,preserveChanPos);
|
||||
updateWindowTitle();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(e->song.systemLen<=1);
|
||||
if (ImGui::Button(ICON_FA_TIMES "##SysRemove")) {
|
||||
sysToDelete=i;
|
||||
showWarning("Are you sure you want to remove this chip?",GUI_WARN_SYSTEM_DEL);
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Remove");
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::PopID();
|
||||
}
|
||||
if (e->song.systemLen<32) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Button(ICON_FA_PLUS "##SysAdd");
|
||||
if (ImGui::BeginPopupContextItem("SysPickerA",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
DivSystem picked=systemPicker();
|
||||
if (picked!=DIV_SYSTEM_NULL) {
|
||||
if (!e->addSystem(picked)) {
|
||||
showError("cannot add chip! ("+e->getLastError()+")");
|
||||
}
|
||||
updateWindowTitle();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SYS_MANAGER;
|
||||
ImGui::End();
|
||||
}
|
||||
97
src/gui/sysPicker.cpp
Normal file
97
src/gui/sysPicker.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* Furnace Tracker - multi-system chiptune tracker
|
||||
* Copyright (C) 2021-2022 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 "IconsFontAwesome4.h"
|
||||
#include "guiConst.h"
|
||||
#include <imgui.h>
|
||||
|
||||
DivSystem FurnaceGUI::systemPicker() {
|
||||
DivSystem ret=DIV_SYSTEM_NULL;
|
||||
DivSystem hoveredSys=DIV_SYSTEM_NULL;
|
||||
bool reissueSearch=false;
|
||||
if (curSysSection==NULL) {
|
||||
curSysSection=availableSystems;
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputTextWithHint("##SysSearch","Search...",&sysSearchQuery)) reissueSearch=true;
|
||||
if (ImGui::BeginTabBar("SysCats")) {
|
||||
for (int i=0; chipCategories[i]; i++) {
|
||||
if (ImGui::BeginTabItem(chipCategoryNames[i])) {
|
||||
if (ImGui::IsItemActive()) {
|
||||
reissueSearch=true;
|
||||
}
|
||||
curSysSection=chipCategories[i];
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
if (reissueSearch) {
|
||||
String lowerCase=sysSearchQuery;
|
||||
for (char& i: lowerCase) {
|
||||
if (i>='A' && i<='Z') i+='a'-'A';
|
||||
}
|
||||
sysSearchResults.clear();
|
||||
for (int j=0; curSysSection[j]; j++) {
|
||||
String lowerCase1=e->getSystemName((DivSystem)curSysSection[j]);
|
||||
for (char& i: lowerCase1) {
|
||||
if (i>='A' && i<='Z') i+='a'-'A';
|
||||
}
|
||||
if (lowerCase1.find(lowerCase)!=String::npos) {
|
||||
sysSearchResults.push_back((DivSystem)curSysSection[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ImGui::BeginTable("SysList",1,ImGuiTableFlags_ScrollY,ImVec2(500.0f*dpiScale,200.0*dpiScale))) {
|
||||
if (sysSearchQuery.empty()) {
|
||||
// display chip list
|
||||
for (int j=0; curSysSection[j]; j++) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(e->getSystemName((DivSystem)curSysSection[j]),false,0,ImVec2(500.0f*dpiScale,0.0f))) ret=(DivSystem)curSysSection[j];
|
||||
if (ImGui::IsItemHovered()) {
|
||||
hoveredSys=(DivSystem)curSysSection[j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// display search results
|
||||
for (DivSystem i: sysSearchResults) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(e->getSystemName(i),false,0,ImVec2(500.0f*dpiScale,0.0f))) ret=i;
|
||||
if (ImGui::IsItemHovered()) {
|
||||
hoveredSys=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::BeginChild("SysDesc",ImVec2(0.0f,150.0f*dpiScale),false,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse)) {
|
||||
if (hoveredSys!=DIV_SYSTEM_NULL) {
|
||||
const DivSysDef* sysDef=e->getSystemDef(hoveredSys);
|
||||
ImGui::TextWrapped("%s",sysDef->description);
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -131,9 +131,8 @@ void FurnaceGUI::drawWaveEdit() {
|
|||
if (curWave>=(int)e->song.wave.size()) curWave=e->song.wave.size()-1;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
// TODO: load replace
|
||||
if (ImGui::Button(ICON_FA_FOLDER_OPEN "##WELoad")) {
|
||||
doAction(GUI_ACTION_WAVE_LIST_OPEN);
|
||||
doAction(GUI_ACTION_WAVE_LIST_OPEN_REPLACE);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_FLOPPY_O "##WESave")) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue