Merge branch 'master' of https://github.com/tildearrow/furnace
This commit is contained in:
commit
3b0df75bf6
112 changed files with 8512 additions and 634 deletions
|
|
@ -102,6 +102,7 @@ const char* aboutLine[]={
|
|||
"fd",
|
||||
"GENATARi",
|
||||
"host12prog",
|
||||
"lunathir",
|
||||
"plane",
|
||||
"TheEssem",
|
||||
"",
|
||||
|
|
@ -133,6 +134,8 @@ const char* aboutLine[]={
|
|||
"puNES (NES, MMC5 and FDS) by FHorse",
|
||||
"NSFPlay (NES and FDS) by Brad Smith and Brezza",
|
||||
"reSID by Dag Lem",
|
||||
"reSIDfp by Dag Lem, Antti Lankila",
|
||||
"and Leandro Nini",
|
||||
"Stella by Stella Team",
|
||||
"QSound emulator by superctr and Valley Bell",
|
||||
"VICE VIC-20 sound core by Rami Rasanen and viznut",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
118
src/gui/gui.cpp
118
src/gui/gui.cpp
|
|
@ -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,9 +283,10 @@ void FurnaceGUI::decodeMMLStrW(String& source, int* macro, int& macroLen, int ma
|
|||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::decodeMMLStr(String& source, int* macro, unsigned char& macroLen, unsigned char& macroLoop, int macroMin, int macroMax, unsigned 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=255;
|
||||
|
|
@ -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,6 +330,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;
|
||||
}
|
||||
|
|
@ -329,6 +346,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;
|
||||
}
|
||||
|
|
@ -345,6 +364,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;
|
||||
}
|
||||
|
|
@ -1572,6 +1593,7 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
int FurnaceGUI::save(String path, int dmfVersion) {
|
||||
SafeWriter* w;
|
||||
if (dmfVersion) {
|
||||
if (dmfVersion<24) dmfVersion=24;
|
||||
w=e->saveDMF(dmfVersion);
|
||||
} else {
|
||||
w=e->saveFur();
|
||||
|
|
@ -1758,8 +1780,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; \
|
||||
|
|
@ -1790,25 +1839,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); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
|
@ -1893,20 +1942,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) { \
|
||||
|
|
@ -3057,9 +3092,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();
|
||||
}
|
||||
|
|
@ -3076,9 +3115,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();
|
||||
}
|
||||
|
|
@ -4167,6 +4208,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();
|
||||
|
|
@ -4775,6 +4826,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
drawHalt(10),
|
||||
macroPointSize(16),
|
||||
waveEditStyle(0),
|
||||
curSysSection(NULL),
|
||||
pendingRawSampleDepth(8),
|
||||
pendingRawSampleChannels(1),
|
||||
pendingRawSampleUnsigned(false),
|
||||
|
|
@ -4935,6 +4987,8 @@ FurnaceGUI::FurnaceGUI():
|
|||
macroDragInitialValueSet(false),
|
||||
macroDragInitialValue(false),
|
||||
macroDragChar(false),
|
||||
macroDragBit30(false),
|
||||
macroDragSettingBit30(false),
|
||||
macroDragLineMode(false),
|
||||
macroDragMouseMoved(false),
|
||||
macroDragLineInitial(0,0),
|
||||
|
|
@ -4973,6 +5027,8 @@ FurnaceGUI::FurnaceGUI():
|
|||
eventTimeEnd(0),
|
||||
eventTimeDelta(0),
|
||||
chanToMove(-1),
|
||||
sysToMove(-1),
|
||||
sysToDelete(-1),
|
||||
transposeAmount(0),
|
||||
randomizeMin(0),
|
||||
randomizeMax(255),
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ enum FurnaceGUIWarnings {
|
|||
GUI_WARN_CLOSE_SETTINGS,
|
||||
GUI_WARN_CLEAR,
|
||||
GUI_WARN_SUBSONG_DEL,
|
||||
GUI_WARN_SYSTEM_DEL,
|
||||
GUI_WARN_GENERIC
|
||||
};
|
||||
|
||||
|
|
@ -869,10 +870,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),
|
||||
|
|
@ -882,6 +883,7 @@ struct FurnaceGUIMacroDesc {
|
|||
bitOffset(bitOff),
|
||||
isBitfield(bitfield),
|
||||
blockMode(block),
|
||||
bit30(bit30Special),
|
||||
hoverFunc(hf) {
|
||||
// MSVC -> hell
|
||||
this->min=macroMin;
|
||||
|
|
@ -967,13 +969,16 @@ 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;
|
||||
|
|
@ -983,6 +988,7 @@ class FurnaceGUI {
|
|||
int drawHalt;
|
||||
int macroPointSize;
|
||||
int waveEditStyle;
|
||||
const int* curSysSection;
|
||||
|
||||
String pendingRawSample;
|
||||
int pendingRawSampleDepth, pendingRawSampleChannels;
|
||||
|
|
@ -1045,6 +1051,7 @@ class FurnaceGUI {
|
|||
int snCore;
|
||||
int nesCore;
|
||||
int fdsCore;
|
||||
int c64Core;
|
||||
int pcSpeakerOutMethod;
|
||||
String yrw801Path;
|
||||
String tg100Path;
|
||||
|
|
@ -1087,6 +1094,8 @@ class FurnaceGUI {
|
|||
int roundedMenus;
|
||||
int loadJapanese;
|
||||
int loadChinese;
|
||||
int loadChineseTraditional;
|
||||
int loadKorean;
|
||||
int fmLayout;
|
||||
int sampleLayout;
|
||||
int waveLayout;
|
||||
|
|
@ -1163,6 +1172,7 @@ class FurnaceGUI {
|
|||
snCore(0),
|
||||
nesCore(0),
|
||||
fdsCore(0),
|
||||
c64Core(1),
|
||||
pcSpeakerOutMethod(0),
|
||||
yrw801Path(""),
|
||||
tg100Path(""),
|
||||
|
|
@ -1205,6 +1215,8 @@ class FurnaceGUI {
|
|||
roundedMenus(0),
|
||||
loadJapanese(0),
|
||||
loadChinese(0),
|
||||
loadChineseTraditional(0),
|
||||
loadKorean(0),
|
||||
fmLayout(0),
|
||||
sampleLayout(0),
|
||||
waveLayout(0),
|
||||
|
|
@ -1398,6 +1410,8 @@ class FurnaceGUI {
|
|||
bool macroDragInitialValueSet;
|
||||
bool macroDragInitialValue;
|
||||
bool macroDragChar;
|
||||
bool macroDragBit30;
|
||||
bool macroDragSettingBit30;
|
||||
bool macroDragLineMode;
|
||||
bool macroDragMouseMoved;
|
||||
ImVec2 macroDragLineInitial;
|
||||
|
|
@ -1429,7 +1443,7 @@ class FurnaceGUI {
|
|||
int renderTimeBegin, renderTimeEnd, renderTimeDelta;
|
||||
int eventTimeBegin, eventTimeEnd, eventTimeDelta;
|
||||
|
||||
int chanToMove;
|
||||
int chanToMove, sysToMove, sysToDelete;
|
||||
|
||||
ImVec2 patWindowPos, patWindowSize;
|
||||
|
||||
|
|
@ -1661,6 +1675,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);
|
||||
|
||||
|
|
@ -1689,8 +1704,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, unsigned char& macroLoop, int macroMin, int macroMax, unsigned 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);
|
||||
|
|
|
|||
|
|
@ -839,7 +839,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,
|
||||
|
|
@ -911,3 +913,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
|
||||
};
|
||||
|
|
@ -42,7 +42,14 @@ extern const char* pitchLabel[11];
|
|||
extern const char* insTypes[];
|
||||
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];
|
||||
|
|
|
|||
|
|
@ -331,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) {
|
||||
|
|
@ -1192,10 +1197,21 @@ 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;
|
||||
|
||||
|
|
@ -1281,12 +1297,14 @@ 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;
|
||||
|
|
@ -1355,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);
|
||||
|
|
@ -1422,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)) {
|
||||
|
|
@ -1446,10 +1487,10 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
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();
|
||||
|
|
@ -4178,7 +4219,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));
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -47,21 +47,24 @@ void FurnaceGUI::drawPatManager() {
|
|||
});
|
||||
}
|
||||
|
||||
for (int i=0; i<e->getTotalChannelCount(); i++) {
|
||||
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::Text("%d. %s",i+1,e->getChannelName(i));
|
||||
ImGui::PushID(1000+i);
|
||||
if (ImGui::BeginTable("PatManTable",257,ImGuiTableFlags_ScrollX|ImGuiTableFlags_SizingFixedFit)) {
|
||||
ImGui::PushFont(patFont);
|
||||
if (ImGui::BeginTable("PatManTable",32)) {
|
||||
|
||||
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++) {
|
||||
if ((k&31)==0) ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
snprintf(id,1023,"%.2X",k);
|
||||
|
|
@ -98,10 +101,11 @@ void FurnaceGUI::drawPatManager() {
|
|||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::EndTable();
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PopFont();
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PAT_MANAGER;
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ void FurnaceGUI::initSystemPresets() {
|
|||
}
|
||||
));
|
||||
cat.systems.push_back(FurnaceGUISysDef(
|
||||
"Yamaha YM2610B (OPNB-B)", {
|
||||
"Yamaha YM2610B (OPNB2)", {
|
||||
DIV_SYSTEM_YM2610B, 64, 0, 0,
|
||||
0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,6 +97,11 @@ const char* nesCores[]={
|
|||
"NSFplay"
|
||||
};
|
||||
|
||||
const char* c64Cores[]={
|
||||
"reSID",
|
||||
"reSIDfp"
|
||||
};
|
||||
|
||||
const char* pcspkrOutMethods[]={
|
||||
"evdev SND_TONE",
|
||||
"KIOCSOUND on /dev/tty1",
|
||||
|
|
@ -980,6 +985,10 @@ void FurnaceGUI::drawSettings() {
|
|||
ImGui::SameLine();
|
||||
ImGui::Combo("##FDSCore",&settings.fdsCore,nesCores,2);
|
||||
|
||||
ImGui::Text("SID core");
|
||||
ImGui::SameLine();
|
||||
ImGui::Combo("##C64Core",&settings.c64Core,c64Cores,2);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("PC Speaker strategy");
|
||||
|
|
@ -1093,6 +1102,32 @@ 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:");
|
||||
|
|
@ -2137,6 +2172,7 @@ void FurnaceGUI::syncSettings() {
|
|||
settings.snCore=e->getConfInt("snCore",0);
|
||||
settings.nesCore=e->getConfInt("nesCore",0);
|
||||
settings.fdsCore=e->getConfInt("fdsCore",0);
|
||||
settings.c64Core=e->getConfInt("c64Core",1);
|
||||
settings.pcSpeakerOutMethod=e->getConfInt("pcSpeakerOutMethod",0);
|
||||
settings.yrw801Path=e->getConfString("yrw801Path","");
|
||||
settings.tg100Path=e->getConfString("tg100Path","");
|
||||
|
|
@ -2179,6 +2215,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);
|
||||
|
|
@ -2248,6 +2286,7 @@ void FurnaceGUI::syncSettings() {
|
|||
clampSetting(settings.snCore,0,1);
|
||||
clampSetting(settings.nesCore,0,1);
|
||||
clampSetting(settings.fdsCore,0,1);
|
||||
clampSetting(settings.c64Core,0,1);
|
||||
clampSetting(settings.pcSpeakerOutMethod,0,4);
|
||||
clampSetting(settings.mainFont,0,6);
|
||||
clampSetting(settings.patFont,0,6);
|
||||
|
|
@ -2284,6 +2323,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);
|
||||
|
|
@ -2382,6 +2423,7 @@ void FurnaceGUI::commitSettings() {
|
|||
e->setConf("snCore",settings.snCore);
|
||||
e->setConf("nesCore",settings.nesCore);
|
||||
e->setConf("fdsCore",settings.fdsCore);
|
||||
e->setConf("c64Core",settings.c64Core);
|
||||
e->setConf("pcSpeakerOutMethod",settings.pcSpeakerOutMethod);
|
||||
e->setConf("yrw801Path",settings.yrw801Path);
|
||||
e->setConf("tg100Path",settings.tg100Path);
|
||||
|
|
@ -2424,6 +2466,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);
|
||||
|
|
@ -3075,6 +3119,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;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include "gui.h"
|
||||
#include "misc/cpp/imgui_stdlib.h"
|
||||
#include "IconsFontAwesome4.h"
|
||||
#include <fmt/printf.h>
|
||||
#include <imgui.h>
|
||||
|
||||
void FurnaceGUI::drawSysManager() {
|
||||
|
|
@ -30,7 +31,93 @@ void FurnaceGUI::drawSysManager() {
|
|||
}
|
||||
if (!sysManagerOpen) return;
|
||||
if (ImGui::Begin("Chip Manager",&sysManagerOpen,globalWinFlags)) {
|
||||
ImGui::Text("Stuff here...");
|
||||
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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue