Merge branch 'master' of https://github.com/tildearrow/furnace into ymf278b

This commit is contained in:
cam900 2024-08-25 12:50:51 +09:00
commit 3e1e2fc2a6
73 changed files with 1657 additions and 663 deletions

View file

@ -35,6 +35,7 @@ const char* aboutLine[]={
_N("-- program --"),
"tildearrow",
_N("A M 4 N (intro tune)"),
"Adam Lederer",
"akumanatt",
"cam900",
"djtuBIG-MaliceX",
@ -302,6 +303,7 @@ const char* aboutLine[]={
_N("openMSX YMF278 emulator (modified version) by the openMSX developers"),
"",
_N("greetings to:"),
"floxy!",
"NEOART Costa Rica",
"Xenium Demoparty",
"@party",

View file

@ -161,6 +161,8 @@ void FurnaceGUI::drawCSPlayer() {
ImGui::TableNextColumn();
ImGui::Text(_("vols"));
ImGui::TableNextColumn();
ImGui::Text(_("volst"));
ImGui::TableNextColumn();
ImGui::Text(_("vib"));
ImGui::TableNextColumn();
ImGui::Text(_("porta"));
@ -189,6 +191,8 @@ void FurnaceGUI::drawCSPlayer() {
ImGui::TableNextColumn();
ImGui::Text("%+d",state->volSpeed);
ImGui::TableNextColumn();
ImGui::Text("%+d",state->volSpeedTarget);
ImGui::TableNextColumn();
ImGui::Text("%d/%d (%d)",state->vibratoDepth,state->vibratoRate,state->vibratoPos);
ImGui::TableNextColumn();
ImGui::Text("-> %d (%d)",state->portaTarget,state->portaSpeed);

View file

@ -145,6 +145,7 @@ void FurnaceGUI::drawDebug() {
ImGui::Text("- portaNote = %d",ch->portaNote);
ImGui::Text("- volume = %.4x",ch->volume);
ImGui::Text("- volSpeed = %d",ch->volSpeed);
ImGui::Text("- volSpeedTarget = %d",ch->volSpeedTarget);
ImGui::Text("- cut = %d",ch->cut);
ImGui::Text("- rowDelay = %d",ch->rowDelay);
ImGui::Text("- volMax = %.4x",ch->volMax);

View file

@ -73,6 +73,8 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_UNDO:
if (curWindow==GUI_WINDOW_SAMPLE_EDIT) {
doUndoSample();
} else if (curWindow==GUI_WINDOW_INS_EDIT) {
doUndoInstrument();
} else {
doUndo();
}
@ -80,6 +82,8 @@ void FurnaceGUI::doAction(int what) {
case GUI_ACTION_REDO:
if (curWindow==GUI_WINDOW_SAMPLE_EDIT) {
doRedoSample();
} else if (curWindow==GUI_WINDOW_INS_EDIT) {
doRedoInstrument();
} else {
doRedo();
}
@ -123,16 +127,16 @@ void FurnaceGUI::doAction(int what) {
pendingStepUpdate=1;
break;
case GUI_ACTION_OCTAVE_UP:
if (++curOctave>7) {
curOctave=7;
if (++curOctave>GUI_EDIT_OCTAVE_MAX) {
curOctave=GUI_EDIT_OCTAVE_MAX;
} else {
e->autoNoteOffAll();
failedNoteOn=false;
}
break;
case GUI_ACTION_OCTAVE_DOWN:
if (--curOctave<-5) {
curOctave=-5;
if (--curOctave<GUI_EDIT_OCTAVE_MIN) {
curOctave=GUI_EDIT_OCTAVE_MIN;
} else {
e->autoNoteOffAll();
failedNoteOn=false;
@ -677,14 +681,7 @@ void FurnaceGUI::doAction(int what) {
latchNibble=false;
break;
case GUI_ACTION_PAT_ABSORB_INSTRUMENT: {
DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],false);
if (!pat) break;
for (int i=cursor.y; i>=0; i--) {
if (pat->data[i][2] >= 0) {
curIns=pat->data[i][2];
break;
}
}
doAbsorbInstrument();
break;
}

View file

@ -508,7 +508,7 @@ void FurnaceGUI::drawMobileControls() {
mobileMenuOpen=false;
doAction(GUI_ACTION_SAVE_AS);
}
ImGui::SameLine();
if (ImGui::Button(_("Export"))) {
doAction(GUI_ACTION_EXPORT);
}
@ -533,6 +533,10 @@ void FurnaceGUI::drawMobileControls() {
drawSpeed(true);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem(_("Comments"))) {
drawNotes(true);
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
break;
@ -647,8 +651,8 @@ void FurnaceGUI::drawEditControls() {
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
if (curOctave>7) curOctave=7;
if (curOctave<-5) curOctave=-5;
if (curOctave>GUI_EDIT_OCTAVE_MAX) curOctave=GUI_EDIT_OCTAVE_MAX;
if (curOctave<GUI_EDIT_OCTAVE_MIN) curOctave=GUI_EDIT_OCTAVE_MIN;
e->autoNoteOffAll();
failedNoteOn=false;
@ -808,8 +812,8 @@ void FurnaceGUI::drawEditControls() {
ImGui::SameLine();
ImGui::SetNextItemWidth(96.0f*dpiScale);
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
if (curOctave>7) curOctave=7;
if (curOctave<-5) curOctave=-5;
if (curOctave>GUI_EDIT_OCTAVE_MAX) curOctave=GUI_EDIT_OCTAVE_MAX;
if (curOctave<GUI_EDIT_OCTAVE_MIN) curOctave=GUI_EDIT_OCTAVE_MIN;
e->autoNoteOffAll();
failedNoteOn=false;
@ -926,8 +930,8 @@ void FurnaceGUI::drawEditControls() {
float avail=ImGui::GetContentRegionAvail().x;
ImGui::SetNextItemWidth(avail);
if (ImGui::InputInt("##Octave",&curOctave,0,0)) {
if (curOctave>7) curOctave=7;
if (curOctave<-5) curOctave=-5;
if (curOctave>GUI_EDIT_OCTAVE_MAX) curOctave=GUI_EDIT_OCTAVE_MAX;
if (curOctave<GUI_EDIT_OCTAVE_MIN) curOctave=GUI_EDIT_OCTAVE_MIN;
e->autoNoteOffAll();
failedNoteOn=false;
@ -1093,8 +1097,8 @@ void FurnaceGUI::drawEditControls() {
float avail=ImGui::GetContentRegionAvail().x;
ImGui::SetNextItemWidth(avail);
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
if (curOctave>7) curOctave=7;
if (curOctave<-5) curOctave=-5;
if (curOctave>GUI_EDIT_OCTAVE_MAX) curOctave=GUI_EDIT_OCTAVE_MAX;
if (curOctave<GUI_EDIT_OCTAVE_MIN) curOctave=GUI_EDIT_OCTAVE_MIN;
e->autoNoteOffAll();
failedNoteOn=false;

View file

@ -1823,6 +1823,52 @@ void FurnaceGUI::doExpandSong(int multiplier) {
if (e->isPlaying()) e->play();
}
void FurnaceGUI::doAbsorbInstrument() {
bool foundIns=false;
bool foundOctave=false;
auto foundAll = [&]() { return foundIns && foundOctave; };
// search this order and all prior until we find all the data we need
int orderIdx=curOrder;
for (; orderIdx>=0 && !foundAll(); orderIdx--) {
DivPattern* pat=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][orderIdx],false);
if (!pat) continue;
// start on current row when searching current order, but start from end when searching
// prior orders.
int searchStartRow=orderIdx==curOrder ? cursor.y : e->curSubSong->patLen-1;
for (int i=searchStartRow; i>=0 && !foundAll(); i--) {
// absorb most recent instrument
if (!foundIns && pat->data[i][2] >= 0) {
foundIns=true;
curIns=pat->data[i][2];
}
// absorb most recent octave (i.e. set curOctave such that the "main row" (QWERTY) of
// notes will result in an octave number equal to the previous note).
if (!foundOctave && pat->data[i][0] != 0) {
foundOctave=true;
// decode octave data (was signed cast to unsigned char)
int octave=pat->data[i][1];
if (octave>128) octave-=256;
// @NOTE the special handling when note==12, which is really an octave above what's
// stored in the octave data. without this handling, if you press Q, then
// "ABSORB_INSTRUMENT", then Q again, you'd get a different octave!
if (pat->data[i][0]==12) octave++;
curOctave=CLAMP(octave-1, GUI_EDIT_OCTAVE_MIN, GUI_EDIT_OCTAVE_MAX);
}
}
}
// if no instrument has been set at this point, the only way to match it is to use "none"
if (!foundIns) curIns=-1;
logD("doAbsorbInstrument -- searched %d orders", curOrder-orderIdx);
}
void FurnaceGUI::doDrag() {
int len=dragEnd.xCoarse-dragStart.xCoarse+1;

View file

@ -319,6 +319,29 @@ void FurnaceGUI::drawExportROM(bool onWindow) {
}
break;
}
case DIV_ROM_ZSM: {
int zsmExportTickRate=romConfig.getInt("zsmrate",60);
bool zsmExportLoop=romConfig.getBool("loop",true);
bool zsmExportOptimize=romConfig.getBool("optimize",true);
if (ImGui::InputInt(_("Tick Rate (Hz)"),&zsmExportTickRate,1,2)) {
if (zsmExportTickRate<1) zsmExportTickRate=1;
if (zsmExportTickRate>44100) zsmExportTickRate=44100;
altered=true;
}
if (ImGui::Checkbox(_("loop"),&zsmExportLoop)) {
altered=true;
}
if (ImGui::Checkbox(_("optimize size"),&zsmExportOptimize)) {
altered=true;
}
if (altered) {
romConfig.set("zsmrate",zsmExportTickRate);
romConfig.set("loop",zsmExportLoop);
romConfig.set("optimize",zsmExportOptimize);
}
break;
}
case DIV_ROM_ABSTRACT:
ImGui::TextWrapped("%s",_("select a target from the menu at the top of this dialog."));
break;
@ -340,28 +363,6 @@ void FurnaceGUI::drawExportROM(bool onWindow) {
}
}
void FurnaceGUI::drawExportZSM(bool onWindow) {
exitDisabledTimer=1;
ImGui::Text(_("Commander X16 Zsound Music File"));
if (ImGui::InputInt(_("Tick Rate (Hz)"),&zsmExportTickRate,1,2)) {
if (zsmExportTickRate<1) zsmExportTickRate=1;
if (zsmExportTickRate>44100) zsmExportTickRate=44100;
}
ImGui::Checkbox(_("loop"),&zsmExportLoop);
ImGui::SameLine();
ImGui::Checkbox(_("optimize size"),&zsmExportOptimize);
if (onWindow) {
ImGui::Separator();
if (ImGui::Button(_("Cancel"),ImVec2(200.0f*dpiScale,0))) ImGui::CloseCurrentPopup();
ImGui::SameLine();
}
if (ImGui::Button(_("Export"),ImVec2(200.0f*dpiScale,0))) {
openFileDialog(GUI_FILE_EXPORT_ZSM);
ImGui::CloseCurrentPopup();
}
}
void FurnaceGUI::drawExportText(bool onWindow) {
exitDisabledTimer=1;
@ -444,16 +445,6 @@ void FurnaceGUI::drawExport() {
ImGui::EndTabItem();
}
}
int numZSMCompat=0;
for (int i=0; i<e->song.systemLen; i++) {
if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++;
}
if (numZSMCompat>0) {
if (ImGui::BeginTabItem(_("ZSM"))) {
drawExportZSM(true);
ImGui::EndTabItem();
}
}
if (ImGui::BeginTabItem(_("Text"))) {
drawExportText(true);
ImGui::EndTabItem();
@ -478,9 +469,6 @@ void FurnaceGUI::drawExport() {
case GUI_EXPORT_ROM:
drawExportROM(true);
break;
case GUI_EXPORT_ZSM:
drawExportZSM(true);
break;
case GUI_EXPORT_TEXT:
drawExportText(true);
break;

View file

@ -995,7 +995,7 @@ Collapsed=0\n\
\n\
[Window][Rendering...]\n\
Pos=585,342\n\
Size=114,71\n\
Size=600,100\n\
Collapsed=0\n\
\n\
[Window][Export VGM##FileDialog]\n\
@ -2022,16 +2022,6 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
(settings.autoFillSave)?shortName:""
);
break;
case GUI_FILE_EXPORT_ZSM:
if (!dirExists(workingDirZSMExport)) workingDirZSMExport=getHomeDir();
hasOpened=fileDialog->openSave(
_("Export ZSM"),
{_("ZSM file"), "*.zsm"},
workingDirZSMExport,
dpiScale,
(settings.autoFillSave)?shortName:""
);
break;
case GUI_FILE_EXPORT_TEXT:
if (!dirExists(workingDirROMExport)) workingDirROMExport=getHomeDir();
hasOpened=fileDialog->openSave(
@ -2592,7 +2582,40 @@ int FurnaceGUI::loadStream(String path) {
void FurnaceGUI::exportAudio(String path, DivAudioExportModes mode) {
songOrdersLengths.clear();
int loopOrder=0;
int loopRow=0;
int loopEnd=0;
e->walkSong(loopOrder,loopRow,loopEnd);
e->findSongLength(loopOrder,loopRow,audioExportOptions.fadeOut,songFadeoutSectionLength,songHasSongEndCommand,songOrdersLengths,songLength); // for progress estimation
songLoopedSectionLength=songLength;
for (int i=0; i<loopOrder; i++) {
songLoopedSectionLength-=songOrdersLengths[i];
}
songLoopedSectionLength-=loopRow;
e->saveAudio(path.c_str(),audioExportOptions);
totalFiles=0;
e->getTotalAudioFiles(totalFiles);
int totalLoops=0;
lengthOfOneFile=songLength;
if (!songHasSongEndCommand) {
e->getTotalLoops(totalLoops);
lengthOfOneFile+=songLoopedSectionLength*totalLoops;
lengthOfOneFile+=songFadeoutSectionLength; // account for fadeout
}
totalLength=lengthOfOneFile*totalFiles;
curProgress=0.0f;
displayExporting=true;
}
@ -3714,6 +3737,7 @@ bool FurnaceGUI::loop() {
ImGui::GetIO().AddKeyEvent(ImGuiKey_Backspace,false);
injectBackUp=false;
}
while (SDL_PollEvent(&ev)) {
WAKE_UP;
ImGui_ImplSDL2_ProcessEvent(&ev);
@ -3730,13 +3754,16 @@ bool FurnaceGUI::loop() {
}
case SDL_MOUSEBUTTONUP:
pointUp(ev.button.x,ev.button.y,ev.button.button);
insEditMayBeDirty=true;
break;
case SDL_MOUSEBUTTONDOWN:
pointDown(ev.button.x,ev.button.y,ev.button.button);
insEditMayBeDirty=true;
break;
case SDL_MOUSEWHEEL:
wheelX+=ev.wheel.x;
wheelY+=ev.wheel.y;
insEditMayBeDirty=true;
break;
case SDL_WINDOWEVENT:
switch (ev.window.event) {
@ -3813,12 +3840,14 @@ bool FurnaceGUI::loop() {
if (!ImGui::GetIO().WantCaptureKeyboard) {
keyDown(ev);
}
insEditMayBeDirty=true;
#ifdef IS_MOBILE
injectBackUp=true;
#endif
break;
case SDL_KEYUP:
// for now
insEditMayBeDirty=true;
break;
case SDL_DROPFILE:
if (ev.drop.file!=NULL) {
@ -4405,16 +4434,6 @@ bool FurnaceGUI::loop() {
ImGui::EndMenu();
}
}
int numZSMCompat=0;
for (int i=0; i<e->song.systemLen; i++) {
if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++;
}
if (numZSMCompat>0) {
if (ImGui::BeginMenu(_("export ZSM..."))) {
drawExportZSM();
ImGui::EndMenu();
}
}
if (ImGui::BeginMenu(_("export text..."))) {
drawExportText();
ImGui::EndMenu();
@ -4442,16 +4461,6 @@ bool FurnaceGUI::loop() {
displayExport=true;
}
}
int numZSMCompat=0;
for (int i=0; i<e->song.systemLen; i++) {
if ((e->song.system[i]==DIV_SYSTEM_VERA) || (e->song.system[i]==DIV_SYSTEM_YM2151)) numZSMCompat++;
}
if (numZSMCompat>0) {
if (ImGui::MenuItem(_("export ZSM..."))) {
curExportType=GUI_EXPORT_ZSM;
displayExport=true;
}
}
if (ImGui::MenuItem(_("export text..."))) {
curExportType=GUI_EXPORT_TEXT;
displayExport=true;
@ -4477,7 +4486,7 @@ bool FurnaceGUI::loop() {
} else {
if (ImGui::BeginMenu(_("add chip..."))) {
exitDisabledTimer=1;
DivSystem picked=systemPicker();
DivSystem picked=systemPicker(false);
if (picked!=DIV_SYSTEM_NULL) {
if (!e->addSystem(picked)) {
showError(fmt::sprintf(_("cannot add chip! (%s)"),e->getLastError()));
@ -4508,7 +4517,7 @@ 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())) {
DivSystem picked=systemPicker();
DivSystem picked=systemPicker(false);
if (picked!=DIV_SYSTEM_NULL) {
if (e->changeSystem(i,picked,preserveChanPos)) {
MARK_MODIFIED;
@ -4778,7 +4787,7 @@ bool FurnaceGUI::loop() {
info=fmt::sprintf(_("Set volume: %d (%.2X, INVALID!)"),p->data[cursor.y][3],p->data[cursor.y][3]);
} else {
float realVol=e->getGain(cursor.xCoarse,p->data[cursor.y][3]);
info=fmt::sprintf(_("Set volume: %d (%.2X, %d%%)"),p->data[cursor.y][3],p->data[cursor.y][3],(int)(realVol*100.0f/(float)maxVol));
info=fmt::sprintf(_("Set volume: %d (%.2X, %d%%)"),p->data[cursor.y][3],p->data[cursor.y][3],(int)(realVol*100.0f));
}
hasInfo=true;
}
@ -5034,9 +5043,6 @@ bool FurnaceGUI::loop() {
case GUI_FILE_EXPORT_VGM:
workingDirVGMExport=fileDialog->getPath()+DIR_SEPARATOR_STR;
break;
case GUI_FILE_EXPORT_ZSM:
workingDirZSMExport=fileDialog->getPath()+DIR_SEPARATOR_STR;
break;
case GUI_FILE_EXPORT_ROM:
case GUI_FILE_EXPORT_TEXT:
case GUI_FILE_EXPORT_CMDSTREAM:
@ -5136,9 +5142,6 @@ bool FurnaceGUI::loop() {
if (curFileDialog==GUI_FILE_EXPORT_ROM) {
checkExtension(romFilterExt.c_str());
}
if (curFileDialog==GUI_FILE_EXPORT_ZSM) {
checkExtension(".zsm");
}
if (curFileDialog==GUI_FILE_EXPORT_TEXT) {
checkExtension(".txt");
}
@ -5614,27 +5617,6 @@ bool FurnaceGUI::loop() {
}
break;
}
case GUI_FILE_EXPORT_ZSM: {
SafeWriter* w=e->saveZSM(zsmExportTickRate,zsmExportLoop,zsmExportOptimize);
if (w!=NULL) {
FILE* f=ps_fopen(copyOfName.c_str(),"wb");
if (f!=NULL) {
fwrite(w->getFinalBuf(),1,w->size(),f);
fclose(f);
pushRecentSys(copyOfName.c_str());
} else {
showError(_("could not open file!"));
}
w->finish();
delete w;
if (!e->getWarnings().empty()) {
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
}
} else {
showError(fmt::sprintf(_("Could not write ZSM! (%s)"),e->getLastError()));
}
break;
}
case GUI_FILE_EXPORT_ROM:
romExportPath=copyOfName;
pendingExport=e->buildROM(romTarget);
@ -5877,8 +5859,54 @@ bool FurnaceGUI::loop() {
MEASURE_BEGIN(popup);
centerNextWindow(_("Rendering..."),canvasW,canvasH);
if (ImGui::BeginPopupModal(_("Rendering..."),NULL,ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text(_("Please wait..."));
if (ImGui::BeginPopupModal(_("Rendering..."),NULL,ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove)) {
// WHAT the HELL?!
WAKE_UP;
if (audioExportOptions.mode!=DIV_EXPORT_MODE_MANY_CHAN) {
ImGui::Text(_("Please wait..."));
}
float* progressLambda=&curProgress;
int curPosInRows=0;
int* curPosInRowsLambda=&curPosInRows;
int loopsLeft=0;
int* loopsLeftLambda=&loopsLeft;
int totalLoops=0;
int* totalLoopsLambda=&totalLoops;
int curFile=0;
int* curFileLambda=&curFile;
if (e->isExporting()) {
e->lockEngine([this, progressLambda, curPosInRowsLambda, curFileLambda,
loopsLeftLambda, totalLoopsLambda] () {
int curRow=0; int curOrder=0;
e->getCurSongPos(curRow, curOrder); *curFileLambda=0;
e->getCurFileIndex(*curFileLambda);
*curPosInRowsLambda=curRow; for (int i=0; i<curOrder;
i++) {
*curPosInRowsLambda+=songOrdersLengths[i];}
if (!songHasSongEndCommand) {
e->getLoopsLeft(*loopsLeftLambda); e->getTotalLoops(*totalLoopsLambda); if ((*totalLoopsLambda)!=(*loopsLeftLambda)) //we are going 2nd, 3rd, etc. time through the song
{
*curPosInRowsLambda-=(songLength-songLoopedSectionLength); //a hack so progress bar does not jump?
}
if (e->getIsFadingOut()) //we are in fadeout??? why it works like that bruh
{
// LIVE WITH IT damn it
*curPosInRowsLambda-=(songLength-songLoopedSectionLength); //a hack so progress bar does not jump?
}
}
// this horrible indentation courtesy of `indent`
*progressLambda=(float) ((*curPosInRowsLambda) + ((*totalLoopsLambda)- (*loopsLeftLambda)) * songLength + lengthOfOneFile * (*curFileLambda)) / (float) totalLength;});
}
ImGui::Text(_("Row %d of %d"),curPosInRows+((totalLoops)-(loopsLeft))*songLength,lengthOfOneFile);
if (audioExportOptions.mode==DIV_EXPORT_MODE_MANY_CHAN) {
ImGui::Text(_("Channel %d of %d"),curFile+1,totalFiles);
}
ImGui::ProgressBar(curProgress,ImVec2(320.0f*dpiScale,0),fmt::sprintf("%.2f%%",curProgress*100.0f).c_str());
if (ImGui::Button(_("Abort"))) {
if (e->haltAudioFile()) {
ImGui::CloseCurrentPopup();
@ -7202,6 +7230,11 @@ bool FurnaceGUI::loop() {
willCommit=false;
}
// To check for instrument editor modification, we need an up-to-date `insEditMayBeDirty`
// (based on incoming user input events), and we want any possible instrument modifications
// to already have been made.
checkRecordInstrumentUndoStep();
if (shallDetectScale) {
if (--shallDetectScale<1) {
if (settings.dpiScale<0.5f) {
@ -7879,7 +7912,6 @@ void FurnaceGUI::syncState() {
workingDirSample=e->getConfString("lastDirSample",workingDir);
workingDirAudioExport=e->getConfString("lastDirAudioExport",workingDir);
workingDirVGMExport=e->getConfString("lastDirVGMExport",workingDir);
workingDirZSMExport=e->getConfString("lastDirZSMExport",workingDir);
workingDirROMExport=e->getConfString("lastDirROMExport",workingDir);
workingDirFont=e->getConfString("lastDirFont",workingDir);
workingDirColors=e->getConfString("lastDirColors",workingDir);
@ -8038,7 +8070,6 @@ void FurnaceGUI::commitState(DivConfig& conf) {
conf.set("lastDirSample",workingDirSample);
conf.set("lastDirAudioExport",workingDirAudioExport);
conf.set("lastDirVGMExport",workingDirVGMExport);
conf.set("lastDirZSMExport",workingDirZSMExport);
conf.set("lastDirROMExport",workingDirROMExport);
conf.set("lastDirFont",workingDirFont);
conf.set("lastDirColors",workingDirColors);
@ -8256,8 +8287,6 @@ FurnaceGUI::FurnaceGUI():
displayError(false),
displayExporting(false),
vgmExportLoop(true),
zsmExportLoop(true),
zsmExportOptimize(true),
vgmExportPatternHints(false),
vgmExportDirectStream(false),
displayInsTypeList(false),
@ -8300,7 +8329,6 @@ FurnaceGUI::FurnaceGUI():
vgmExportVersion(0x171),
vgmExportTrailingTicks(-1),
drawHalt(10),
zsmExportTickRate(60),
macroPointSize(16),
waveEditStyle(0),
displayInsTypeListMakeInsSample(-1),
@ -8367,11 +8395,21 @@ FurnaceGUI::FurnaceGUI():
bigFont(NULL),
headFont(NULL),
fontRange(NULL),
songLength(0),
songLoopedSectionLength(0),
songFadeoutSectionLength(0),
songHasSongEndCommand(false),
lengthOfOneFile(0),
totalLength(0),
curProgress(0.0f),
totalFiles(0),
localeRequiresJapanese(false),
localeRequiresChinese(false),
localeRequiresChineseTrad(false),
localeRequiresKorean(false),
prevInsData(NULL),
cachedCurInsPtr(NULL),
insEditMayBeDirty(false),
pendingLayoutImport(NULL),
pendingLayoutImportLen(0),
pendingLayoutImportStep(0),
@ -8887,6 +8925,8 @@ FurnaceGUI::FurnaceGUI():
memset(romExportAvail,0,sizeof(bool)*DIV_ROM_MAX);
songOrdersLengths.clear();
strncpy(noteOffLabel,"OFF",32);
strncpy(noteRelLabel,"===",32);
strncpy(macroRelLabel,"REL",32);

View file

@ -137,6 +137,9 @@ enum FurnaceGUIRenderBackend {
#define ngettext momo_ngettext
#endif
#define GUI_EDIT_OCTAVE_MIN -5
#define GUI_EDIT_OCTAVE_MAX 7
// TODO:
// - add colors for FM envelope and waveform
// - maybe add "alternate" color for FM modulators/carriers (a bit difficult)
@ -598,7 +601,6 @@ enum FurnaceGUIFileDialogs {
GUI_FILE_EXPORT_AUDIO_PER_SYS,
GUI_FILE_EXPORT_AUDIO_PER_CHANNEL,
GUI_FILE_EXPORT_VGM,
GUI_FILE_EXPORT_ZSM,
GUI_FILE_EXPORT_CMDSTREAM,
GUI_FILE_EXPORT_TEXT,
GUI_FILE_EXPORT_ROM,
@ -651,7 +653,6 @@ enum FurnaceGUIExportTypes {
GUI_EXPORT_AUDIO=0,
GUI_EXPORT_VGM,
GUI_EXPORT_ROM,
GUI_EXPORT_ZSM,
GUI_EXPORT_CMD_STREAM,
GUI_EXPORT_TEXT,
GUI_EXPORT_DMF
@ -1594,7 +1595,7 @@ class FurnaceGUI {
String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile, sysSearchQuery, newSongQuery, paletteQuery, sampleBankSearchQuery;
String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport;
String workingDirVGMExport, workingDirZSMExport, workingDirROMExport;
String workingDirVGMExport, workingDirROMExport;
String workingDirFont, workingDirColors, workingDirKeybinds;
String workingDirLayout, workingDirROM, workingDirTest;
String workingDirConfig;
@ -1613,7 +1614,7 @@ class FurnaceGUI {
std::vector<String> availRenderDrivers;
std::vector<String> availAudioDrivers;
bool quit, warnQuit, willCommit, edit, editClone, isPatUnique, modified, displayError, displayExporting, vgmExportLoop, zsmExportLoop, zsmExportOptimize, vgmExportPatternHints;
bool quit, warnQuit, willCommit, edit, editClone, isPatUnique, modified, displayError, displayExporting, vgmExportLoop, vgmExportPatternHints;
bool vgmExportDirectStream, displayInsTypeList, displayWaveSizeList;
bool portrait, injectBackUp, mobileMenuOpen, warnColorPushed;
bool wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu;
@ -1634,7 +1635,6 @@ class FurnaceGUI {
int vgmExportTrailingTicks;
int cvHiScore;
int drawHalt;
int zsmExportTickRate;
int macroPointSize;
int waveEditStyle;
int displayInsTypeListMakeInsSample;
@ -1723,6 +1723,16 @@ class FurnaceGUI {
char emptyLabel[32];
char emptyLabel2[32];
std::vector<int> songOrdersLengths; // lengths of all orders (for drawing song export progress)
int songLength; // length of all the song in rows
int songLoopedSectionLength; // length of looped part of the song
int songFadeoutSectionLength; // length of fading part of the song
bool songHasSongEndCommand; // song has "Song end" command (FFxx)
int lengthOfOneFile; // length of one rendering pass. song length times num of loops + fadeout
int totalLength; // total length of render (lengthOfOneFile times num of files for per-channel export)
float curProgress;
int totalFiles;
struct Settings {
bool settingsChanged;
int mainFontSize, patFontSize, headFontSize, iconSize;
@ -2263,6 +2273,9 @@ class FurnaceGUI {
std::vector<ImWchar> localeExtraRanges;
DivInstrument* prevInsData;
DivInstrument cachedCurIns;
DivInstrument* cachedCurInsPtr;
bool insEditMayBeDirty;
unsigned char* pendingLayoutImport;
size_t pendingLayoutImportLen;
@ -2704,7 +2717,6 @@ class FurnaceGUI {
void drawExportAudio(bool onWindow=false);
void drawExportVGM(bool onWindow=false);
void drawExportROM(bool onWindow=false);
void drawExportZSM(bool onWindow=false);
void drawExportText(bool onWindow=false);
void drawExportCommand(bool onWindow=false);
void drawExportDMF(bool onWindow=false);
@ -2824,7 +2836,7 @@ class FurnaceGUI {
void drawMemory();
void drawCompatFlags();
void drawPiano();
void drawNotes();
void drawNotes(bool asChild=false);
void drawChannels();
void drawPatManager();
void drawSysManager();
@ -2914,13 +2926,14 @@ class FurnaceGUI {
void doExpand(int multiplier, const SelectionPoint& sStart, const SelectionPoint& sEnd);
void doCollapseSong(int divider);
void doExpandSong(int multiplier);
void doAbsorbInstrument();
void doUndo();
void doRedo();
void doFind();
void doReplace();
void doDrag();
void editOptions(bool topMenu);
DivSystem systemPicker();
DivSystem systemPicker(bool fullWidth);
void noteInput(int num, int key, int vol=-1);
void valueInput(int num, bool direct=false, int target=-1);
void orderInput(int num);
@ -2930,6 +2943,10 @@ class FurnaceGUI {
void doUndoSample();
void doRedoSample();
void checkRecordInstrumentUndoStep();
void doUndoInstrument();
void doRedoInstrument();
void play(int row=0);
void setOrder(unsigned char order, bool forced=false);
void stop();

View file

@ -473,8 +473,8 @@ const FurnaceGUIColors fxColors[256]={
GUI_COLOR_PATTERN_EFFECT_INVALID,
GUI_COLOR_PATTERN_EFFECT_INVALID,
GUI_COLOR_PATTERN_EFFECT_INVALID,
GUI_COLOR_PATTERN_EFFECT_INVALID,
GUI_COLOR_PATTERN_EFFECT_INVALID,
GUI_COLOR_PATTERN_EFFECT_VOLUME,
GUI_COLOR_PATTERN_EFFECT_VOLUME,
GUI_COLOR_PATTERN_EFFECT_INVALID,
GUI_COLOR_PATTERN_EFFECT_INVALID,
GUI_COLOR_PATTERN_EFFECT_INVALID,
@ -687,7 +687,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
D("PAT_LATCH", _N("Set note input latch"), 0),
D("PAT_SCROLL_MODE", _N("Change mobile scroll mode"), 0),
D("PAT_CLEAR_LATCH", _N("Clear note input latch"), 0),
D("PAT_ABSORB_INSTRUMENT", _N("Set current instrument to channel's current instrument column"), 0),
D("PAT_ABSORB_INSTRUMENT", _N("Absorb instrument/octave from status at cursor"), 0),
D("PAT_MAX", "", NOT_AN_ACTION),
D("INS_LIST_MIN", _N("---Instrument list"), NOT_AN_ACTION),

View file

@ -5250,6 +5250,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::SetNextWindowSizeConstraints(ImVec2(440.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW,canvasH));
}
if (ImGui::Begin("Instrument Editor",&insEditOpen,globalWinFlags|(settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking),_("Instrument Editor"))) {
DivInstrument* ins=NULL;
if (curIns==-2) {
ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(ImGui::GetContentRegionAvail().y-ImGui::GetFrameHeightWithSpacing()+ImGui::GetStyle().ItemSpacing.y)*0.5f);
CENTER_TEXT(_("waiting..."));
@ -5277,6 +5278,7 @@ void FurnaceGUI::drawInsEdit() {
curIns=i;
wavePreviewInit=true;
updateFMPreview=true;
ins = e->song.ins[curIns];
}
}
ImGui::EndCombo();
@ -5299,7 +5301,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::EndTable();
}
} else {
DivInstrument* ins=e->song.ins[curIns];
ins=e->song.ins[curIns];
if (updateFMPreview) {
renderFMPreview(ins);
updateFMPreview=false;
@ -7196,6 +7198,8 @@ void FurnaceGUI::drawInsEdit() {
macroList.push_back(FurnaceGUIMacroDesc(_("Noise"),&ins->std.dutyMacro,0,8,160,uiColors[GUI_COLOR_MACRO_NOISE]));
}
macroList.push_back(FurnaceGUIMacroDesc(_("Waveform"),&ins->std.waveMacro,0,waveCount,160,uiColors[GUI_COLOR_MACRO_WAVE],false,NULL,NULL,false,NULL));
macroList.push_back(FurnaceGUIMacroDesc(_("Panning (left)"),&ins->std.panLMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL));
macroList.push_back(FurnaceGUIMacroDesc(_("Panning (right)"),&ins->std.panRMacro,0,15,46,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
break;
@ -7755,6 +7759,63 @@ void FurnaceGUI::drawInsEdit() {
ImGui::EndPopup();
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_INS_EDIT;
ImGui::End();
}
void FurnaceGUI::checkRecordInstrumentUndoStep() {
if (insEditOpen && curIns>=0 && curIns<(int)e->song.ins.size()) {
DivInstrument* ins=e->song.ins[curIns];
// invalidate cachedCurIns/any possible changes if the cachedCurIns was referencing a different
// instrument altgoether
bool insChanged=ins!=cachedCurInsPtr;
if (insChanged) {
insEditMayBeDirty=false;
cachedCurInsPtr=ins;
cachedCurIns=*ins;
}
cachedCurInsPtr=ins;
// check against the last cached to see if diff -- note that modifications to instruments
// happen outside drawInsEdit (e.g. cursor inputs are processed and can directly modify
// macro data). but don't check until we think the user input is complete.
bool delayDiff=ImGui::IsMouseDown(ImGuiMouseButton_Left) || ImGui::IsMouseDown(ImGuiMouseButton_Right) || ImGui::GetIO().WantCaptureKeyboard;
if (!delayDiff && insEditMayBeDirty) {
bool hasChange=ins->recordUndoStepIfChanged(e->processTime, &cachedCurIns);
if (hasChange) {
cachedCurIns=*ins;
}
insEditMayBeDirty=false;
}
} else {
cachedCurInsPtr=NULL;
insEditMayBeDirty=false;
}
}
void FurnaceGUI::doUndoInstrument() {
if (!insEditOpen) return;
if (curIns<0 || curIns>=(int)e->song.ins.size()) return;
DivInstrument* ins=e->song.ins[curIns];
// is locking the engine necessary? copied from doUndoSample
e->lockEngine([this,ins]() {
ins->undo();
cachedCurInsPtr=ins;
cachedCurIns=*ins;
});
}
void FurnaceGUI::doRedoInstrument() {
if (!insEditOpen) return;
if (curIns<0 || curIns>=(int)e->song.ins.size()) return;
DivInstrument* ins=e->song.ins[curIns];
// is locking the engine necessary? copied from doRedoSample
e->lockEngine([this,ins]() {
ins->redo();
cachedCurInsPtr=ins;
cachedCurIns=*ins;
});
}

View file

@ -1500,6 +1500,7 @@ void FurnaceGUI::drawPattern() {
i.cmd==DIV_CMD_HINT_PORTA ||
i.cmd==DIV_CMD_HINT_LEGATO ||
i.cmd==DIV_CMD_HINT_VOL_SLIDE ||
i.cmd==DIV_CMD_HINT_VOL_SLIDE_TARGET ||
i.cmd==DIV_CMD_HINT_ARPEGGIO ||
i.cmd==DIV_CMD_HINT_PITCH ||
i.cmd==DIV_CMD_HINT_VIBRATO ||

View file

@ -1216,62 +1216,62 @@ void FurnaceGUI::initSystemPresets() {
}
);
SUB_ENTRY(
"Sega TeraDrive", {
CH(DIV_SYSTEM_YM2612, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
"Sega TeraDrive", {
CH(DIV_SYSTEM_YM2612, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
}
);
SUB_SUB_ENTRY(
"Sega TeraDrive (extended channel 3)", {
CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
"Sega TeraDrive (extended channel 3)", {
CH(DIV_SYSTEM_YM2612_EXT, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
}
);
SUB_SUB_ENTRY(
"Sega TeraDrive (CSM)", {
CH(DIV_SYSTEM_YM2612_CSM, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
"Sega TeraDrive (CSM)", {
CH(DIV_SYSTEM_YM2612_CSM, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
}
);
SUB_SUB_ENTRY(
"Sega TeraDrive (DualPCM)", {
CH(DIV_SYSTEM_YM2612_DUALPCM, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
"Sega TeraDrive (DualPCM)", {
CH(DIV_SYSTEM_YM2612_DUALPCM, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
}
);
SUB_SUB_ENTRY(
"Sega TeraDrive (DualPCM, extended channel 3)", {
CH(DIV_SYSTEM_YM2612_DUALPCM_EXT, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
"Sega TeraDrive (DualPCM, extended channel 3)", {
CH(DIV_SYSTEM_YM2612_DUALPCM_EXT, 1.0f, 0, ""),
CH(DIV_SYSTEM_SMS, 0.5f, 0, ""),
CH(DIV_SYSTEM_PCSPKR, 1.0f, 0, "")
}
);
ENTRY(
"Sharp X1", {
CH(DIV_SYSTEM_AY8910, 1.0f, 0, "clockSel=3")
}
}
);
SUB_ENTRY(
"Sharp X1 + FM Addon", {
CH(DIV_SYSTEM_AY8910, 1.0f, 0, "clockSel=3"),
CH(DIV_SYSTEM_YM2151, 1.0f, 0, "clockSel=2")
}
}
);
ENTRY(
"Sharp X68000", {
CH(DIV_SYSTEM_YM2151, 1.0f, 0, "clockSel=2"),
CH(DIV_SYSTEM_MSM6258, 1.0f, 0, "clockSel=2")
}
}
);
ENTRY(
"FM-7", {
CH(DIV_SYSTEM_AY8910, 1.0f, 0, "clockSel=12"),
CH(DIV_SYSTEM_YM2203, 1.0f, 0, "clockSel=5")
}
}
);
SUB_ENTRY(
"FM-7 (extended channel 3)", {

View file

@ -253,16 +253,27 @@ void FurnaceGUI::drawSampleEdit() {
SAMPLE_WARN(warnLength,"QSound: maximum sample length is 65535");
}
break;
case DIV_SYSTEM_NES:
case DIV_SYSTEM_NES: {
if (sample->loop) {
if (sample->loopStart!=0 || sample->loopEnd!=(int)(sample->samples)) {
SAMPLE_WARN(warnLoopPos,_("NES: loop point ignored on DPCM (may only loop entire sample)"));
if (sample->loopStart&511) {
int tryWith=(sample->loopStart)&(~511);
if (tryWith>(int)sample->samples) tryWith-=512;
String alignHint=fmt::sprintf(_("NES: loop start must be a multiple of 512 (try with %d)"),tryWith);
SAMPLE_WARN(warnLoopStart,alignHint);
}
if ((sample->loopEnd)&127) {
// +1 bc of how sample length is treated: https://www.nesdev.org/wiki/APU_DMC
int tryWith=(sample->loopEnd + 1)&(~127);
if (tryWith>(int)sample->samples) tryWith-=128;
String alignHint=fmt::sprintf(_("NES: loop end must be a multiple of 128 (try with %d)"),tryWith);
SAMPLE_WARN(warnLoopEnd,alignHint);
}
}
if (sample->samples>32648) {
SAMPLE_WARN(warnLength,_("NES: maximum DPCM sample length is 32648"));
}
break;
}
case DIV_SYSTEM_X1_010:
if (sample->loop) {
SAMPLE_WARN(warnLoop,_("X1-010: samples can't loop"));

View file

@ -1089,15 +1089,19 @@ void FurnaceGUI::drawSettings() {
ImGui::PushID(i);
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(_("Invert")).x-ImGui::GetFrameHeightWithSpacing()*2.0-ImGui::GetStyle().ItemSpacing.x*2.0);
if (ImGui::BeginCombo("##System",getSystemName(sysID))) {
for (int j=0; availableSystems[j]; j++) {
if (ImGui::Selectable(getSystemName((DivSystem)availableSystems[j]),sysID==availableSystems[j])) {
sysID=(DivSystem)availableSystems[j];
settings.initialSys.set(fmt::sprintf("id%d",i),(int)e->systemToFileFur(sysID));
settings.initialSys.set(fmt::sprintf("flags%d",i),"");
settingsChanged=true;
}
if (ImGui::BeginCombo("##System",getSystemName(sysID),ImGuiComboFlags_HeightLargest)) {
sysID=systemPicker(true);
if (sysID!=DIV_SYSTEM_NULL)
{
settings.initialSys.set(fmt::sprintf("id%d",i),(int)e->systemToFileFur(sysID));
settings.initialSys.set(fmt::sprintf("flags%d",i),"");
settingsChanged=true;
ImGui::CloseCurrentPopup();
}
ImGui::EndCombo();
}

View file

@ -22,18 +22,23 @@
// NOTE: please don't ask me to enable text wrap.
// Dear ImGui doesn't have that feature. D:
void FurnaceGUI::drawNotes() {
void FurnaceGUI::drawNotes(bool asChild) {
if (nextWindow==GUI_WINDOW_NOTES) {
notesOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!notesOpen) return;
if (ImGui::Begin("Song Comments",&notesOpen,globalWinFlags,_("Song Comments"))) {
if (!notesOpen && !asChild) return;
bool began=asChild?ImGui::BeginChild("Song Info##Song Information"):ImGui::Begin("Song Comments",&notesOpen,globalWinFlags,_("Song Comments"));
if (began) {
if (ImGui::InputTextMultiline("##SongNotes",&e->song.notes,ImGui::GetContentRegionAvail(),ImGuiInputTextFlags_UndoRedo)) {
MARK_MODIFIED;
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_NOTES;
ImGui::End();
if (!asChild && ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_NOTES;
if (asChild) {
ImGui::EndChild();
} else {
ImGui::End();
}
}

View file

@ -1969,6 +1969,8 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
echoFilter[6]=flags.getInt("echoFilter6",0);
echoFilter[7]=flags.getInt("echoFilter7",0);
bool interpolationOff=flags.getBool("interpolationOff",false);
ImGui::Text(_("Volume scale:"));
if (CWSliderInt(_("Left##VolScaleL"),&vsL,0,127)) {
if (vsL<0) vsL=0;
@ -2084,6 +2086,10 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
ImGui::Text(_("sum: %d"),filterSum);
ImGui::PopStyleColor();
if (ImGui::Checkbox(_("Disable Gaussian interpolation"),&interpolationOff)) {
altered=true;
}
if (altered) {
e->lockSave([&]() {
flags.set("volScaleL",127-vsL);
@ -2102,6 +2108,7 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
flags.set("echoFilter6",echoFilter[6]);
flags.set("echoFilter7",echoFilter[7]);
flags.set("echoMask",echoMask);
flags.set("interpolationOff",interpolationOff);
});
}

View file

@ -102,7 +102,7 @@ void FurnaceGUI::drawSysManager() {
ImGui::SameLine();
ImGui::Button(_("Change##SysChange"));
if (ImGui::BeginPopupContextItem("SysPickerC",ImGuiPopupFlags_MouseButtonLeft)) {
DivSystem picked=systemPicker();
DivSystem picked=systemPicker(false);
if (picked!=DIV_SYSTEM_NULL) {
if (e->changeSystem(i,picked,preserveChanPos)) {
MARK_MODIFIED;
@ -138,7 +138,7 @@ void FurnaceGUI::drawSysManager() {
ImGui::TableNextColumn();
ImGui::Button(ICON_FA_PLUS "##SysAdd");
if (ImGui::BeginPopupContextItem("SysPickerA",ImGuiPopupFlags_MouseButtonLeft)) {
DivSystem picked=systemPicker();
DivSystem picked=systemPicker(false);
if (picked!=DIV_SYSTEM_NULL) {
if (!e->addSystem(picked)) {
showError(fmt::sprintf(_("cannot add chip! (%s)"),e->getLastError()));

View file

@ -23,7 +23,7 @@
#include "guiConst.h"
#include <imgui.h>
DivSystem FurnaceGUI::systemPicker() {
DivSystem FurnaceGUI::systemPicker(bool fullWidth) {
DivSystem ret=DIV_SYSTEM_NULL;
DivSystem hoveredSys=DIV_SYSTEM_NULL;
bool reissueSearch=false;
@ -61,7 +61,7 @@ DivSystem FurnaceGUI::systemPicker() {
}
}
}
if (ImGui::BeginTable("SysList",1,ImGuiTableFlags_ScrollY,ImVec2(500.0f*dpiScale,200.0*dpiScale))) {
if (ImGui::BeginTable("SysList",1,ImGuiTableFlags_ScrollY,ImVec2(fullWidth ? ImGui::GetContentRegionAvail().x : 500.0f*dpiScale,200.0f*dpiScale))) {
if (sysSearchQuery.empty()) {
// display chip list
for (int j=0; curSysSection[j]; j++) {

View file

@ -392,7 +392,7 @@ void FurnaceGUI::drawUserPresets() {
tempID=fmt::sprintf("%s##USystem",getSystemName(chip.sys));
ImGui::Button(tempID.c_str(),ImVec2(ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize(_("Invert")).x-ImGui::GetFrameHeightWithSpacing()*2.0-ImGui::GetStyle().ItemSpacing.x*2.0,0));
if (ImGui::BeginPopupContextItem("SysPickerCU",ImGuiPopupFlags_MouseButtonLeft)) {
DivSystem picked=systemPicker();
DivSystem picked=systemPicker(false);
if (picked!=DIV_SYSTEM_NULL) {
chip.sys=picked;
mustBake=true;
@ -456,7 +456,7 @@ void FurnaceGUI::drawUserPresets() {
ImGui::Button(ICON_FA_PLUS "##SysAddU");
if (ImGui::BeginPopupContextItem("SysPickerU",ImGuiPopupFlags_MouseButtonLeft)) {
DivSystem picked=systemPicker();
DivSystem picked=systemPicker(false);
if (picked!=DIV_SYSTEM_NULL) {
preset->orig.push_back(FurnaceGUISysDefChip(picked,1.0f,0.0f,""));
mustBake=true;