diff --git a/TODO.md b/TODO.md index 3002ac7c..1c754923 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,6 @@ # to-do for 0.6pre1 -- finish ExtCh on OPN/OPNA +- finish ExtCh on OPNA - RF5C68 system - ZX beeper system overlay percussion - ADPCM chips diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index b567803b..5c33d9e4 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2206,6 +2206,21 @@ void FurnaceGUI::editOptions(bool topMenu) { } } +void FurnaceGUI::toggleMobileUI(bool enable, bool force) { + if (mobileUI!=enable || force) { + if (!mobileUI && enable) { + ImGui::SaveIniSettingsToDisk(finalLayoutPath); + } + mobileUI=enable; + if (mobileUI) { + ImGui::GetIO().IniFilename=NULL; + } else { + ImGui::GetIO().IniFilename=finalLayoutPath; + ImGui::LoadIniSettingsFromDisk(finalLayoutPath); + } + } +} + int _processEvent(void* instance, SDL_Event* event) { return ((FurnaceGUI*)instance)->processEvent(event); } @@ -2711,321 +2726,363 @@ bool FurnaceGUI::loop() { curWindow=GUI_WINDOW_NOTHING; editOptsVisible=false; - ImGui::BeginMainMenuBar(); - if (ImGui::BeginMenu("file")) { - if (ImGui::MenuItem("new...")) { - if (modified) { - showWarning("Unsaved changes! Save changes before creating a new song?",GUI_WARN_NEW); - } else { - displayNew=true; + if (!mobileUI) { + ImGui::BeginMainMenuBar(); + if (ImGui::BeginMenu("file")) { + if (ImGui::MenuItem("new...")) { + if (modified) { + showWarning("Unsaved changes! Save changes before creating a new song?",GUI_WARN_NEW); + } else { + displayNew=true; + } } - } - if (ImGui::MenuItem("open...",BIND_FOR(GUI_ACTION_OPEN))) { - if (modified) { - showWarning("Unsaved changes! Save changes before opening another file?",GUI_WARN_OPEN); - } else { - openFileDialog(GUI_FILE_OPEN); + if (ImGui::MenuItem("open...",BIND_FOR(GUI_ACTION_OPEN))) { + if (modified) { + showWarning("Unsaved changes! Save changes before opening another file?",GUI_WARN_OPEN); + } else { + openFileDialog(GUI_FILE_OPEN); + } } - } - ImGui::Separator(); - if (ImGui::MenuItem("save",BIND_FOR(GUI_ACTION_SAVE))) { - if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { + ImGui::Separator(); + if (ImGui::MenuItem("save",BIND_FOR(GUI_ACTION_SAVE))) { + if (curFileName=="" || curFileName==backupPath || e->song.version>=0xff00) { + openFileDialog(GUI_FILE_SAVE); + } else { + if (save(curFileName,e->song.isDMF?e->song.version:0)>0) { + showError(fmt::sprintf("Error while saving file! (%s)",lastError)); + } + } + } + if (ImGui::MenuItem("save as...",BIND_FOR(GUI_ACTION_SAVE_AS))) { openFileDialog(GUI_FILE_SAVE); - } else { - if (save(curFileName,e->song.isDMF?e->song.version:0)>0) { - showError(fmt::sprintf("Error while saving file! (%s)",lastError)); + } + if (ImGui::MenuItem("save as .dmf (1.0/legacy)...",BIND_FOR(GUI_ACTION_SAVE_AS))) { + openFileDialog(GUI_FILE_SAVE_DMF_LEGACY); + } + ImGui::Separator(); + if (ImGui::BeginMenu("export audio...")) { + if (ImGui::MenuItem("one file")) { + openFileDialog(GUI_FILE_EXPORT_AUDIO_ONE); } + if (ImGui::MenuItem("multiple files (one per system)")) { + openFileDialog(GUI_FILE_EXPORT_AUDIO_PER_SYS); + } + if (ImGui::MenuItem("multiple files (one per channel)")) { + openFileDialog(GUI_FILE_EXPORT_AUDIO_PER_CHANNEL); + } + if (ImGui::InputInt("Loops",&exportLoops,1,2)) { + if (exportLoops<0) exportLoops=0; + } + ImGui::EndMenu(); } - } - if (ImGui::MenuItem("save as...",BIND_FOR(GUI_ACTION_SAVE_AS))) { - openFileDialog(GUI_FILE_SAVE); - } - if (ImGui::MenuItem("save as .dmf (1.0/legacy)...",BIND_FOR(GUI_ACTION_SAVE_AS))) { - openFileDialog(GUI_FILE_SAVE_DMF_LEGACY); - } - ImGui::Separator(); - if (ImGui::BeginMenu("export audio...")) { - if (ImGui::MenuItem("one file")) { - openFileDialog(GUI_FILE_EXPORT_AUDIO_ONE); - } - if (ImGui::MenuItem("multiple files (one per system)")) { - openFileDialog(GUI_FILE_EXPORT_AUDIO_PER_SYS); - } - if (ImGui::MenuItem("multiple files (one per channel)")) { - openFileDialog(GUI_FILE_EXPORT_AUDIO_PER_CHANNEL); - } - if (ImGui::InputInt("Loops",&exportLoops,1,2)) { - if (exportLoops<0) exportLoops=0; - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("export VGM...")) { - ImGui::Text("settings:"); - if (ImGui::BeginCombo("format version",fmt::sprintf("%d.%.2x",vgmExportVersion>>8,vgmExportVersion&0xff).c_str())) { - for (int i=0; i<6; i++) { - if (ImGui::Selectable(fmt::sprintf("%d.%.2x",vgmVersions[i]>>8,vgmVersions[i]&0xff).c_str(),vgmExportVersion==vgmVersions[i])) { - vgmExportVersion=vgmVersions[i]; + if (ImGui::BeginMenu("export VGM...")) { + ImGui::Text("settings:"); + if (ImGui::BeginCombo("format version",fmt::sprintf("%d.%.2x",vgmExportVersion>>8,vgmExportVersion&0xff).c_str())) { + for (int i=0; i<6; i++) { + if (ImGui::Selectable(fmt::sprintf("%d.%.2x",vgmVersions[i]>>8,vgmVersions[i]&0xff).c_str(),vgmExportVersion==vgmVersions[i])) { + vgmExportVersion=vgmVersions[i]; + } + } + ImGui::EndCombo(); + } + ImGui::Checkbox("loop",&vgmExportLoop); + ImGui::Text("systems to export:"); + bool hasOneAtLeast=false; + for (int i=0; isong.systemLen; i++) { + int minVersion=e->minVGMVersion(e->song.system[i]); + ImGui::BeginDisabled(minVersion>vgmExportVersion || minVersion==0); + ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i]); + ImGui::EndDisabled(); + if (minVersion>vgmExportVersion) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { + ImGui::SetTooltip("this system is only available in VGM %d.%.2x and higher!",minVersion>>8,minVersion&0xff); + } + } else if (minVersion==0) { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { + ImGui::SetTooltip("this system is not supported by the VGM format!"); + } + } else { + if (willExport[i]) hasOneAtLeast=true; } } - ImGui::EndCombo(); - } - ImGui::Checkbox("loop",&vgmExportLoop); - ImGui::Text("systems to export:"); - bool hasOneAtLeast=false; - for (int i=0; isong.systemLen; i++) { - int minVersion=e->minVGMVersion(e->song.system[i]); - ImGui::BeginDisabled(minVersion>vgmExportVersion || minVersion==0); - ImGui::Checkbox(fmt::sprintf("%d. %s##_SYSV%d",i+1,getSystemName(e->song.system[i]),i).c_str(),&willExport[i]); - ImGui::EndDisabled(); - if (minVersion>vgmExportVersion) { - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { - ImGui::SetTooltip("this system is only available in VGM %d.%.2x and higher!",minVersion>>8,minVersion&0xff); - } - } else if (minVersion==0) { - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { - ImGui::SetTooltip("this system is not supported by the VGM format!"); + ImGui::Text("select the systems you wish to export,"); + ImGui::Text("but only up to %d of each type.",(vgmExportVersion>=0x151)?2:1); + if (hasOneAtLeast) { + if (ImGui::MenuItem("click to export")) { + openFileDialog(GUI_FILE_EXPORT_VGM); } } else { - if (willExport[i]) hasOneAtLeast=true; + ImGui::Text("nothing to export"); } + ImGui::EndMenu(); } - ImGui::Text("select the systems you wish to export,"); - ImGui::Text("but only up to %d of each type.",(vgmExportVersion>=0x151)?2:1); - if (hasOneAtLeast) { - if (ImGui::MenuItem("click to export")) { - openFileDialog(GUI_FILE_EXPORT_VGM); + ImGui::Separator(); + if (ImGui::BeginMenu("add system...")) { + for (int j=0; availableSystems[j]; j++) { + if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY || availableSystems[j]==DIV_SYSTEM_SOUND_UNIT)) continue; + sysAddOption((DivSystem)availableSystems[j]); } - } else { - ImGui::Text("nothing to export"); + ImGui::EndMenu(); } - ImGui::EndMenu(); - } - ImGui::Separator(); - if (ImGui::BeginMenu("add system...")) { - for (int j=0; availableSystems[j]; j++) { - if (!settings.hiddenSystems && (availableSystems[j]==DIV_SYSTEM_YMU759 || availableSystems[j]==DIV_SYSTEM_DUMMY || availableSystems[j]==DIV_SYSTEM_SOUND_UNIT)) continue; - sysAddOption((DivSystem)availableSystems[j]); - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("configure system...")) { - for (int i=0; isong.systemLen; i++) { - if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSP%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::EndMenu(); - } - if (ImGui::BeginMenu("change system...")) { - ImGui::Checkbox("Preserve channel positions",&preserveChanPos); - for (int i=0; isong.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 || availableSystems[j]==DIV_SYSTEM_SOUND_UNIT)) continue; - sysChangeOption(i,(DivSystem)availableSystems[j]); - } - ImGui::EndMenu(); - } - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("remove system...")) { - ImGui::Checkbox("Preserve channel positions",&preserveChanPos); - for (int i=0; isong.systemLen; i++) { - if (ImGui::MenuItem(fmt::sprintf("%d. %s##_SYSR%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { - if (!e->removeSystem(i,preserveChanPos)) { - showError("cannot remove system! ("+e->getLastError()+")"); + if (ImGui::BeginMenu("configure system...")) { + for (int i=0; isong.systemLen; i++) { + if (ImGui::TreeNode(fmt::sprintf("%d. %s##_SYSP%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::EndMenu(); + } + if (ImGui::BeginMenu("change system...")) { + ImGui::Checkbox("Preserve channel positions",&preserveChanPos); + for (int i=0; isong.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 || availableSystems[j]==DIV_SYSTEM_SOUND_UNIT)) continue; + sysChangeOption(i,(DivSystem)availableSystems[j]); + } + ImGui::EndMenu(); + } + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("remove system...")) { + ImGui::Checkbox("Preserve channel positions",&preserveChanPos); + for (int i=0; isong.systemLen; i++) { + if (ImGui::MenuItem(fmt::sprintf("%d. %s##_SYSR%d",i+1,getSystemName(e->song.system[i]),i).c_str())) { + if (!e->removeSystem(i,preserveChanPos)) { + showError("cannot remove system! ("+e->getLastError()+")"); + } + } + } + ImGui::EndMenu(); + } + ImGui::Separator(); + if (ImGui::MenuItem("restore backup",BIND_FOR(GUI_ACTION_OPEN_BACKUP))) { + doAction(GUI_ACTION_OPEN_BACKUP); + } + ImGui::Separator(); + if (ImGui::MenuItem("exit")) { + if (modified) { + showWarning("Unsaved changes! Save before quitting?",GUI_WARN_QUIT); + } else { + quit=true; + } } ImGui::EndMenu(); } - ImGui::Separator(); - if (ImGui::MenuItem("restore backup",BIND_FOR(GUI_ACTION_OPEN_BACKUP))) { - doAction(GUI_ACTION_OPEN_BACKUP); + if (ImGui::BeginMenu("edit")) { + if (ImGui::MenuItem("undo",BIND_FOR(GUI_ACTION_UNDO))) doUndo(); + if (ImGui::MenuItem("redo",BIND_FOR(GUI_ACTION_REDO))) doRedo(); + ImGui::Separator(); + editOptions(true); + ImGui::Separator(); + if (ImGui::MenuItem("clear...")) { + showWarning("Are you sure you want to clear... (cannot be undone!)",GUI_WARN_CLEAR); + } + ImGui::EndMenu(); } - ImGui::Separator(); - if (ImGui::MenuItem("exit")) { - if (modified) { - showWarning("Unsaved changes! Save before quitting?",GUI_WARN_QUIT); - } else { - quit=true; + if (ImGui::BeginMenu("settings")) { + #ifndef IS_MOBILE + if (ImGui::MenuItem("full screen",BIND_FOR(GUI_ACTION_FULLSCREEN),fullScreen)) { + doAction(GUI_ACTION_FULLSCREEN); + } + #endif + if (ImGui::MenuItem("lock layout (not working!)",NULL,lockLayout)) { + lockLayout=!lockLayout; + } + if (ImGui::MenuItem("visualizer",NULL,fancyPattern)) { + fancyPattern=!fancyPattern; + e->enableCommandStream(fancyPattern); + e->getCommandStream(cmdStream); + cmdStream.clear(); + } + if (ImGui::MenuItem("reset layout")) { + showWarning("Are you sure you want to reset the workspace layout?",GUI_WARN_RESET_LAYOUT); + } + if (ImGui::MenuItem("settings...",BIND_FOR(GUI_ACTION_WINDOW_SETTINGS))) { + syncSettings(); + settingsOpen=true; + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("window")) { + if (ImGui::MenuItem("song information",BIND_FOR(GUI_ACTION_WINDOW_SONG_INFO),songInfoOpen)) songInfoOpen=!songInfoOpen; + if (ImGui::MenuItem("subsongs",BIND_FOR(GUI_ACTION_WINDOW_SUBSONGS),subSongsOpen)) subSongsOpen=!subSongsOpen; + if (ImGui::MenuItem("instruments",BIND_FOR(GUI_ACTION_WINDOW_INS_LIST),insListOpen)) insListOpen=!insListOpen; + if (ImGui::MenuItem("wavetables",BIND_FOR(GUI_ACTION_WINDOW_WAVE_LIST),waveListOpen)) waveListOpen=!waveListOpen; + if (ImGui::MenuItem("samples",BIND_FOR(GUI_ACTION_WINDOW_SAMPLE_LIST),sampleListOpen)) sampleListOpen=!sampleListOpen; + if (ImGui::MenuItem("orders",BIND_FOR(GUI_ACTION_WINDOW_ORDERS),ordersOpen)) ordersOpen=!ordersOpen; + 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("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(); + if (ImGui::MenuItem("instrument editor",BIND_FOR(GUI_ACTION_WINDOW_INS_EDIT),insEditOpen)) insEditOpen=!insEditOpen; + if (ImGui::MenuItem("wavetable editor",BIND_FOR(GUI_ACTION_WINDOW_WAVE_EDIT),waveEditOpen)) waveEditOpen=!waveEditOpen; + if (ImGui::MenuItem("sample editor",BIND_FOR(GUI_ACTION_WINDOW_SAMPLE_EDIT),sampleEditOpen)) sampleEditOpen=!sampleEditOpen; + ImGui::Separator(); + if (ImGui::MenuItem("play/edit controls",BIND_FOR(GUI_ACTION_WINDOW_EDIT_CONTROLS),editControlsOpen)) editControlsOpen=!editControlsOpen; + if (ImGui::MenuItem("piano/input pad",BIND_FOR(GUI_ACTION_WINDOW_PIANO),pianoOpen)) pianoOpen=!pianoOpen; + if (ImGui::MenuItem("oscilloscope (master)",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen; + if (ImGui::MenuItem("oscilloscope (per-channel)",BIND_FOR(GUI_ACTION_WINDOW_CHAN_OSC),chanOscOpen)) chanOscOpen=!chanOscOpen; + if (ImGui::MenuItem("volume meter",BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen; + if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen; + if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen; + if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; + + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("help")) { + if (ImGui::MenuItem("effect list",BIND_FOR(GUI_ACTION_WINDOW_EFFECT_LIST),effectListOpen)) effectListOpen=!effectListOpen; + if (ImGui::MenuItem("debug menu",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) debugOpen=!debugOpen; + if (ImGui::MenuItem("panic",BIND_FOR(GUI_ACTION_PANIC))) e->syncReset(); + if (ImGui::MenuItem("about...",BIND_FOR(GUI_ACTION_WINDOW_ABOUT))) { + aboutOpen=true; + aboutScroll=0; + } + ImGui::EndMenu(); + } + ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PLAYBACK_STAT]); + if (e->isPlaying()) { + int totalTicks=e->getTotalTicks(); + int totalSeconds=e->getTotalSeconds(); + ImGui::Text("| Speed %d:%d @ %gHz (%g BPM) | Order %d/%d | Row %d/%d | %d:%.2d:%.2d.%.2d",e->getSpeed1(),e->getSpeed2(),e->getCurHz(),calcBPM(e->getSpeed1(),e->getSpeed2(),e->getCurHz(),e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD),e->getOrder(),e->curSubSong->ordersLen,e->getRow(),e->curSubSong->patLen,totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000); + } else { + bool hasInfo=false; + String info; + if (cursor.xCoarse>=0 && cursor.xCoarsegetTotalChannelCount()) { + DivPattern* p=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],false); + if (cursor.xFine>=0) switch (cursor.xFine) { + case 0: // note + if (p->data[cursor.y][0]>0) { + if (p->data[cursor.y][0]==100) { + info=fmt::sprintf("Note off (cut)"); + } else if (p->data[cursor.y][0]==101) { + info=fmt::sprintf("Note off (release)"); + } else if (p->data[cursor.y][0]==102) { + info=fmt::sprintf("Macro release only"); + } else { + info=fmt::sprintf("Note on: %s",noteName(p->data[cursor.y][0],p->data[cursor.y][1])); + } + hasInfo=true; + } + break; + case 1: // instrument + if (p->data[cursor.y][2]>-1) { + if (p->data[cursor.y][2]>=(int)e->song.ins.size()) { + info=fmt::sprintf("Ins %d: ",p->data[cursor.y][2]); + } else { + DivInstrument* ins=e->getIns(p->data[cursor.y][2]); + info=fmt::sprintf("Ins %d: %s",p->data[cursor.y][2],ins->name); + } + hasInfo=true; + } + break; + case 2: // volume + if (p->data[cursor.y][3]>-1) { + int maxVol=e->getMaxVolumeChan(cursor.xCoarse); + if (maxVol<1 || p->data[cursor.y][3]>maxVol) { + info=fmt::sprintf("Set volume: %d (%.2X, INVALID!)",p->data[cursor.y][3],p->data[cursor.y][3]); + } else { + info=fmt::sprintf("Set volume: %d (%.2X, %d%%)",p->data[cursor.y][3],p->data[cursor.y][3],(p->data[cursor.y][3]*100)/maxVol); + } + hasInfo=true; + } + break; + default: // effect + int actualCursor=((cursor.xFine+1)&(~1)); + if (p->data[cursor.y][actualCursor]>-1) { + info=e->getEffectDesc(p->data[cursor.y][actualCursor],cursor.xCoarse,true); + hasInfo=true; + } + break; + } + } + if (hasInfo && (settings.statusDisplay==0 || settings.statusDisplay==2)) { + ImGui::Text("| %s",info.c_str()); + } else if (settings.statusDisplay==1 || settings.statusDisplay==2) { + if (curFileName!="") ImGui::Text("| %s",curFileName.c_str()); } } - ImGui::EndMenu(); + ImGui::PopStyleColor(); + if (modified) { + ImGui::Text("| modified"); + } + ImGui::EndMainMenuBar(); } - if (ImGui::BeginMenu("edit")) { - if (ImGui::MenuItem("undo",BIND_FOR(GUI_ACTION_UNDO))) doUndo(); - if (ImGui::MenuItem("redo",BIND_FOR(GUI_ACTION_REDO))) doRedo(); - ImGui::Separator(); - editOptions(true); - ImGui::Separator(); - if (ImGui::MenuItem("clear...")) { - showWarning("Are you sure you want to clear... (cannot be undone!)",GUI_WARN_CLEAR); - } - ImGui::EndMenu(); + + if (!mobileUI) { + ImGui::DockSpaceOverViewport(NULL,lockLayout?(ImGuiDockNodeFlags_NoResize|ImGuiDockNodeFlags_NoCloseButton|ImGuiDockNodeFlags_NoDocking|ImGuiDockNodeFlags_NoDockingSplitMe|ImGuiDockNodeFlags_NoDockingSplitOther):0); } - if (ImGui::BeginMenu("settings")) { -#ifndef IS_MOBILE - if (ImGui::MenuItem("full screen",BIND_FOR(GUI_ACTION_FULLSCREEN),fullScreen)) { - doAction(GUI_ACTION_FULLSCREEN); + + if (mobileUI) { + ImGuiViewport* mainView=ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(mainView->Pos); + ImGui::SetNextWindowSize(mainView->Size); + ImGui::SetNextWindowViewport(mainView->ID); + ImGuiID dockID=ImGui::GetID("MobileUISpace"); + ImGuiWindowFlags muiFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoCollapse|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoDocking|ImGuiWindowFlags_NoBringToFrontOnFocus|ImGuiWindowFlags_NoNavFocus; + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + ImGui::Begin("MobileUI",NULL,muiFlags); + ImGui::PopStyleVar(3); + if (ImGui::DockBuilderGetNode(dockID)==NULL) { + ImGui::DockBuilderRemoveNode(dockID); + ImGuiID dn=ImGui::DockBuilderAddNode(dockID); + ImGuiID upper, lower, left, right; + ImGui::DockBuilderSplitNode(dn,ImGuiDir_Left,0.1f,&left,&right); + ImGui::DockBuilderSplitNode(right,ImGuiDir_Down,0.2f,&lower,&upper); + ImGui::DockBuilderDockWindow("Mobile Controls",left); + ImGui::DockBuilderDockWindow("Pattern",upper); + ImGui::DockBuilderDockWindow("Piano",lower); + ImGui::DockBuilderFinish(dn); } -#endif - if (ImGui::MenuItem("lock layout (not working!)",NULL,lockLayout)) { - lockLayout=!lockLayout; + ImGui::DockSpace(dockID); + ImGui::End(); + + if (ImGui::Begin("Mobile Controls")) { + ImGui::Text("Hi!"); + if (ImGui::Button("Get me out of here")) { + toggleMobileUI(false); + } } - if (ImGui::MenuItem("visualizer",NULL,fancyPattern)) { - fancyPattern=!fancyPattern; - e->enableCommandStream(fancyPattern); - e->getCommandStream(cmdStream); - cmdStream.clear(); - } - if (ImGui::MenuItem("reset layout")) { - showWarning("Are you sure you want to reset the workspace layout?",GUI_WARN_RESET_LAYOUT); - } - if (ImGui::MenuItem("settings...",BIND_FOR(GUI_ACTION_WINDOW_SETTINGS))) { - syncSettings(); - settingsOpen=true; - } - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("window")) { - if (ImGui::MenuItem("song information",BIND_FOR(GUI_ACTION_WINDOW_SONG_INFO),songInfoOpen)) songInfoOpen=!songInfoOpen; - if (ImGui::MenuItem("subsongs",BIND_FOR(GUI_ACTION_WINDOW_SUBSONGS),subSongsOpen)) subSongsOpen=!subSongsOpen; - if (ImGui::MenuItem("instruments",BIND_FOR(GUI_ACTION_WINDOW_INS_LIST),insListOpen)) insListOpen=!insListOpen; - if (ImGui::MenuItem("wavetables",BIND_FOR(GUI_ACTION_WINDOW_WAVE_LIST),waveListOpen)) waveListOpen=!waveListOpen; - if (ImGui::MenuItem("samples",BIND_FOR(GUI_ACTION_WINDOW_SAMPLE_LIST),sampleListOpen)) sampleListOpen=!sampleListOpen; - if (ImGui::MenuItem("orders",BIND_FOR(GUI_ACTION_WINDOW_ORDERS),ordersOpen)) ordersOpen=!ordersOpen; - 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("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(); - if (ImGui::MenuItem("instrument editor",BIND_FOR(GUI_ACTION_WINDOW_INS_EDIT),insEditOpen)) insEditOpen=!insEditOpen; - if (ImGui::MenuItem("wavetable editor",BIND_FOR(GUI_ACTION_WINDOW_WAVE_EDIT),waveEditOpen)) waveEditOpen=!waveEditOpen; - if (ImGui::MenuItem("sample editor",BIND_FOR(GUI_ACTION_WINDOW_SAMPLE_EDIT),sampleEditOpen)) sampleEditOpen=!sampleEditOpen; - ImGui::Separator(); - if (ImGui::MenuItem("play/edit controls",BIND_FOR(GUI_ACTION_WINDOW_EDIT_CONTROLS),editControlsOpen)) editControlsOpen=!editControlsOpen; - if (ImGui::MenuItem("piano/input pad",BIND_FOR(GUI_ACTION_WINDOW_PIANO),pianoOpen)) pianoOpen=!pianoOpen; - if (ImGui::MenuItem("oscilloscope (master)",BIND_FOR(GUI_ACTION_WINDOW_OSCILLOSCOPE),oscOpen)) oscOpen=!oscOpen; - if (ImGui::MenuItem("oscilloscope (per-channel)",BIND_FOR(GUI_ACTION_WINDOW_CHAN_OSC),chanOscOpen)) chanOscOpen=!chanOscOpen; - if (ImGui::MenuItem("volume meter",BIND_FOR(GUI_ACTION_WINDOW_VOL_METER),volMeterOpen)) volMeterOpen=!volMeterOpen; - if (ImGui::MenuItem("register view",BIND_FOR(GUI_ACTION_WINDOW_REGISTER_VIEW),regViewOpen)) regViewOpen=!regViewOpen; - if (ImGui::MenuItem("log viewer",BIND_FOR(GUI_ACTION_WINDOW_LOG),logOpen)) logOpen=!logOpen; - if (ImGui::MenuItem("statistics",BIND_FOR(GUI_ACTION_WINDOW_STATS),statsOpen)) statsOpen=!statsOpen; - - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("help")) { - if (ImGui::MenuItem("effect list",BIND_FOR(GUI_ACTION_WINDOW_EFFECT_LIST),effectListOpen)) effectListOpen=!effectListOpen; - if (ImGui::MenuItem("debug menu",BIND_FOR(GUI_ACTION_WINDOW_DEBUG))) debugOpen=!debugOpen; - if (ImGui::MenuItem("panic",BIND_FOR(GUI_ACTION_PANIC))) e->syncReset(); - if (ImGui::MenuItem("about...",BIND_FOR(GUI_ACTION_WINDOW_ABOUT))) { - aboutOpen=true; - aboutScroll=0; - } - ImGui::EndMenu(); - } - ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PLAYBACK_STAT]); - if (e->isPlaying()) { - int totalTicks=e->getTotalTicks(); - int totalSeconds=e->getTotalSeconds(); - ImGui::Text("| Speed %d:%d @ %gHz (%g BPM) | Order %d/%d | Row %d/%d | %d:%.2d:%.2d.%.2d",e->getSpeed1(),e->getSpeed2(),e->getCurHz(),calcBPM(e->getSpeed1(),e->getSpeed2(),e->getCurHz(),e->curSubSong->virtualTempoN,e->curSubSong->virtualTempoD),e->getOrder(),e->curSubSong->ordersLen,e->getRow(),e->curSubSong->patLen,totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000); + ImGui::End(); + + drawPattern(); + drawPiano(); } else { - bool hasInfo=false; - String info; - if (cursor.xCoarse>=0 && cursor.xCoarsegetTotalChannelCount()) { - DivPattern* p=e->curPat[cursor.xCoarse].getPattern(e->curOrders->ord[cursor.xCoarse][curOrder],false); - if (cursor.xFine>=0) switch (cursor.xFine) { - case 0: // note - if (p->data[cursor.y][0]>0) { - if (p->data[cursor.y][0]==100) { - info=fmt::sprintf("Note off (cut)"); - } else if (p->data[cursor.y][0]==101) { - info=fmt::sprintf("Note off (release)"); - } else if (p->data[cursor.y][0]==102) { - info=fmt::sprintf("Macro release only"); - } else { - info=fmt::sprintf("Note on: %s",noteName(p->data[cursor.y][0],p->data[cursor.y][1])); - } - hasInfo=true; - } - break; - case 1: // instrument - if (p->data[cursor.y][2]>-1) { - if (p->data[cursor.y][2]>=(int)e->song.ins.size()) { - info=fmt::sprintf("Ins %d: ",p->data[cursor.y][2]); - } else { - DivInstrument* ins=e->getIns(p->data[cursor.y][2]); - info=fmt::sprintf("Ins %d: %s",p->data[cursor.y][2],ins->name); - } - hasInfo=true; - } - break; - case 2: // volume - if (p->data[cursor.y][3]>-1) { - int maxVol=e->getMaxVolumeChan(cursor.xCoarse); - if (maxVol<1 || p->data[cursor.y][3]>maxVol) { - info=fmt::sprintf("Set volume: %d (%.2X, INVALID!)",p->data[cursor.y][3],p->data[cursor.y][3]); - } else { - info=fmt::sprintf("Set volume: %d (%.2X, %d%%)",p->data[cursor.y][3],p->data[cursor.y][3],(p->data[cursor.y][3]*100)/maxVol); - } - hasInfo=true; - } - break; - default: // effect - int actualCursor=((cursor.xFine+1)&(~1)); - if (p->data[cursor.y][actualCursor]>-1) { - info=e->getEffectDesc(p->data[cursor.y][actualCursor],cursor.xCoarse,true); - hasInfo=true; - } - break; - } - } - if (hasInfo && (settings.statusDisplay==0 || settings.statusDisplay==2)) { - ImGui::Text("| %s",info.c_str()); - } else if (settings.statusDisplay==1 || settings.statusDisplay==2) { - if (curFileName!="") ImGui::Text("| %s",curFileName.c_str()); - } + drawSubSongs(); + drawPattern(); + drawEditControls(); + drawSongInfo(); + drawOrders(); + drawSampleList(); + drawSampleEdit(); + drawWaveList(); + drawWaveEdit(); + drawInsList(); + drawInsEdit(); + drawMixer(); + + readOsc(); + + drawOsc(); + drawChanOsc(); + drawVolMeter(); + drawSettings(); + drawDebug(); + drawStats(); + drawCompatFlags(); + drawPiano(); + drawNotes(); + drawChannels(); + drawRegView(); + drawLog(); + drawEffectList(); } - ImGui::PopStyleColor(); - if (modified) { - ImGui::Text("| modified"); - } - ImGui::EndMainMenuBar(); - - ImGui::DockSpaceOverViewport(NULL,lockLayout?(ImGuiDockNodeFlags_NoResize|ImGuiDockNodeFlags_NoCloseButton|ImGuiDockNodeFlags_NoDocking|ImGuiDockNodeFlags_NoDockingSplitMe|ImGuiDockNodeFlags_NoDockingSplitOther):0); - - drawSubSongs(); - drawPattern(); - drawEditControls(); - drawSongInfo(); - drawOrders(); - drawSampleList(); - drawSampleEdit(); - drawWaveList(); - drawWaveEdit(); - drawInsList(); - drawInsEdit(); - drawMixer(); - - readOsc(); - - drawOsc(); - drawChanOsc(); - drawVolMeter(); - drawSettings(); - drawDebug(); - drawStats(); - drawCompatFlags(); - drawPiano(); - drawNotes(); - drawChannels(); - drawRegView(); - drawLog(); - drawEffectList(); if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); @@ -3543,8 +3600,10 @@ bool FurnaceGUI::loop() { case GUI_WARN_RESET_LAYOUT: if (ImGui::Button("Yes")) { ImGui::CloseCurrentPopup(); - ImGui::LoadIniSettingsFromMemory(defaultLayout); - ImGui::SaveIniSettingsToDisk(finalLayoutPath); + if (!mobileUI) { + ImGui::LoadIniSettingsFromMemory(defaultLayout); + ImGui::SaveIniSettingsToDisk(finalLayoutPath); + } } ImGui::SameLine(); if (ImGui::Button("No")) { @@ -3943,8 +4002,7 @@ bool FurnaceGUI::init() { prepareLayout(); ImGui::GetIO().ConfigFlags|=ImGuiConfigFlags_DockingEnable; - ImGui::GetIO().IniFilename=finalLayoutPath; - ImGui::LoadIniSettingsFromDisk(finalLayoutPath); + toggleMobileUI(mobileUI,true); updateWindowTitle(); @@ -3972,7 +4030,9 @@ bool FurnaceGUI::init() { } bool FurnaceGUI::finish() { - ImGui::SaveIniSettingsToDisk(finalLayoutPath); + if (!mobileUI) { + ImGui::SaveIniSettingsToDisk(finalLayoutPath); + } ImGui_ImplSDLRenderer_Shutdown(); ImGui_ImplSDL2_Shutdown(); ImGui::DestroyContext(); diff --git a/src/gui/gui.h b/src/gui/gui.h index a99ee90a..b1384170 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -806,7 +806,7 @@ class FurnaceGUI { String workingDir, fileName, clipboard, warnString, errorString, lastError, curFileName, nextFile; String workingDirSong, workingDirIns, workingDirWave, workingDirSample, workingDirAudioExport, workingDirVGMExport, workingDirFont, workingDirColors, workingDirKeybinds, workingDirLayout, workingDirROM; - String mmlString[17]; + String mmlString[32]; String mmlStringW; bool quit, warnQuit, willCommit, edit, modified, displayError, displayExporting, vgmExportLoop, wantCaptureKeyboard, oldWantCaptureKeyboard, displayMacroMenu; @@ -1264,6 +1264,8 @@ class FurnaceGUI { void actualWaveList(); void actualSampleList(); + void toggleMobileUI(bool enable, bool force=false); + void drawEditControls(); void drawSongInfo(); void drawOrders(); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 983e3b33..03746c51 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1139,13 +1139,6 @@ void FurnaceGUI::drawSettings() { settings.oplStandardWaveNames=oplStandardWaveNamesB; } - if (nonLatchNibble) { - bool hiddenSystemsB=settings.hiddenSystems; - if (ImGui::Checkbox(":smile: :star_struck: :sunglasses: :ok_hand:",&hiddenSystemsB)) { - settings.hiddenSystems=hiddenSystemsB; - } - } - bool overflowHighlightB=settings.overflowHighlight; if (ImGui::Checkbox("Overflow pattern highlights",&overflowHighlightB)) { settings.overflowHighlight=overflowHighlightB; @@ -1799,6 +1792,47 @@ void FurnaceGUI::drawSettings() { ImGui::EndChild(); ImGui::EndTabItem(); } + if (nonLatchNibble) { + // ok, so you decided to read the code. + // these are the cheat codes: + // "Debug" - toggles mobile UI + // "Nice Amiga cover of the song!" - enables hidden systems (YMU759/SoundUnit/Dummy) + if (ImGui::BeginTabItem("Cheat Codes")) { + ImVec2 settingsViewSize=ImGui::GetContentRegionAvail(); + settingsViewSize.y-=ImGui::GetFrameHeight()+ImGui::GetStyle().WindowPadding.y; + if (ImGui::BeginChild("SettingsView",settingsViewSize)) { + ImGui::Text("Enter code:"); + ImGui::InputText("##CheatCode",&mmlString[31]); + if (ImGui::Button("Submit")) { + unsigned int checker=0x11111111; + unsigned int checker1=0; + int index=0; + mmlString[30]="invalid code"; + + for (char& i: mmlString[31]) { + checker^=((unsigned int)i)<>1|(((checker)^(checker>>2)^(checker>>3)^(checker>>5))&1)<<31); + checker1<<=1; + index=(index+1)&31; + } + if (checker==0x90888b65 && checker1==0x1482) { + mmlString[30]="toggled alternate UI"; + toggleMobileUI(!mobileUI); + } + if (checker==0x5a42a113 && checker1==0xe4ef451e) { + mmlString[30]=":smile: :star_struck: :sunglasses: :ok_hand:"; + settings.hiddenSystems=!settings.hiddenSystems; + } + + mmlString[31]=""; + } + ImGui::Text("%s",mmlString[30].c_str()); + } + ImGui::EndChild(); + ImGui::EndTabItem(); + } + } ImGui::EndTabBar(); } ImGui::Separator(); @@ -2292,6 +2326,10 @@ bool FurnaceGUI::exportKeybinds(String path) { } bool FurnaceGUI::importLayout(String path) { + if (mobileUI) { + logW("but you are on the mobile UI!"); + return false; + } FILE* f=ps_fopen(path.c_str(),"rb"); if (f==NULL) { logW("error while opening keybind file for import: %s",strerror(errno)); @@ -2338,6 +2376,10 @@ bool FurnaceGUI::importLayout(String path) { } bool FurnaceGUI::exportLayout(String path) { + if (mobileUI) { + logW("but you are on the mobile UI!"); + return false; + } FILE* f=ps_fopen(path.c_str(),"wb"); if (f==NULL) { logW("error while opening layout file for export: %s",strerror(errno)); diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index 93fe14bc..4328b840 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -42,16 +42,19 @@ void FurnaceGUI::drawSongInfo() { if (ImGui::InputText("##Name",&e->song.name)) { MARK_MODIFIED updateWindowTitle(); } - if (e->song.name.size()==27) { + if (e->song.insLen==2) { unsigned int checker=0x11111111; unsigned int checker1=0; - for (int i=0; i<27; i++) { - checker^=e->song.name[i]<song.name[i]; - checker=(checker>>1|(((checker)^(checker>>2)^(checker>>3)^(checker>>5))&1)<<31); - checker1<<=1; + DivInstrument* ins=e->getIns(1); + if (ins->name.size()==15 && e->curSubSong->ordersLen==8) { + for (int i=0; i<15; i++) { + checker^=ins->name[i]<name[i]; + checker=(checker>>1|(((checker)^(checker>>2)^(checker>>3)^(checker>>5))&1)<<31); + checker1<<=1; + } + if (checker==0x5ec4497d && checker1==0x6347ee) nonLatchNibble=true; } - if (checker==0x94ffb4f7 && checker1==0x801c68a6) nonLatchNibble=true; } ImGui::TableNextRow(); ImGui::TableNextColumn();