GUI: massive code split

gui.cpp now less than 3000 lines
This commit is contained in:
tildearrow 2022-03-21 17:34:43 -05:00
parent e62f9bffd3
commit 7e5c27c5b7
28 changed files with 5201 additions and 4793 deletions

View file

@ -357,14 +357,33 @@ src/gui/fileDialog.cpp
src/gui/intConst.cpp
src/gui/guiConst.cpp
src/gui/about.cpp
src/gui/channels.cpp
src/gui/compatFlags.cpp
src/gui/cursor.cpp
src/gui/dataList.cpp
src/gui/debugWindow.cpp
src/gui/doAction.cpp
src/gui/editing.cpp
src/gui/editControls.cpp
src/gui/insEdit.cpp
src/gui/mixer.cpp
src/gui/newSong.cpp
src/gui/orders.cpp
src/gui/osc.cpp
src/gui/pattern.cpp
src/gui/piano.cpp
src/gui/presets.cpp
src/gui/regView.cpp
src/gui/sampleEdit.cpp
src/gui/settings.cpp
src/gui/songInfo.cpp
src/gui/songNotes.cpp
src/gui/stats.cpp
src/gui/sysConf.cpp
src/gui/util.cpp
src/gui/waveEdit.cpp
src/gui/volMeter.cpp
src/gui/gui.cpp
)

211
src/gui/about.cpp Normal file
View file

@ -0,0 +1,211 @@
/**
* 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"
const char* aboutLine[]={
"tildearrow",
"is proud to present",
"",
("Furnace " DIV_VERSION),
"",
"the free software chiptune tracker,",
"compatible with DefleMask modules.",
"",
"zero disassembly.",
"just clean-room design,",
"time and dedication.",
"",
"> CREDITS <",
"",
"-- program --",
"tildearrow",
"akumanatt",
"cam900",
"djtuBIG-MaliceX",
"laoo",
"superctr",
"",
"-- graphics/UI design --",
"tildearrow",
"BlastBrothers",
"",
"-- documentation --",
"tildearrow",
"freq-mod",
"nicco1690",
"DeMOSic",
"cam900",
"",
"-- demo songs --",
"0x5066",
"ActualNK358",
"breakthetargets",
"CaptainMalware",
"kleeder",
"Mahbod Karamoozian",
"nicco1690",
"NikonTeen",
"SuperJet Spade",
"TheDuccinator",
"TheRealHedgehogSonic",
"tildearrow",
"Ultraprogramer",
"",
"-- additional feedback/fixes --",
"fd",
"OPNA2608",
"plane",
"TheEssem",
"",
"powered by:",
"Dear ImGui by Omar Cornut",
"SDL2 by Sam Lantinga",
"zlib by Jean-loup Gailly",
"and Mark Adler",
"libsndfile by Erik de Castro Lopo",
"Nuked-OPM & Nuked-OPN2 by Nuke.YKT",
"ymfm by Aaron Giles",
"MAME SN76496 by Nicola Salmoria",
"MAME AY-3-8910 by Couriersud",
"with AY8930 fixes by Eulous",
"MAME SAA1099 by Juergen Buchmueller and Manuel Abadia",
"SAASound",
"SameBoy by Lior Halphon",
"Mednafen PCE",
"puNES by FHorse",
"reSID by Dag Lem",
"Stella by Stella Team",
"QSound emulator by Ian Karlsson and Valley Bell",
"",
"greetings to:",
"Delek",
"fd",
"ILLUMIDARO",
"all members of Deflers of Noice!",
"",
"copyright © 2021-2022 tildearrow",
"(and contributors).",
"licensed under GPLv2+! see",
"LICENSE for more information.",
"",
"help Furnace grow:",
"https://github.com/tildearrow/furnace",
"",
"contact tildearrow at:",
"https://tildearrow.org/?p=contact",
"",
"disclaimer:",
"despite the fact this program works",
"with the .dmf file format, it is NOT",
"affiliated with Delek or DefleMask in",
"any way, nor it is a replacement for",
"the original program.",
"",
"it also comes with ABSOLUTELY NO WARRANTY.",
"",
"thanks to all contributors/bug reporters!"
};
const size_t aboutCount=sizeof(aboutLine)/sizeof(aboutLine[0]);
void FurnaceGUI::drawAbout() {
// do stuff
if (ImGui::Begin("About Furnace",NULL,ImGuiWindowFlags_Modal|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoDocking|ImGuiWindowFlags_NoTitleBar)) {
ImGui::SetWindowPos(ImVec2(0,0));
ImGui::SetWindowSize(ImVec2(scrW*dpiScale,scrH*dpiScale));
ImGui::PushFont(bigFont);
ImDrawList* dl=ImGui::GetWindowDrawList();
float r=0;
float g=0;
float b=0;
float peakMix=settings.partyTime?((peak[0]+peak[1])*0.5):0.3;
ImGui::ColorConvertHSVtoRGB(aboutHue,1.0,0.25+MIN(0.75f,peakMix*0.75f),r,g,b);
dl->AddRectFilled(ImVec2(0,0),ImVec2(scrW*dpiScale,scrH*dpiScale),0xff000000);
bool skip=false;
bool skip2=false;
for (int i=(-80-sin(double(aboutSin)*2*M_PI/120.0)*80.0)*2; i<scrW; i+=160) {
skip2=!skip2;
skip=skip2;
for (int j=(-80-cos(double(aboutSin)*2*M_PI/150.0)*80.0)*2; j<scrH; j+=160) {
skip=!skip;
if (skip) continue;
dl->AddRectFilled(ImVec2(i*dpiScale,j*dpiScale),ImVec2((i+160)*dpiScale,(j+160)*dpiScale),ImGui::GetColorU32(ImVec4(r*0.25,g*0.25,b*0.25,1.0)));
}
}
skip=false;
skip2=false;
for (int i=(-80-cos(double(aboutSin)*2*M_PI/120.0)*80.0)*2; i<scrW; i+=160) {
skip2=!skip2;
skip=skip2;
for (int j=(-80-sin(double(aboutSin)*2*M_PI/150.0)*80.0)*2; j<scrH; j+=160) {
skip=!skip;
if (skip) continue;
dl->AddRectFilled(ImVec2(i*dpiScale,j*dpiScale),ImVec2((i+160)*dpiScale,(j+160)*dpiScale),ImGui::GetColorU32(ImVec4(r*0.5,g*0.5,b*0.5,1.0)));
}
}
skip=false;
skip2=false;
for (int i=(-160+fmod(aboutSin*2,160))*2; i<scrW; i+=160) {
skip2=!skip2;
skip=skip2;
for (int j=(-240-cos(double(aboutSin*M_PI/300.0))*240.0)*2; j<scrH; j+=160) {
skip=!skip;
if (skip) continue;
dl->AddRectFilled(ImVec2(i*dpiScale,j*dpiScale),ImVec2((i+160)*dpiScale,(j+160)*dpiScale),ImGui::GetColorU32(ImVec4(r*0.75,g*0.75,b*0.75,1.0)));
}
}
for (size_t i=0; i<aboutCount; i++) {
double posX=(scrW*dpiScale/2.0)+(sin(double(i)*0.5+double(aboutScroll)/90.0)*120*dpiScale)-(ImGui::CalcTextSize(aboutLine[i]).x*0.5);
double posY=(scrH-aboutScroll+42*i)*dpiScale;
if (posY<-80*dpiScale || posY>scrH*dpiScale) continue;
dl->AddText(bigFont,bigFont->FontSize,
ImVec2(posX+dpiScale,posY+dpiScale),
0xff000000,aboutLine[i]);
dl->AddText(bigFont,bigFont->FontSize,
ImVec2(posX+dpiScale,posY-dpiScale),
0xff000000,aboutLine[i]);
dl->AddText(bigFont,bigFont->FontSize,
ImVec2(posX-dpiScale,posY+dpiScale),
0xff000000,aboutLine[i]);
dl->AddText(bigFont,bigFont->FontSize,
ImVec2(posX-dpiScale,posY-dpiScale),
0xff000000,aboutLine[i]);
dl->AddText(bigFont,bigFont->FontSize,
ImVec2(posX,posY),
0xffffffff,aboutLine[i]);
}
ImGui::PopFont();
float timeScale=60.0f*ImGui::GetIO().DeltaTime;
aboutHue+=(0.001+peakMix*0.004)*timeScale;
aboutScroll+=(2+(peakMix>0.78)*3)*timeScale;
aboutSin+=(1+(peakMix>0.75)*2)*timeScale;
while (aboutHue>1) aboutHue--;
while (aboutSin>=2400) aboutSin-=2400;
if (aboutScroll>(42*aboutCount+scrH)) aboutScroll=-20;
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_ABOUT;
ImGui::End();
}

21
src/gui/actionUtil.h Normal file
View file

@ -0,0 +1,21 @@
#define DETERMINE_FIRST \
int firstChannel=0; \
for (int i=0; i<e->getTotalChannelCount(); i++) { \
if (e->song.chanShow[i]) { \
firstChannel=i; \
break; \
} \
} \
#define DETERMINE_LAST \
int lastChannel=0; \
for (int i=e->getTotalChannelCount()-1; i>=0; i--) { \
if (e->song.chanShow[i]) { \
lastChannel=i+1; \
break; \
} \
}
#define DETERMINE_FIRST_LAST \
DETERMINE_FIRST \
DETERMINE_LAST

53
src/gui/channels.cpp Normal file
View file

@ -0,0 +1,53 @@
/**
* 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"
void FurnaceGUI::drawChannels() {
if (nextWindow==GUI_WINDOW_CHANNELS) {
channelsOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!channelsOpen) return;
if (ImGui::Begin("Channels",&channelsOpen)) {
if (ImGui::BeginTable("ChannelList",3)) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale);
for (int i=0; i<e->getTotalChannelCount(); i++) {
ImGui::PushID(i);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Checkbox("##Visible",&e->song.chanShow[i]);
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->song.chanName[i]);
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::InputTextWithHint("##ChanShortName",e->getChannelShortName(i),&e->song.chanShortName[i]);
ImGui::PopID();
}
ImGui::EndTable();
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_CHANNELS;
ImGui::End();
}

136
src/gui/compatFlags.cpp Normal file
View file

@ -0,0 +1,136 @@
/**
* 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"
void FurnaceGUI::drawCompatFlags() {
if (nextWindow==GUI_WINDOW_COMPAT_FLAGS) {
compatFlagsOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!compatFlagsOpen) return;
if (ImGui::Begin("Compatibility Flags",&compatFlagsOpen)) {
ImGui::TextWrapped("these flags are designed to provide better DefleMask/older Furnace compatibility.");
ImGui::Checkbox("Limit slide range",&e->song.limitSlides);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, slides are limited to a compatible range.\nmay cause problems with slides in negative octaves.");
}
ImGui::Checkbox("Linear pitch control",&e->song.linearPitch);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("linear pitch:\n- slides work in frequency/period space\n- E5xx and 04xx effects work in tonality space\nnon-linear pitch:\n- slides work in frequency/period space\n- E5xx and 04xx effects work on frequency/period space");
}
ImGui::Checkbox("Proper noise layout on NES and PC Engine",&e->song.properNoiseLayout);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("use a proper noise channel note mapping (0-15) instead of a rather unusual compatible one.\nunlocks all noise frequencies on PC Engine.");
}
ImGui::Checkbox("Game Boy instrument duty is wave volume",&e->song.waveDutyIsVol);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("if enabled, an instrument with duty macro in the wave channel will be mapped to wavetable volume.");
}
ImGui::Checkbox("Restart macro on portamento",&e->song.resetMacroOnPorta);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, a portamento effect will reset the channel's macro if used in combination with a note.");
}
ImGui::Checkbox("Legacy volume slides",&e->song.legacyVolumeSlides);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("simulate glitchy volume slide behavior by silently overflowing the volume when the slide goes below 0.");
}
ImGui::Checkbox("Compatible arpeggio",&e->song.compatibleArpeggio);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("delay arpeggio by one tick on every new note.");
}
ImGui::Checkbox("Reset slides after note off",&e->song.noteOffResetsSlides);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, note off will reset the channel's slide effect.");
}
ImGui::Checkbox("Reset portamento after reaching target",&e->song.targetResetsSlides);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, the slide effect is disabled after it reaches its target.");
}
ImGui::Checkbox("Ignore duplicate slide effects",&e->song.ignoreDuplicateSlides);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("if this is on, only the first slide of a row in a channel will be considered.");
}
ImGui::Checkbox("Continuous vibrato",&e->song.continuousVibrato);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, vibrato will not be reset on a new note.");
}
ImGui::Checkbox("Broken DAC mode",&e->song.brokenDACMode);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, the DAC in YM2612 will be disabled if there isn't any sample playing.");
}
ImGui::Checkbox("Auto-insert one tick gap between notes",&e->song.oneTickCut);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("when enabled, a one-tick note cut will be inserted between non-legato/non-portamento notes.\nthis simulates the behavior of some Amiga/SNES music engines.");
}
ImGui::Text("Loop modality:");
if (ImGui::RadioButton("Reset channels",e->song.loopModality==0)) {
e->song.loopModality=0;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("select to reset channels on loop. may trigger a voltage click on every loop!");
}
if (ImGui::RadioButton("Soft reset channels",e->song.loopModality==1)) {
e->song.loopModality=1;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("select to turn channels off on loop.");
}
if (ImGui::RadioButton("Do nothing",e->song.loopModality==2)) {
e->song.loopModality=2;
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("select to not reset channels on loop.");
}
ImGui::Separator();
ImGui::TextWrapped("the following flags are for compatibility with older Furnace versions.");
ImGui::Checkbox("Arpeggio inhibits non-porta slides",&e->song.arpNonPorta);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.5.5");
}
ImGui::Checkbox("Wack FM algorithm macro",&e->song.algMacroBehavior);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.5.5");
}
ImGui::Checkbox("Broken shortcut slides (E1xy/E2xy)",&e->song.brokenShortcutSlides);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.5.7");
}
ImGui::Checkbox("Stop portamento on note off",&e->song.stopPortaOnNoteOff);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
}
ImGui::Checkbox("Allow instrument change during slides",&e->song.newInsTriggersInPorta);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
}
ImGui::Checkbox("Reset note to base on arpeggio stop",&e->song.arp0Reset);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("behavior changed in 0.6");
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_COMPAT_FLAGS;
ImGui::End();
}

285
src/gui/cursor.cpp Normal file
View file

@ -0,0 +1,285 @@
/**
* 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 "actionUtil.h"
void FurnaceGUI::startSelection(int xCoarse, int xFine, int y) {
if (xCoarse!=selStart.xCoarse || xFine!=selStart.xFine || y!=selStart.y) {
curNibble=false;
}
cursor.xCoarse=xCoarse;
cursor.xFine=xFine;
cursor.y=y;
selStart.xCoarse=xCoarse;
selStart.xFine=xFine;
selStart.y=y;
selEnd.xCoarse=xCoarse;
selEnd.xFine=xFine;
selEnd.y=y;
selecting=true;
}
void FurnaceGUI::updateSelection(int xCoarse, int xFine, int y) {
if (!selecting) return;
selEnd.xCoarse=xCoarse;
selEnd.xFine=xFine;
selEnd.y=y;
}
void FurnaceGUI::finishSelection() {
// swap points if needed
if (selEnd.y<selStart.y) {
selEnd.y^=selStart.y;
selStart.y^=selEnd.y;
selEnd.y^=selStart.y;
}
if (selEnd.xCoarse<selStart.xCoarse) {
selEnd.xCoarse^=selStart.xCoarse;
selStart.xCoarse^=selEnd.xCoarse;
selEnd.xCoarse^=selStart.xCoarse;
selEnd.xFine^=selStart.xFine;
selStart.xFine^=selEnd.xFine;
selEnd.xFine^=selStart.xFine;
} else if (selEnd.xCoarse==selStart.xCoarse && selEnd.xFine<selStart.xFine) {
selEnd.xFine^=selStart.xFine;
selStart.xFine^=selEnd.xFine;
selEnd.xFine^=selStart.xFine;
}
selecting=false;
// boundary check
int chanCount=e->getTotalChannelCount();
if (selStart.xCoarse<0) selStart.xCoarse=0;
if (selStart.xCoarse>=chanCount) selStart.xCoarse=chanCount-1;
if (selStart.y<0) selStart.y=0;
if (selStart.y>=e->song.patLen) selStart.y=e->song.patLen-1;
if (selEnd.xCoarse<0) selEnd.xCoarse=0;
if (selEnd.xCoarse>=chanCount) selEnd.xCoarse=chanCount-1;
if (selEnd.y<0) selEnd.y=0;
if (selEnd.y>=e->song.patLen) selEnd.y=e->song.patLen-1;
if (cursor.xCoarse<0) cursor.xCoarse=0;
if (cursor.xCoarse>=chanCount) cursor.xCoarse=chanCount-1;
if (cursor.y<0) cursor.y=0;
if (cursor.y>=e->song.patLen) cursor.y=e->song.patLen-1;
if (e->song.chanCollapse[selEnd.xCoarse]) {
selStart.xFine=0;
}
if (e->song.chanCollapse[selEnd.xCoarse]) {
selEnd.xFine=2+e->song.pat[cursor.xCoarse].effectRows*2;
}
}
void FurnaceGUI::moveCursor(int x, int y, bool select) {
if (!select) {
finishSelection();
}
DETERMINE_FIRST_LAST;
curNibble=false;
if (x!=0) {
demandScrollX=true;
if (x>0) {
for (int i=0; i<x; i++) {
if (++cursor.xFine>=(e->song.chanCollapse[cursor.xCoarse]?1:(3+e->song.pat[cursor.xCoarse].effectRows*2))) {
cursor.xFine=0;
if (++cursor.xCoarse>=lastChannel) {
if (settings.wrapHorizontal!=0 && !select) {
cursor.xCoarse=firstChannel;
if (settings.wrapHorizontal==2) y++;
} else {
cursor.xCoarse=lastChannel-1;
cursor.xFine=e->song.chanCollapse[cursor.xCoarse]?0:(2+e->song.pat[cursor.xCoarse].effectRows*2);
}
} else {
while (!e->song.chanShow[cursor.xCoarse]) {
cursor.xCoarse++;
if (cursor.xCoarse>=e->getTotalChannelCount()) break;
}
}
}
}
} else {
for (int i=0; i<-x; i++) {
if (--cursor.xFine<0) {
if (--cursor.xCoarse<firstChannel) {
if (settings.wrapHorizontal!=0 && !select) {
cursor.xCoarse=lastChannel-1;
cursor.xFine=2+e->song.pat[cursor.xCoarse].effectRows*2;
if (settings.wrapHorizontal==2) y--;
} else {
cursor.xCoarse=firstChannel;
cursor.xFine=0;
}
} else {
while (!e->song.chanShow[cursor.xCoarse]) {
cursor.xCoarse--;
if (cursor.xCoarse<0) break;
}
if (e->song.chanCollapse[cursor.xCoarse]) {
cursor.xFine=0;
} else {
cursor.xFine=2+e->song.pat[cursor.xCoarse].effectRows*2;
}
}
}
}
}
}
if (y!=0) {
if (y>0) {
for (int i=0; i<y; i++) {
cursor.y++;
if (cursor.y>=e->song.patLen) {
if (settings.wrapVertical!=0 && !select) {
cursor.y=0;
if (settings.wrapVertical==2) {
if (!e->isPlaying() && e->getOrder()<(e->song.ordersLen-1)) {
e->setOrder(e->getOrder()+1);
} else {
cursor.y=e->song.patLen-1;
}
}
} else {
cursor.y=e->song.patLen-1;
}
}
}
} else {
for (int i=0; i<-y; i++) {
cursor.y--;
if (cursor.y<0) {
if (settings.wrapVertical!=0 && !select) {
cursor.y=e->song.patLen-1;
if (settings.wrapVertical==2) {
if (!e->isPlaying() && e->getOrder()>0) {
e->setOrder(e->getOrder()-1);
} else {
cursor.y=0;
}
}
} else {
cursor.y=0;
}
}
}
}
}
if (!select) {
selStart=cursor;
}
selEnd=cursor;
updateScroll(cursor.y);
}
void FurnaceGUI::moveCursorPrevChannel(bool overflow) {
finishSelection();
curNibble=false;
DETERMINE_FIRST_LAST;
do {
cursor.xCoarse--;
if (cursor.xCoarse<0) break;
} while (!e->song.chanShow[cursor.xCoarse]);
if (cursor.xCoarse<firstChannel) {
if (overflow) {
cursor.xCoarse=lastChannel-1;
} else {
cursor.xCoarse=firstChannel;
}
}
selStart=cursor;
selEnd=cursor;
demandScrollX=true;
}
void FurnaceGUI::moveCursorNextChannel(bool overflow) {
finishSelection();
curNibble=false;
DETERMINE_FIRST_LAST;
do {
cursor.xCoarse++;
if (cursor.xCoarse>=e->getTotalChannelCount()) break;
} while (!e->song.chanShow[cursor.xCoarse]);
if (cursor.xCoarse>=lastChannel) {
if (overflow) {
cursor.xCoarse=firstChannel;
} else {
cursor.xCoarse=lastChannel-1;
}
}
selStart=cursor;
selEnd=cursor;
demandScrollX=true;
}
void FurnaceGUI::moveCursorTop(bool select) {
finishSelection();
curNibble=false;
if (cursor.y==0) {
DETERMINE_FIRST;
cursor.xCoarse=firstChannel;
cursor.xFine=0;
demandScrollX=true;
} else {
cursor.y=0;
}
selStart=cursor;
if (!select) {
selEnd=cursor;
}
updateScroll(cursor.y);
}
void FurnaceGUI::moveCursorBottom(bool select) {
finishSelection();
curNibble=false;
if (cursor.y==e->song.patLen-1) {
DETERMINE_LAST;
cursor.xCoarse=lastChannel-1;
cursor.xFine=2+e->song.pat[cursor.xCoarse].effectRows*2;
demandScrollX=true;
} else {
cursor.y=e->song.patLen-1;
}
if (!select) {
selStart=cursor;
}
selEnd=cursor;
updateScroll(cursor.y);
}
void FurnaceGUI::editAdvance() {
finishSelection();
cursor.y+=editStep;
if (cursor.y>=e->song.patLen) cursor.y=e->song.patLen-1;
selStart=cursor;
selEnd=cursor;
updateScroll(cursor.y);
}

View file

@ -1,3 +1,22 @@
/**
* 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 "IconsFontAwesome4.h"
#include "misc/cpp/imgui_stdlib.h"

250
src/gui/debugWindow.cpp Normal file
View file

@ -0,0 +1,250 @@
/**
* 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 "debug.h"
#include "IconsFontAwesome4.h"
#include <fmt/printf.h>
void FurnaceGUI::drawDebug() {
static int bpOrder;
static int bpRow;
static int bpTick;
static bool bpOn;
if (nextWindow==GUI_WINDOW_DEBUG) {
debugOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!debugOpen) return;
ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
if (ImGui::Begin("Debug",&debugOpen,ImGuiWindowFlags_NoDocking)) {
ImGui::Text("NOTE: use with caution.");
if (ImGui::TreeNode("Debug Controls")) {
if (e->isHalted()) {
if (ImGui::Button("Resume")) e->resume();
} else {
if (ImGui::Button("Pause")) e->halt();
}
ImGui::SameLine();
if (ImGui::Button("Frame Advance")) e->haltWhen(DIV_HALT_TICK);
ImGui::SameLine();
if (ImGui::Button("Row Advance")) e->haltWhen(DIV_HALT_ROW);
ImGui::SameLine();
if (ImGui::Button("Pattern Advance")) e->haltWhen(DIV_HALT_PATTERN);
if (ImGui::Button("Panic")) e->syncReset();
ImGui::SameLine();
if (ImGui::Button("Abort")) {
abort();
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Breakpoint")) {
ImGui::InputInt("Order",&bpOrder);
ImGui::InputInt("Row",&bpRow);
ImGui::InputInt("Tick",&bpTick);
ImGui::Checkbox("Enable",&bpOn);
ImGui::TreePop();
}
if (ImGui::TreeNode("Dispatch Status")) {
ImGui::Text("for best results set latency to minimum or use the Frame Advance button.");
ImGui::Columns(e->getTotalChannelCount());
for (int i=0; i<e->getTotalChannelCount(); i++) {
void* ch=e->getDispatchChanState(i);
ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Ch. %d: %d, %d",i,e->dispatchOfChan[i],e->dispatchChanOfChan[i]);
if (ch==NULL) {
ImGui::Text("NULL");
} else {
putDispatchChan(ch,e->dispatchChanOfChan[i],e->sysOfChan[i]);
}
ImGui::NextColumn();
}
ImGui::Columns();
ImGui::TreePop();
}
if (ImGui::TreeNode("Playback Status")) {
ImGui::Text("for best results set latency to minimum or use the Frame Advance button.");
ImGui::Columns(e->getTotalChannelCount());
for (int i=0; i<e->getTotalChannelCount(); i++) {
DivChannelState* ch=e->getChanState(i);
ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],"Channel %d:",i);
if (ch==NULL) {
ImGui::Text("NULL");
} else {
ImGui::Text("* General:");
ImGui::Text("- note = %d",ch->note);
ImGui::Text("- oldNote = %d",ch->oldNote);
ImGui::Text("- pitch = %d",ch->pitch);
ImGui::Text("- portaSpeed = %d",ch->portaSpeed);
ImGui::Text("- portaNote = %d",ch->portaNote);
ImGui::Text("- volume = %.4x",ch->volume);
ImGui::Text("- volSpeed = %d",ch->volSpeed);
ImGui::Text("- cut = %d",ch->cut);
ImGui::Text("- rowDelay = %d",ch->rowDelay);
ImGui::Text("- volMax = %.4x",ch->volMax);
ImGui::Text("- delayOrder = %d",ch->delayOrder);
ImGui::Text("- delayRow = %d",ch->delayRow);
ImGui::Text("- retrigSpeed = %d",ch->retrigSpeed);
ImGui::Text("- retrigTick = %d",ch->retrigTick);
ImGui::PushStyleColor(ImGuiCol_Text,(ch->vibratoDepth>0)?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_TEXT]);
ImGui::Text("* Vibrato:");
ImGui::Text("- depth = %d",ch->vibratoDepth);
ImGui::Text("- rate = %d",ch->vibratoRate);
ImGui::Text("- pos = %d",ch->vibratoPos);
ImGui::Text("- dir = %d",ch->vibratoDir);
ImGui::Text("- fine = %d",ch->vibratoFine);
ImGui::PopStyleColor();
ImGui::PushStyleColor(ImGuiCol_Text,(ch->tremoloDepth>0)?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_TEXT]);
ImGui::Text("* Tremolo:");
ImGui::Text("- depth = %d",ch->tremoloDepth);
ImGui::Text("- rate = %d",ch->tremoloRate);
ImGui::Text("- pos = %d",ch->tremoloPos);
ImGui::PopStyleColor();
ImGui::PushStyleColor(ImGuiCol_Text,(ch->arp>0)?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_TEXT]);
ImGui::Text("* Arpeggio:");
ImGui::Text("- arp = %.2X",ch->arp);
ImGui::Text("- stage = %d",ch->arpStage);
ImGui::Text("- ticks = %d",ch->arpTicks);
ImGui::PopStyleColor();
ImGui::Text("* Miscellaneous:");
ImGui::TextColored(ch->doNote?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Do Note");
ImGui::TextColored(ch->legato?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Legato");
ImGui::TextColored(ch->portaStop?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> PortaStop");
ImGui::TextColored(ch->keyOn?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Key On");
ImGui::TextColored(ch->keyOff?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Key Off");
ImGui::TextColored(ch->nowYouCanStop?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> NowYouCanStop");
ImGui::TextColored(ch->stopOnOff?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Stop on Off");
ImGui::TextColored(ch->arpYield?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> Arp Yield");
ImGui::TextColored(ch->delayLocked?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> DelayLocked");
ImGui::TextColored(ch->inPorta?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> InPorta");
ImGui::TextColored(ch->scheduledSlideReset?uiColors[GUI_COLOR_MACRO_VOLUME]:uiColors[GUI_COLOR_HEADER],">> SchedSlide");
}
ImGui::NextColumn();
}
ImGui::Columns();
ImGui::TreePop();
}
if (ImGui::TreeNode("Playground")) {
if (pgSys<0 || pgSys>=e->song.systemLen) pgSys=0;
if (ImGui::BeginCombo("System",fmt::sprintf("%d. %s",pgSys+1,e->getSystemName(e->song.system[pgSys])).c_str())) {
for (int i=0; i<e->song.systemLen; i++) {
if (ImGui::Selectable(fmt::sprintf("%d. %s",i+1,e->getSystemName(e->song.system[i])).c_str())) {
pgSys=i;
break;
}
}
ImGui::EndCombo();
}
ImGui::Text("Program");
if (pgProgram.empty()) {
ImGui::Text("-nothing here-");
} else {
char id[32];
for (size_t index=0; index<pgProgram.size(); index++) {
DivRegWrite& i=pgProgram[index];
snprintf(id,31,"pgw%d",(int)index);
ImGui::PushID(id);
ImGui::SetNextItemWidth(100.0f*dpiScale);
ImGui::InputScalar("##PAddress",ImGuiDataType_U32,&i.addr,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
ImGui::SameLine();
ImGui::Text("=");
ImGui::SameLine();
ImGui::SetNextItemWidth(100.0f*dpiScale);
ImGui::InputScalar("##PValue",ImGuiDataType_U16,&i.val,NULL,NULL,"%.2X",ImGuiInputTextFlags_CharsHexadecimal);
ImGui::SameLine();
if (ImGui::Button(ICON_FA_TIMES "##PRemove")) {
pgProgram.erase(pgProgram.begin()+index);
index--;
}
ImGui::PopID();
}
}
if (ImGui::Button("Execute")) {
e->poke(pgSys,pgProgram);
}
ImGui::SameLine();
if (ImGui::Button("Clear")) {
pgProgram.clear();
}
ImGui::Text("Address");
ImGui::SameLine();
ImGui::SetNextItemWidth(100.0f*dpiScale);
ImGui::InputInt("##PAddress",&pgAddr,0,0,ImGuiInputTextFlags_CharsHexadecimal);
ImGui::SameLine();
ImGui::Text("Value");
ImGui::SameLine();
ImGui::SetNextItemWidth(100.0f*dpiScale);
ImGui::InputInt("##PValue",&pgVal,0,0,ImGuiInputTextFlags_CharsHexadecimal);
ImGui::SameLine();
if (ImGui::Button("Write")) {
e->poke(pgSys,pgAddr,pgVal);
}
ImGui::SameLine();
if (ImGui::Button("Add")) {
pgProgram.push_back(DivRegWrite(pgAddr,pgVal));
}
if (ImGui::TreeNode("Register Cheatsheet")) {
const char** sheet=e->getRegisterSheet(pgSys);
if (sheet==NULL) {
ImGui::Text("no cheatsheet available for this system.");
} else {
if (ImGui::BeginTable("RegisterSheet",2,ImGuiTableFlags_SizingFixedSame)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Name");
ImGui::TableNextColumn();
ImGui::Text("Address");
for (int i=0; sheet[i]!=NULL; i+=2) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("%s",sheet[i]);
ImGui::TableNextColumn();
ImGui::Text("$%s",sheet[i+1]);
}
ImGui::EndTable();
}
}
ImGui::TreePop();
}
ImGui::TreePop();
}
if (ImGui::TreeNode("User Interface")) {
if (ImGui::Button("Inspect")) {
inspectorOpen=!inspectorOpen;
}
ImGui::TreePop();
}
if (ImGui::TreeNode("Settings")) {
if (ImGui::Button("Sync")) syncSettings();
ImGui::SameLine();
if (ImGui::Button("Commit")) commitSettings();
ImGui::SameLine();
if (ImGui::Button("Force Load")) e->loadConf();
ImGui::SameLine();
if (ImGui::Button("Force Save")) e->saveConf();
ImGui::TreePop();
}
ImGui::Text("Song format version %d",e->song.version);
ImGui::Text("Furnace version " DIV_VERSION " (%d)",DIV_ENGINE_VERSION);
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_DEBUG;
ImGui::End();
}

687
src/gui/doAction.cpp Normal file
View file

@ -0,0 +1,687 @@
/**
* 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 <fmt/printf.h>
#include "actionUtil.h"
void FurnaceGUI::doAction(int what) {
switch (what) {
case GUI_ACTION_OPEN:
if (modified) {
showWarning("Unsaved changes! Are you sure?",GUI_WARN_OPEN);
} else {
openFileDialog(GUI_FILE_OPEN);
}
break;
case GUI_ACTION_OPEN_BACKUP:
if (modified) {
showWarning("Unsaved changes! Are you sure?",GUI_WARN_OPEN_BACKUP);
} else {
if (load(backupPath)>0) {
showError("No backup available! (or unable to open it)");
}
}
break;
case 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));
}
}
break;
case GUI_ACTION_SAVE_AS:
openFileDialog(GUI_FILE_SAVE);
break;
case GUI_ACTION_UNDO:
doUndo();
break;
case GUI_ACTION_REDO:
doRedo();
break;
case GUI_ACTION_PLAY_TOGGLE:
if (e->isPlaying() && !e->isStepping()) {
stop();
} else {
play();
}
break;
case GUI_ACTION_PLAY:
play();
break;
case GUI_ACTION_STOP:
stop();
break;
case GUI_ACTION_PLAY_REPEAT:
play();
e->setRepeatPattern(true);
break;
case GUI_ACTION_PLAY_CURSOR:
if (e->isPlaying() && !e->isStepping()) {
stop();
} else {
play(cursor.y);
}
break;
case GUI_ACTION_STEP_ONE:
e->stepOne(cursor.y);
break;
case GUI_ACTION_OCTAVE_UP:
if (++curOctave>7) {
curOctave=7;
} else {
for (size_t i=0; i<activeNotes.size(); i++) {
e->noteOff(activeNotes[i].chan);
}
activeNotes.clear();
}
break;
case GUI_ACTION_OCTAVE_DOWN:
if (--curOctave<-5) {
curOctave=-5;
} else {
for (size_t i=0; i<activeNotes.size(); i++) {
e->noteOff(activeNotes[i].chan);
}
activeNotes.clear();
}
break;
case GUI_ACTION_INS_UP:
if (--curIns<-1) curIns=-1;
break;
case GUI_ACTION_INS_DOWN:
if (++curIns>=(int)e->song.ins.size()) curIns=((int)e->song.ins.size())-1;
break;
case GUI_ACTION_STEP_UP:
if (++editStep>64) editStep=64;
break;
case GUI_ACTION_STEP_DOWN:
if (--editStep<0) editStep=0;
break;
case GUI_ACTION_TOGGLE_EDIT:
edit=!edit;
break;
case GUI_ACTION_METRONOME:
e->setMetronome(!e->getMetronome());
break;
case GUI_ACTION_REPEAT_PATTERN:
e->setRepeatPattern(!e->getRepeatPattern());
break;
case GUI_ACTION_FOLLOW_ORDERS:
followOrders=!followOrders;
break;
case GUI_ACTION_FOLLOW_PATTERN:
followPattern=!followPattern;
break;
case GUI_ACTION_PANIC:
e->syncReset();
break;
case GUI_ACTION_WINDOW_EDIT_CONTROLS:
nextWindow=GUI_WINDOW_EDIT_CONTROLS;
break;
case GUI_ACTION_WINDOW_ORDERS:
nextWindow=GUI_WINDOW_ORDERS;
break;
case GUI_ACTION_WINDOW_INS_LIST:
nextWindow=GUI_WINDOW_INS_LIST;
break;
case GUI_ACTION_WINDOW_INS_EDIT:
nextWindow=GUI_WINDOW_INS_EDIT;
break;
case GUI_ACTION_WINDOW_SONG_INFO:
nextWindow=GUI_WINDOW_SONG_INFO;
break;
case GUI_ACTION_WINDOW_PATTERN:
nextWindow=GUI_WINDOW_PATTERN;
break;
case GUI_ACTION_WINDOW_WAVE_LIST:
nextWindow=GUI_WINDOW_WAVE_LIST;
break;
case GUI_ACTION_WINDOW_WAVE_EDIT:
nextWindow=GUI_WINDOW_WAVE_EDIT;
break;
case GUI_ACTION_WINDOW_SAMPLE_LIST:
nextWindow=GUI_WINDOW_SAMPLE_LIST;
break;
case GUI_ACTION_WINDOW_SAMPLE_EDIT:
nextWindow=GUI_WINDOW_SAMPLE_EDIT;
break;
case GUI_ACTION_WINDOW_ABOUT:
nextWindow=GUI_WINDOW_ABOUT;
break;
case GUI_ACTION_WINDOW_SETTINGS:
nextWindow=GUI_WINDOW_SETTINGS;
break;
case GUI_ACTION_WINDOW_MIXER:
nextWindow=GUI_WINDOW_MIXER;
break;
case GUI_ACTION_WINDOW_DEBUG:
nextWindow=GUI_WINDOW_DEBUG;
break;
case GUI_ACTION_WINDOW_OSCILLOSCOPE:
nextWindow=GUI_WINDOW_OSCILLOSCOPE;
break;
case GUI_ACTION_WINDOW_VOL_METER:
nextWindow=GUI_WINDOW_VOL_METER;
break;
case GUI_ACTION_WINDOW_STATS:
nextWindow=GUI_WINDOW_STATS;
break;
case GUI_ACTION_WINDOW_COMPAT_FLAGS:
nextWindow=GUI_WINDOW_COMPAT_FLAGS;
break;
case GUI_ACTION_WINDOW_PIANO:
nextWindow=GUI_WINDOW_PIANO;
break;
case GUI_ACTION_WINDOW_NOTES:
nextWindow=GUI_WINDOW_NOTES;
break;
case GUI_ACTION_WINDOW_CHANNELS:
nextWindow=GUI_WINDOW_CHANNELS;
break;
case GUI_ACTION_WINDOW_REGISTER_VIEW:
nextWindow=GUI_WINDOW_REGISTER_VIEW;
break;
case GUI_ACTION_COLLAPSE_WINDOW:
collapseWindow=true;
break;
case GUI_ACTION_CLOSE_WINDOW:
switch (curWindow) {
case GUI_WINDOW_EDIT_CONTROLS:
editControlsOpen=false;
break;
case GUI_WINDOW_SONG_INFO:
songInfoOpen=false;
break;
case GUI_WINDOW_ORDERS:
ordersOpen=false;
break;
case GUI_WINDOW_INS_LIST:
insListOpen=false;
break;
case GUI_WINDOW_PATTERN:
patternOpen=false;
break;
case GUI_WINDOW_INS_EDIT:
insEditOpen=false;
break;
case GUI_WINDOW_WAVE_LIST:
waveListOpen=false;
break;
case GUI_WINDOW_WAVE_EDIT:
waveEditOpen=false;
break;
case GUI_WINDOW_SAMPLE_LIST:
sampleListOpen=false;
break;
case GUI_WINDOW_SAMPLE_EDIT:
sampleEditOpen=false;
break;
case GUI_WINDOW_MIXER:
mixerOpen=false;
break;
case GUI_WINDOW_ABOUT:
aboutOpen=false;
break;
case GUI_WINDOW_SETTINGS:
settingsOpen=false;
break;
case GUI_WINDOW_DEBUG:
debugOpen=false;
break;
case GUI_WINDOW_OSCILLOSCOPE:
oscOpen=false;
break;
case GUI_WINDOW_VOL_METER:
volMeterOpen=false;
break;
case GUI_WINDOW_STATS:
statsOpen=false;
break;
case GUI_WINDOW_COMPAT_FLAGS:
compatFlagsOpen=false;
break;
case GUI_WINDOW_PIANO:
pianoOpen=false;
break;
case GUI_WINDOW_NOTES:
notesOpen=false;
break;
case GUI_WINDOW_CHANNELS:
channelsOpen=false;
break;
case GUI_WINDOW_REGISTER_VIEW:
regViewOpen=false;
break;
default:
break;
}
curWindow=GUI_WINDOW_NOTHING;
break;
case GUI_ACTION_PAT_NOTE_UP:
doTranspose(1);
break;
case GUI_ACTION_PAT_NOTE_DOWN:
doTranspose(-1);
break;
case GUI_ACTION_PAT_OCTAVE_UP:
doTranspose(12);
break;
case GUI_ACTION_PAT_OCTAVE_DOWN:
doTranspose(-12);
break;
case GUI_ACTION_PAT_SELECT_ALL:
doSelectAll();
break;
case GUI_ACTION_PAT_CUT:
doCopy(true);
break;
case GUI_ACTION_PAT_COPY:
doCopy(false);
break;
case GUI_ACTION_PAT_PASTE:
doPaste();
break;
case GUI_ACTION_PAT_CURSOR_UP:
moveCursor(0,-MAX(1,settings.scrollStep?editStep:1),false);
break;
case GUI_ACTION_PAT_CURSOR_DOWN:
moveCursor(0,MAX(1,settings.scrollStep?editStep:1),false);
break;
case GUI_ACTION_PAT_CURSOR_LEFT:
moveCursor(-1,0,false);
break;
case GUI_ACTION_PAT_CURSOR_RIGHT:
moveCursor(1,0,false);
break;
case GUI_ACTION_PAT_CURSOR_UP_ONE:
moveCursor(0,-1,false);
break;
case GUI_ACTION_PAT_CURSOR_DOWN_ONE:
moveCursor(0,1,false);
break;
case GUI_ACTION_PAT_CURSOR_LEFT_CHANNEL:
moveCursorPrevChannel(false);
break;
case GUI_ACTION_PAT_CURSOR_RIGHT_CHANNEL:
moveCursorNextChannel(false);
break;
case GUI_ACTION_PAT_CURSOR_NEXT_CHANNEL:
moveCursorNextChannel(true);
break;
case GUI_ACTION_PAT_CURSOR_PREVIOUS_CHANNEL:
moveCursorPrevChannel(true);
break;
case GUI_ACTION_PAT_CURSOR_BEGIN:
moveCursorTop(false);
break;
case GUI_ACTION_PAT_CURSOR_END:
moveCursorBottom(false);
break;
case GUI_ACTION_PAT_CURSOR_UP_COARSE:
moveCursor(0,-16,false);
break;
case GUI_ACTION_PAT_CURSOR_DOWN_COARSE:
moveCursor(0,16,false);
break;
case GUI_ACTION_PAT_SELECTION_UP:
moveCursor(0,-MAX(1,settings.scrollStep?editStep:1),true);
break;
case GUI_ACTION_PAT_SELECTION_DOWN:
moveCursor(0,MAX(1,settings.scrollStep?editStep:1),true);
break;
case GUI_ACTION_PAT_SELECTION_LEFT:
moveCursor(-1,0,true);
break;
case GUI_ACTION_PAT_SELECTION_RIGHT:
moveCursor(1,0,true);
break;
case GUI_ACTION_PAT_SELECTION_UP_ONE:
moveCursor(0,-1,true);
break;
case GUI_ACTION_PAT_SELECTION_DOWN_ONE:
moveCursor(0,1,true);
break;
case GUI_ACTION_PAT_SELECTION_BEGIN:
moveCursorTop(true);
break;
case GUI_ACTION_PAT_SELECTION_END:
moveCursorBottom(true);
break;
case GUI_ACTION_PAT_SELECTION_UP_COARSE:
moveCursor(0,-16,true);
break;
case GUI_ACTION_PAT_SELECTION_DOWN_COARSE:
moveCursor(0,16,true);
break;
case GUI_ACTION_PAT_DELETE:
doDelete();
if (settings.stepOnDelete) {
moveCursor(0,editStep,false);
}
break;
case GUI_ACTION_PAT_PULL_DELETE:
doPullDelete();
break;
case GUI_ACTION_PAT_INSERT:
doInsert();
if (settings.stepOnInsert) {
moveCursor(0,editStep,false);
}
break;
case GUI_ACTION_PAT_MUTE_CURSOR:
if (cursor.xCoarse<0 || cursor.xCoarse>=e->getTotalChannelCount()) break;
e->toggleMute(cursor.xCoarse);
break;
case GUI_ACTION_PAT_SOLO_CURSOR:
if (cursor.xCoarse<0 || cursor.xCoarse>=e->getTotalChannelCount()) break;
e->toggleSolo(cursor.xCoarse);
break;
case GUI_ACTION_PAT_UNMUTE_ALL:
e->unmuteAll();
break;
case GUI_ACTION_PAT_NEXT_ORDER:
if (e->getOrder()<e->song.ordersLen-1) {
e->setOrder(e->getOrder()+1);
}
break;
case GUI_ACTION_PAT_PREV_ORDER:
if (e->getOrder()>0) {
e->setOrder(e->getOrder()-1);
}
break;
case GUI_ACTION_PAT_COLLAPSE:
if (cursor.xCoarse<0 || cursor.xCoarse>=e->getTotalChannelCount()) break;
e->song.chanCollapse[cursor.xCoarse]=!e->song.chanCollapse[cursor.xCoarse];
break;
case GUI_ACTION_PAT_INCREASE_COLUMNS:
if (cursor.xCoarse<0 || cursor.xCoarse>=e->getTotalChannelCount()) break;
e->song.pat[cursor.xCoarse].effectRows++;
if (e->song.pat[cursor.xCoarse].effectRows>8) e->song.pat[cursor.xCoarse].effectRows=8;
break;
case GUI_ACTION_PAT_DECREASE_COLUMNS:
if (cursor.xCoarse<0 || cursor.xCoarse>=e->getTotalChannelCount()) break;
e->song.pat[cursor.xCoarse].effectRows--;
if (e->song.pat[cursor.xCoarse].effectRows<1) e->song.pat[cursor.xCoarse].effectRows=1;
break;
case GUI_ACTION_PAT_INTERPOLATE:
doInterpolate();
break;
case GUI_ACTION_PAT_INVERT_VALUES:
doInvertValues();
break;
case GUI_ACTION_PAT_FLIP_SELECTION:
doFlip();
break;
case GUI_ACTION_PAT_COLLAPSE_ROWS:
doCollapse(2);
break;
case GUI_ACTION_PAT_EXPAND_ROWS:
doExpand(2);
break;
case GUI_ACTION_PAT_COLLAPSE_PAT: // TODO
break;
case GUI_ACTION_PAT_EXPAND_PAT: // TODO
break;
case GUI_ACTION_PAT_COLLAPSE_SONG: // TODO
break;
case GUI_ACTION_PAT_EXPAND_SONG: // TODO
break;
case GUI_ACTION_PAT_LATCH: // TODO
break;
case GUI_ACTION_INS_LIST_ADD:
curIns=e->addInstrument(cursor.xCoarse);
MARK_MODIFIED;
break;
case GUI_ACTION_INS_LIST_DUPLICATE:
if (curIns>=0 && curIns<(int)e->song.ins.size()) {
int prevIns=curIns;
curIns=e->addInstrument(cursor.xCoarse);
(*e->song.ins[curIns])=(*e->song.ins[prevIns]);
MARK_MODIFIED;
}
break;
case GUI_ACTION_INS_LIST_OPEN:
openFileDialog(GUI_FILE_INS_OPEN);
break;
case GUI_ACTION_INS_LIST_SAVE:
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE);
break;
case GUI_ACTION_INS_LIST_MOVE_UP:
if (e->moveInsUp(curIns)) curIns--;
break;
case GUI_ACTION_INS_LIST_MOVE_DOWN:
if (e->moveInsDown(curIns)) curIns++;
break;
case GUI_ACTION_INS_LIST_DELETE:
if (curIns>=0 && curIns<(int)e->song.ins.size()) {
e->delInstrument(curIns);
MARK_MODIFIED;
if (curIns>=(int)e->song.ins.size()) {
curIns--;
}
}
break;
case GUI_ACTION_INS_LIST_EDIT:
insEditOpen=true;
break;
case GUI_ACTION_INS_LIST_UP:
if (--curIns<0) curIns=0;
break;
case GUI_ACTION_INS_LIST_DOWN:
if (++curIns>=(int)e->song.ins.size()) curIns=((int)e->song.ins.size())-1;
break;
case GUI_ACTION_WAVE_LIST_ADD:
curWave=e->addWave();
MARK_MODIFIED;
break;
case GUI_ACTION_WAVE_LIST_DUPLICATE:
if (curWave>=0 && curWave<(int)e->song.wave.size()) {
int prevWave=curWave;
curWave=e->addWave();
(*e->song.wave[curWave])=(*e->song.wave[prevWave]);
MARK_MODIFIED;
}
break;
case GUI_ACTION_WAVE_LIST_OPEN:
openFileDialog(GUI_FILE_WAVE_OPEN);
break;
case GUI_ACTION_WAVE_LIST_SAVE:
if (curWave>=0 && curWave<(int)e->song.wave.size()) openFileDialog(GUI_FILE_WAVE_SAVE);
break;
case GUI_ACTION_WAVE_LIST_MOVE_UP:
if (e->moveWaveUp(curWave)) curWave--;
break;
case GUI_ACTION_WAVE_LIST_MOVE_DOWN:
if (e->moveWaveDown(curWave)) curWave++;
break;
case GUI_ACTION_WAVE_LIST_DELETE:
if (curWave>=0 && curWave<(int)e->song.wave.size()) {
e->delWave(curWave);
MARK_MODIFIED;
if (curWave>=(int)e->song.wave.size()) {
curWave--;
}
}
break;
case GUI_ACTION_WAVE_LIST_EDIT:
waveEditOpen=true;
break;
case GUI_ACTION_WAVE_LIST_UP:
if (--curWave<0) curWave=0;
break;
case GUI_ACTION_WAVE_LIST_DOWN:
if (++curWave>=(int)e->song.wave.size()) curWave=((int)e->song.wave.size())-1;
break;
case GUI_ACTION_SAMPLE_LIST_ADD:
curSample=e->addSample();
MARK_MODIFIED;
break;
case GUI_ACTION_SAMPLE_LIST_OPEN:
openFileDialog(GUI_FILE_SAMPLE_OPEN);
break;
case GUI_ACTION_SAMPLE_LIST_SAVE:
if (curSample>=0 && curSample<(int)e->song.sample.size()) openFileDialog(GUI_FILE_SAMPLE_SAVE);
break;
case GUI_ACTION_SAMPLE_LIST_MOVE_UP:
if (e->moveSampleUp(curSample)) curSample--;
break;
case GUI_ACTION_SAMPLE_LIST_MOVE_DOWN:
if (e->moveSampleDown(curSample)) curSample++;
break;
case GUI_ACTION_SAMPLE_LIST_DELETE:
e->delSample(curSample);
MARK_MODIFIED;
if (curSample>=(int)e->song.sample.size()) {
curSample--;
}
break;
case GUI_ACTION_SAMPLE_LIST_EDIT:
sampleEditOpen=true;
break;
case GUI_ACTION_SAMPLE_LIST_UP:
if (--curSample<0) curSample=0;
break;
case GUI_ACTION_SAMPLE_LIST_DOWN:
if (++curSample>=(int)e->song.sample.size()) curSample=((int)e->song.sample.size())-1;
break;
case GUI_ACTION_SAMPLE_LIST_PREVIEW:
e->previewSample(curSample);
break;
case GUI_ACTION_SAMPLE_LIST_STOP_PREVIEW:
e->stopSamplePreview();
break;
case GUI_ACTION_ORDERS_UP:
if (e->getOrder()>0) {
e->setOrder(e->getOrder()-1);
}
break;
case GUI_ACTION_ORDERS_DOWN:
if (e->getOrder()<e->song.ordersLen-1) {
e->setOrder(e->getOrder()+1);
}
break;
case GUI_ACTION_ORDERS_LEFT: {
DETERMINE_FIRST;
do {
orderCursor--;
if (orderCursor<firstChannel) {
orderCursor=firstChannel;
break;
}
} while (!e->song.chanShow[orderCursor]);
break;
}
case GUI_ACTION_ORDERS_RIGHT: {
DETERMINE_LAST;
do {
orderCursor++;
if (orderCursor>=lastChannel) {
orderCursor=lastChannel-1;
break;
}
} while (!e->song.chanShow[orderCursor]);
break;
}
case GUI_ACTION_ORDERS_INCREASE: {
if (orderCursor<0 || orderCursor>=e->getTotalChannelCount()) break;
int curOrder=e->getOrder();
if (e->song.orders.ord[orderCursor][curOrder]<0x7f) {
e->song.orders.ord[orderCursor][curOrder]++;
}
break;
}
case GUI_ACTION_ORDERS_DECREASE: {
if (orderCursor<0 || orderCursor>=e->getTotalChannelCount()) break;
int curOrder=e->getOrder();
if (e->song.orders.ord[orderCursor][curOrder]>0) {
e->song.orders.ord[orderCursor][curOrder]--;
}
break;
}
case GUI_ACTION_ORDERS_EDIT_MODE:
orderEditMode++;
if (orderEditMode>3) orderEditMode=0;
break;
case GUI_ACTION_ORDERS_LINK:
changeAllOrders=!changeAllOrders;
break;
case GUI_ACTION_ORDERS_ADD:
prepareUndo(GUI_UNDO_CHANGE_ORDER);
e->addOrder(false,false);
makeUndo(GUI_UNDO_CHANGE_ORDER);
break;
case GUI_ACTION_ORDERS_DUPLICATE:
prepareUndo(GUI_UNDO_CHANGE_ORDER);
e->addOrder(true,false);
makeUndo(GUI_UNDO_CHANGE_ORDER);
break;
case GUI_ACTION_ORDERS_DEEP_CLONE:
prepareUndo(GUI_UNDO_CHANGE_ORDER);
e->deepCloneOrder(false);
makeUndo(GUI_UNDO_CHANGE_ORDER);
if (!e->getWarnings().empty()) {
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
}
break;
case GUI_ACTION_ORDERS_DUPLICATE_END:
prepareUndo(GUI_UNDO_CHANGE_ORDER);
e->addOrder(true,true);
makeUndo(GUI_UNDO_CHANGE_ORDER);
break;
case GUI_ACTION_ORDERS_DEEP_CLONE_END:
prepareUndo(GUI_UNDO_CHANGE_ORDER);
e->deepCloneOrder(true);
makeUndo(GUI_UNDO_CHANGE_ORDER);
if (!e->getWarnings().empty()) {
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
}
break;
case GUI_ACTION_ORDERS_REMOVE:
prepareUndo(GUI_UNDO_CHANGE_ORDER);
e->deleteOrder();
makeUndo(GUI_UNDO_CHANGE_ORDER);
break;
case GUI_ACTION_ORDERS_MOVE_UP:
prepareUndo(GUI_UNDO_CHANGE_ORDER);
e->moveOrderUp();
makeUndo(GUI_UNDO_CHANGE_ORDER);
break;
case GUI_ACTION_ORDERS_MOVE_DOWN:
prepareUndo(GUI_UNDO_CHANGE_ORDER);
e->moveOrderDown();
makeUndo(GUI_UNDO_CHANGE_ORDER);
break;
case GUI_ACTION_ORDERS_REPLAY:
e->setOrder(e->getOrder());
break;
}
}

330
src/gui/editControls.cpp Normal file
View file

@ -0,0 +1,330 @@
/**
* 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 "IconsFontAwesome4.h"
void FurnaceGUI::drawEditControls() {
if (nextWindow==GUI_WINDOW_EDIT_CONTROLS) {
editControlsOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!editControlsOpen) return;
switch (settings.controlLayout) {
case 0: // classic
if (ImGui::Begin("Play/Edit Controls",&editControlsOpen)) {
ImGui::Text("Octave");
ImGui::SameLine();
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
if (curOctave>7) curOctave=7;
if (curOctave<-5) curOctave=-5;
for (size_t i=0; i<activeNotes.size(); i++) {
e->noteOff(activeNotes[i].chan);
}
activeNotes.clear();
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
nextWindow=GUI_WINDOW_PATTERN;
}
}
ImGui::Text("Edit Step");
ImGui::SameLine();
if (ImGui::InputInt("##EditStep",&editStep,1,1)) {
if (editStep>=e->song.patLen) editStep=e->song.patLen-1;
if (editStep<0) editStep=0;
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
nextWindow=GUI_WINDOW_PATTERN;
}
}
if (ImGui::Button(ICON_FA_PLAY "##Play")) {
play();
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_STOP "##Stop")) {
stop();
}
ImGui::SameLine();
ImGui::Checkbox("Edit",&edit);
ImGui::SameLine();
bool metro=e->getMetronome();
if (ImGui::Checkbox("Metronome",&metro)) {
e->setMetronome(metro);
}
ImGui::Text("Follow");
ImGui::SameLine();
unimportant(ImGui::Checkbox("Orders",&followOrders));
ImGui::SameLine();
unimportant(ImGui::Checkbox("Pattern",&followPattern));
bool repeatPattern=e->getRepeatPattern();
if (ImGui::Checkbox("Repeat pattern",&repeatPattern)) {
e->setRepeatPattern(repeatPattern);
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_ARROW_DOWN "##StepOne")) {
e->stepOne(cursor.y);
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS;
ImGui::End();
break;
case 1: // compact
if (ImGui::Begin("Play/Edit Controls",&editControlsOpen,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse)) {
if (ImGui::Button(ICON_FA_STOP "##Stop")) {
stop();
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_PLAY "##Play")) {
play();
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_ARROW_DOWN "##StepOne")) {
e->stepOne(cursor.y);
}
ImGui::SameLine();
bool repeatPattern=e->getRepeatPattern();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(repeatPattern)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_REPEAT "##RepeatPattern")) {
e->setRepeatPattern(!repeatPattern);
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(edit)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_CIRCLE "##Edit")) {
edit=!edit;
}
ImGui::PopStyleColor();
ImGui::SameLine();
bool metro=e->getMetronome();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(metro)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_BELL_O "##Metronome")) {
e->setMetronome(!metro);
}
ImGui::PopStyleColor();
ImGui::SameLine();
ImGui::Text("Octave");
ImGui::SameLine();
ImGui::SetNextItemWidth(96.0f*dpiScale);
if (ImGui::InputInt("##Octave",&curOctave,1,1)) {
if (curOctave>7) curOctave=7;
if (curOctave<-5) curOctave=-5;
for (size_t i=0; i<activeNotes.size(); i++) {
e->noteOff(activeNotes[i].chan);
}
activeNotes.clear();
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
nextWindow=GUI_WINDOW_PATTERN;
}
}
ImGui::SameLine();
ImGui::Text("Edit Step");
ImGui::SameLine();
ImGui::SetNextItemWidth(96.0f*dpiScale);
if (ImGui::InputInt("##EditStep",&editStep,1,1)) {
if (editStep>=e->song.patLen) editStep=e->song.patLen-1;
if (editStep<0) editStep=0;
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
nextWindow=GUI_WINDOW_PATTERN;
}
}
ImGui::SameLine();
ImGui::Text("Follow");
ImGui::SameLine();
unimportant(ImGui::Checkbox("Orders",&followOrders));
ImGui::SameLine();
unimportant(ImGui::Checkbox("Pattern",&followPattern));
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS;
ImGui::End();
break;
case 2: // compact vertical
if (ImGui::Begin("Play/Edit Controls",&editControlsOpen,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse)) {
if (ImGui::Button(ICON_FA_PLAY "##Play")) {
play();
}
if (ImGui::Button(ICON_FA_STOP "##Stop")) {
stop();
}
if (ImGui::Button(ICON_FA_ARROW_DOWN "##StepOne")) {
e->stepOne(cursor.y);
}
bool repeatPattern=e->getRepeatPattern();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(repeatPattern)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_REPEAT "##RepeatPattern")) {
e->setRepeatPattern(!repeatPattern);
}
ImGui::PopStyleColor();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(edit)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_CIRCLE "##Edit")) {
edit=!edit;
}
ImGui::PopStyleColor();
bool metro=e->getMetronome();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(metro)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_BELL_O "##Metronome")) {
e->setMetronome(!metro);
}
ImGui::PopStyleColor();
ImGui::Text("Oct.");
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;
for (size_t i=0; i<activeNotes.size(); i++) {
e->noteOff(activeNotes[i].chan);
}
activeNotes.clear();
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
nextWindow=GUI_WINDOW_PATTERN;
}
}
ImGui::Text("Step");
ImGui::SetNextItemWidth(avail);
if (ImGui::InputInt("##EditStep",&editStep,0,0)) {
if (editStep>=e->song.patLen) editStep=e->song.patLen-1;
if (editStep<0) editStep=0;
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
nextWindow=GUI_WINDOW_PATTERN;
}
}
ImGui::Text("Foll.");
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(followOrders)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::SmallButton("Ord##FollowOrders")) { handleUnimportant
followOrders=!followOrders;
}
ImGui::PopStyleColor();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(followPattern)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::SmallButton("Pat##FollowPattern")) { handleUnimportant
followPattern=!followPattern;
}
ImGui::PopStyleColor();
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS;
ImGui::End();
break;
case 3: // split
if (ImGui::Begin("Play Controls",&editControlsOpen,ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoScrollWithMouse)) {
if (e->isPlaying()) {
if (ImGui::Button(ICON_FA_STOP "##Stop")) {
stop();
}
} else {
if (ImGui::Button(ICON_FA_PLAY "##Play")) {
play();
}
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_PLAY_CIRCLE "##PlayAgain")) {
play();
}
ImGui::SameLine();
if (ImGui::Button(ICON_FA_ARROW_DOWN "##StepOne")) {
e->stepOne(cursor.y);
}
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(edit)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_CIRCLE "##Edit")) {
edit=!edit;
}
ImGui::PopStyleColor();
bool metro=e->getMetronome();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(metro)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_BELL_O "##Metronome")) {
e->setMetronome(!metro);
}
ImGui::PopStyleColor();
ImGui::SameLine();
bool repeatPattern=e->getRepeatPattern();
ImGui::PushStyleColor(ImGuiCol_Button,ImVec4(0.2f,(repeatPattern)?0.6f:0.2f,0.2f,1.0f));
if (ImGui::Button(ICON_FA_REPEAT "##RepeatPattern")) {
e->setRepeatPattern(!repeatPattern);
}
ImGui::PopStyleColor();
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS;
ImGui::End();
if (ImGui::Begin("Edit Controls",&editControlsOpen)) {
ImGui::Columns(2);
ImGui::Text("Octave");
ImGui::SameLine();
float cursor=ImGui::GetCursorPosX();
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;
for (size_t i=0; i<activeNotes.size(); i++) {
e->noteOff(activeNotes[i].chan);
}
activeNotes.clear();
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
nextWindow=GUI_WINDOW_PATTERN;
}
}
ImGui::Text("Step");
ImGui::SameLine();
ImGui::SetCursorPosX(cursor);
ImGui::SetNextItemWidth(avail);
if (ImGui::InputInt("##EditStep",&editStep,1,1)) {
if (editStep>=e->song.patLen) editStep=e->song.patLen-1;
if (editStep<0) editStep=0;
if (settings.insFocusesPattern && !ImGui::IsItemActive() && patternOpen) {
nextWindow=GUI_WINDOW_PATTERN;
}
}
ImGui::NextColumn();
unimportant(ImGui::Checkbox("Follow orders",&followOrders));
unimportant(ImGui::Checkbox("Follow pattern",&followPattern));
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_EDIT_CONTROLS;
ImGui::End();
break;
}
}

1015
src/gui/editing.cpp Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -17,6 +17,9 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef _FUR_GUI_H
#define _FUR_GUI_H
#include "../engine/engine.h"
#include "imgui.h"
#include "imgui_impl_sdl.h"
@ -775,6 +778,7 @@ class FurnaceGUI {
void drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, const ImVec2& size);
void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, float maxTl, float maxArDr, const ImVec2& size);
void drawSysConf(int i);
void updateWindowTitle();
void prepareLayout();
@ -865,6 +869,7 @@ class FurnaceGUI {
void exportAudio(String path, DivAudioExportModes mode);
void applyUISettings();
void initSystemPresets();
void encodeMMLStr(String& target, int* macro, int macroLen, int macroLoop, int macroRel);
void encodeMMLStr(String& target, unsigned char* macro, unsigned char macroLen, signed char macroLoop, signed char macroRel);
@ -892,3 +897,5 @@ class FurnaceGUI {
bool init();
FurnaceGUI();
};
#endif

View file

@ -19,7 +19,7 @@
// guiConst: constants used in the GUI like arrays, strings and other stuff
#include "guiConst.h"
#include "../engine/instrument.h"
#include "../engine/song.h"
const int opOrder[4]={
0, 2, 1, 3
@ -122,3 +122,47 @@ const char* resampleStrats[]={
"sinc",
"best possible"
};
// define systems.
const int availableSystems[]={
DIV_SYSTEM_YM2612,
DIV_SYSTEM_YM2612_EXT,
DIV_SYSTEM_SMS,
DIV_SYSTEM_GB,
DIV_SYSTEM_PCE,
DIV_SYSTEM_NES,
DIV_SYSTEM_C64_8580,
DIV_SYSTEM_C64_6581,
DIV_SYSTEM_YM2151,
DIV_SYSTEM_SEGAPCM,
DIV_SYSTEM_SEGAPCM_COMPAT,
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_AY8910,
DIV_SYSTEM_AMIGA,
DIV_SYSTEM_PCSPKR,
DIV_SYSTEM_OPLL,
DIV_SYSTEM_OPLL_DRUMS,
DIV_SYSTEM_VRC7,
DIV_SYSTEM_OPL,
DIV_SYSTEM_OPL_DRUMS,
DIV_SYSTEM_OPL2,
DIV_SYSTEM_OPL2_DRUMS,
DIV_SYSTEM_OPL3,
DIV_SYSTEM_OPL3_DRUMS,
DIV_SYSTEM_TIA,
DIV_SYSTEM_SAA1099,
DIV_SYSTEM_AY8930,
DIV_SYSTEM_LYNX,
DIV_SYSTEM_QSOUND,
DIV_SYSTEM_X1_010,
DIV_SYSTEM_SWAN,
DIV_SYSTEM_VERA,
DIV_SYSTEM_BUBSYS_WSG,
DIV_SYSTEM_PET,
0 // don't remove this last one!
};

View file

@ -25,4 +25,5 @@ extern const char* noteNamesG[180];
extern const char* pitchLabel[11];
extern const char* insTypes[];
extern const char* sampleDepths[17];
extern const char* resampleStrats[];
extern const char* resampleStrats[];
extern const int availableSystems[];

59
src/gui/mixer.cpp Normal file
View file

@ -0,0 +1,59 @@
/**
* 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 "intConst.h"
void FurnaceGUI::drawMixer() {
if (nextWindow==GUI_WINDOW_MIXER) {
mixerOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!mixerOpen) return;
ImGui::SetNextWindowSizeConstraints(ImVec2(400.0f*dpiScale,200.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
if (ImGui::Begin("Mixer",&mixerOpen,settings.allowEditDocking?0:ImGuiWindowFlags_NoDocking)) {
char id[32];
if (ImGui::SliderFloat("Master Volume",&e->song.masterVol,0,3,"%.2fx")) {
if (e->song.masterVol<0) e->song.masterVol=0;
if (e->song.masterVol>3) e->song.masterVol=3;
} rightClickable
for (int i=0; i<e->song.systemLen; i++) {
snprintf(id,31,"MixS%d",i);
bool doInvert=e->song.systemVol[i]&128;
signed char vol=e->song.systemVol[i]&127;
ImGui::PushID(id);
ImGui::Text("%d. %s",i+1,getSystemName(e->song.system[i]));
ImGui::SameLine(ImGui::GetWindowWidth()-(82.0f*dpiScale));
if (ImGui::Checkbox("Invert",&doInvert)) {
e->song.systemVol[i]^=128;
}
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(50.0f*dpiScale));
if (ImGui::SliderScalar("Volume",ImGuiDataType_S8,&vol,&_ZERO,&_ONE_HUNDRED_TWENTY_SEVEN)) {
e->song.systemVol[i]=(e->song.systemVol[i]&128)|vol;
} rightClickable
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(50.0f*dpiScale));
ImGui::SliderScalar("Panning",ImGuiDataType_S8,&e->song.systemPan[i],&_MINUS_ONE_HUNDRED_TWENTY_SEVEN,&_ONE_HUNDRED_TWENTY_SEVEN); rightClickable
ImGui::PopID();
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_MIXER;
ImGui::End();
}

90
src/gui/newSong.cpp Normal file
View file

@ -0,0 +1,90 @@
/**
* 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"
void FurnaceGUI::drawNewSong() {
bool accepted=false;
ImGui::PushFont(bigFont);
ImGui::SetCursorPosX((ImGui::GetContentRegionAvail().x-ImGui::CalcTextSize("Choose a System!").x)*0.5);
ImGui::Text("Choose a System!");
ImGui::PopFont();
if (ImGui::BeginTable("sysPicker",2)) {
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");
ImGui::TableNextRow();
// CATEGORIES
ImGui::TableNextColumn();
int index=0;
for (FurnaceGUISysCategory& i: sysCategories) {
if (ImGui::Selectable(i.name,newSongCategory==index,ImGuiSelectableFlags_DontClosePopups)) { \
newSongCategory=index;
}
index++;
}
// SYSTEMS
ImGui::TableNextColumn();
if (ImGui::BeginTable("Systems",1,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollY)) {
for (FurnaceGUISysDef& i: sysCategories[newSongCategory].systems) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::Selectable(i.name,false,ImGuiSelectableFlags_DontClosePopups)) {
nextDesc=i.definition.data();
accepted=true;
}
}
ImGui::EndTable();
}
ImGui::EndTable();
}
if (ImGui::Button("Cancel")) {
ImGui::CloseCurrentPopup();
}
if (accepted) {
e->createNew(nextDesc);
undoHist.clear();
redoHist.clear();
curFileName="";
modified=false;
curNibble=false;
orderNibble=false;
orderCursor=-1;
samplePos=0;
updateSampleTex=true;
selStart=SelectionPoint();
selEnd=SelectionPoint();
cursor=SelectionPoint();
updateWindowTitle();
ImGui::CloseCurrentPopup();
}
}

47
src/gui/osc.cpp Normal file
View file

@ -0,0 +1,47 @@
/**
* 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"
void FurnaceGUI::drawOsc() {
if (nextWindow==GUI_WINDOW_OSCILLOSCOPE) {
oscOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!oscOpen) return;
ImGui::SetNextWindowSizeConstraints(ImVec2(64.0f*dpiScale,32.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0));
if (ImGui::Begin("Oscilloscope",&oscOpen)) {
float values[512];
for (int i=0; i<512; i++) {
int pos=i*e->oscSize/512;
values[i]=(e->oscBuf[0][pos]+e->oscBuf[1][pos])*0.5f;
}
//ImGui::SetCursorPos(ImVec2(0,0));
ImGui::BeginDisabled();
ImGui::PlotLines("##SingleOsc",values,512,0,NULL,-1.0f,1.0f,ImGui::GetContentRegionAvail());
ImGui::EndDisabled();
}
ImGui::PopStyleVar(3);
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_OSCILLOSCOPE;
ImGui::End();
}

46
src/gui/piano.cpp Normal file
View file

@ -0,0 +1,46 @@
/**
* 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 "guiConst.h"
void FurnaceGUI::drawPiano() {
if (nextWindow==GUI_WINDOW_PIANO) {
pianoOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!pianoOpen) return;
if (ImGui::Begin("Piano",&pianoOpen)) {
for (int i=0; i<e->getTotalChannelCount(); i++) {
DivChannelState* cs=e->getChanState(i);
if (cs->keyOn) {
const char* noteName=NULL;
if (cs->note<-60 || cs->note>120) {
noteName="???";
} else {
noteName=noteNames[cs->note+60];
}
ImGui::Text("%d: %s",i,noteName);
}
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_PIANO;
ImGui::End();
}

639
src/gui/presets.cpp Normal file
View file

@ -0,0 +1,639 @@
/**
* 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"
// add system configurations here.
// every entry is written in the following format:
// cat.systems.push_back(FurnaceGUISysDef(
// "System Name", {
// DIV_SYSTEM_???, Volume, Panning, Flags,
// DIV_SYSTEM_???, Volume, Panning, Flags,
// ...
// 0
// }
// ));
void FurnaceGUI::initSystemPresets() {
FurnaceGUISysCategory cat;
cat=FurnaceGUISysCategory("FM");
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2612", {
DIV_SYSTEM_YM2612, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2612 (extended channel 3)", {
DIV_SYSTEM_YM2612_EXT, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2151", {
DIV_SYSTEM_YM2151, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2610", {
DIV_SYSTEM_YM2610_FULL, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2610 (extended channel 2)", {
DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2610B", {
DIV_SYSTEM_YM2610B, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2610B (extended channel 3)", {
DIV_SYSTEM_YM2610B_EXT, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2413", {
DIV_SYSTEM_OPLL, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Yamaha YM2413 (drums mode)", {
DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0,
0
}
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Square");
cat.systems.push_back(FurnaceGUISysDef(
"TI SN76489", {
DIV_SYSTEM_SMS, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"AY-3-8910", {
DIV_SYSTEM_AY8910, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Philips SAA1099", {
DIV_SYSTEM_SAA1099, 64, 0, 0,
0
}
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Sample");
cat.systems.push_back(FurnaceGUISysDef(
"Amiga", {
DIV_SYSTEM_AMIGA, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"SegaPCM", {
DIV_SYSTEM_SEGAPCM, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Capcom QSound", {
DIV_SYSTEM_QSOUND, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Seta/Allumer X1-010", {
DIV_SYSTEM_X1_010, 64, 0, 0,
0
}
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Game consoles");
cat.systems.push_back(FurnaceGUISysDef(
"Sega Genesis", {
DIV_SYSTEM_YM2612, 64, 0, 0,
DIV_SYSTEM_SMS, 24, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Genesis (extended channel 3)", {
DIV_SYSTEM_YM2612_EXT, 64, 0, 0,
DIV_SYSTEM_SMS, 24, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Master System", {
DIV_SYSTEM_SMS, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Master System (with FM expansion)", {
DIV_SYSTEM_SMS, 64, 0, 0,
DIV_SYSTEM_OPLL, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Master System (with FM expansion in drums mode)", {
DIV_SYSTEM_SMS, 64, 0, 0,
DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Game Boy", {
DIV_SYSTEM_GB, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NEC PC Engine/TurboGrafx-16", {
DIV_SYSTEM_PCE, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES", {
DIV_SYSTEM_NES, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Konami VRC7", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_VRC7, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Sunsoft 5B", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_AY8910, 64, 0, 38,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Mattel Intellivision", {
DIV_SYSTEM_AY8910, 64, 0, 48,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Vectrex", {
DIV_SYSTEM_AY8910, 64, 0, 4,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Neo Geo AES", {
DIV_SYSTEM_YM2610_FULL, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Neo Geo AES (extended channel 2)", {
DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Atari 2600/7800", {
DIV_SYSTEM_TIA, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Atari Lynx", {
DIV_SYSTEM_LYNX, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"WonderSwan", {
DIV_SYSTEM_SWAN, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Gamate", {
DIV_SYSTEM_AY8910, 64, 0, 73,
0
}
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Computers");
cat.systems.push_back(FurnaceGUISysDef(
"Commodore PET", {
DIV_SYSTEM_PET, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Commodore VIC-20", {
DIV_SYSTEM_VIC20, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Commodore 64 (6581 SID)", {
DIV_SYSTEM_C64_6581, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Commodore 64 (8580 SID)", {
DIV_SYSTEM_C64_8580, 64, 0, 1,
0
}
));
/*
cat.systems.push_back(FurnaceGUISysDef(
"Commodore 64 (6581 SID + Sound Expander)", {
DIV_SYSTEM_OPL, 64, 0, 0,
DIV_SYSTEM_C64_6581, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Commodore 64 (6581 SID + Sound Expander with drums mode)", {
DIV_SYSTEM_OPL_DRUMS, 64, 0, 0,
DIV_SYSTEM_C64_6581, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Commodore 64 (8580 SID + Sound Expander)", {
DIV_SYSTEM_OPL, 64, 0, 0,
DIV_SYSTEM_C64_8580, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Commodore 64 (8580 SID + Sound Expander with drums mode)", {
DIV_SYSTEM_OPL_DRUMS, 64, 0, 0,
DIV_SYSTEM_C64_8580, 64, 0, 1,
0
}
));*/
cat.systems.push_back(FurnaceGUISysDef(
"Amiga", {
DIV_SYSTEM_AMIGA, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"MSX", {
DIV_SYSTEM_AY8910, 64, 0, 16,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"MSX + SFG-01", {
DIV_SYSTEM_YM2151, 64, 0, 0,
DIV_SYSTEM_AY8910, 64, 0, 16,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"MSX + MSX-MUSIC", {
DIV_SYSTEM_OPLL, 64, 0, 0,
DIV_SYSTEM_AY8910, 64, 0, 16,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"MSX + MSX-MUSIC (drums mode)", {
DIV_SYSTEM_OPLL_DRUMS, 64, 0, 0,
DIV_SYSTEM_AY8910, 64, 0, 16,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"ZX Spectrum (48K)", {
DIV_SYSTEM_AY8910, 64, 0, 2,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"ZX Spectrum (128K)", {
DIV_SYSTEM_AY8910, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Amstrad CPC", {
DIV_SYSTEM_AY8910, 64, 0, 5,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"SAM Coupé", {
DIV_SYSTEM_SAA1099, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"BBC Micro", {
DIV_SYSTEM_SMS, 64, 0, 6,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC (barebones)", {
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + Covox Sound Master", {
DIV_SYSTEM_AY8930, 64, 0, 3,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + SSI 2001", {
DIV_SYSTEM_C64_6581, 64, 0, 2,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + Game Blaster", {
DIV_SYSTEM_SAA1099, 64, -127, 1,
DIV_SYSTEM_SAA1099, 64, 127, 1,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + AdLib/Sound Blaster", {
DIV_SYSTEM_OPL2, 64, 0, 0,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + AdLib/Sound Blaster (drums mode)", {
DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + Sound Blaster w/Game Blaster Compatible", {
DIV_SYSTEM_OPL2, 64, 0, 0,
DIV_SYSTEM_SAA1099, 64, -127, 1,
DIV_SYSTEM_SAA1099, 64, 127, 1,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + Sound Blaster w/Game Blaster Compatible (drums mode)", {
DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0,
DIV_SYSTEM_SAA1099, 64, -127, 1,
DIV_SYSTEM_SAA1099, 64, 127, 1,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + Sound Blaster Pro 2", {
DIV_SYSTEM_OPL3, 64, 0, 0,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"PC + Sound Blaster Pro 2 (drums mode)", {
DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0,
DIV_SYSTEM_PCSPKR, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sharp X1", {
DIV_SYSTEM_AY8910, 64, 0, 3,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sharp X1 + FM Addon", {
DIV_SYSTEM_AY8910, 64, 0, 3,
DIV_SYSTEM_YM2151, 64, 0, 2,
0
}
));
/*
cat.systems.push_back(FurnaceGUISysDef(
"Sharp X68000", {
DIV_SYSTEM_YM2151, 64, 0, 2,
DIV_SYSTEM_MSM6258, 64, 0, 0,
0
}
));*/
cat.systems.push_back(FurnaceGUISysDef(
"Commander X16", {
DIV_SYSTEM_YM2151, 64, 0, 0,
DIV_SYSTEM_VERA, 64, 0, 0,
0
}
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("Arcade systems");
cat.systems.push_back(FurnaceGUISysDef(
"Bally Midway MCR", {
DIV_SYSTEM_AY8910, 64, 0, 0,
DIV_SYSTEM_AY8910, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Kyugo", {
DIV_SYSTEM_AY8910, 64, 0, 4,
DIV_SYSTEM_AY8910, 64, 0, 4,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega OutRun/X Board", {
DIV_SYSTEM_YM2151, 64, 0, 2,
DIV_SYSTEM_SEGAPCM, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Neo Geo MVS", {
DIV_SYSTEM_YM2610_FULL, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Neo Geo MVS (extended channel 2)", {
DIV_SYSTEM_YM2610_FULL_EXT, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Taito Arcade", {
DIV_SYSTEM_YM2610B, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Taito Arcade (extended channel 3)", {
DIV_SYSTEM_YM2610B_EXT, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Capcom CPS-2 (QSound)", {
DIV_SYSTEM_QSOUND, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Seta 1", {
DIV_SYSTEM_X1_010, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Seta 2", {
DIV_SYSTEM_X1_010, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Konami Bubble System", {
DIV_SYSTEM_AY8910, 64, 0, 0,
DIV_SYSTEM_AY8910, 64, 0, 0,
DIV_SYSTEM_BUBSYS_WSG, 64, 0, 0,
// VLM5030 exists but not used for music at all
0
}
));
sysCategories.push_back(cat);
cat=FurnaceGUISysCategory("DefleMask-compatible");
cat.systems.push_back(FurnaceGUISysDef(
"Sega Genesis", {
DIV_SYSTEM_YM2612, 64, 0, 0,
DIV_SYSTEM_SMS, 24, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Genesis (extended channel 3)", {
DIV_SYSTEM_YM2612_EXT, 64, 0, 0,
DIV_SYSTEM_SMS, 24, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Master System", {
DIV_SYSTEM_SMS, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Sega Master System (with FM expansion)", {
DIV_SYSTEM_SMS, 64, 0, 0,
DIV_SYSTEM_OPLL, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Game Boy", {
DIV_SYSTEM_GB, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NEC PC Engine/TurboGrafx-16", {
DIV_SYSTEM_PCE, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES", {
DIV_SYSTEM_NES, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"NES with Konami VRC7", {
DIV_SYSTEM_NES, 64, 0, 0,
DIV_SYSTEM_VRC7, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Commodore 64 (6581 SID)", {
DIV_SYSTEM_C64_6581, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Commodore 64 (8580 SID)", {
DIV_SYSTEM_C64_8580, 64, 0, 1,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Arcade (YM2151 and SegaPCM)", {
DIV_SYSTEM_YM2151, 64, 0, 0,
DIV_SYSTEM_SEGAPCM_COMPAT, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Neo Geo CD", {
DIV_SYSTEM_YM2610, 64, 0, 0,
0
}
));
cat.systems.push_back(FurnaceGUISysDef(
"Neo Geo CD (extended channel 2)", {
DIV_SYSTEM_YM2610_EXT, 64, 0, 0,
0
}
));
sysCategories.push_back(cat);
}

71
src/gui/regView.cpp Normal file
View file

@ -0,0 +1,71 @@
/**
* 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"
void FurnaceGUI::drawRegView() {
if (nextWindow==GUI_WINDOW_REGISTER_VIEW) {
channelsOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!regViewOpen) return;
if (ImGui::Begin("Register View",&regViewOpen)) {
for (int i=0; i<e->song.systemLen; i++) {
ImGui::Text("%d. %s",i+1,getSystemName(e->song.system[i]));
int size=0;
int depth=8;
unsigned char* regPool=e->getRegisterPool(i,size,depth);
unsigned short* regPoolW=(unsigned short*)regPool;
if (regPool==NULL) {
ImGui::Text("- no register pool available");
} else {
ImGui::PushFont(patFont);
if (ImGui::BeginTable("Memory",17)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
for (int i=0; i<16; i++) {
ImGui::TableNextColumn();
ImGui::TextColored(uiColors[GUI_COLOR_PATTERN_ROW_INDEX]," %X",i);
}
for (int i=0; i<=((size-1)>>4); i++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextColored(uiColors[GUI_COLOR_PATTERN_ROW_INDEX],"%.2X",i*16);
for (int j=0; j<16; j++) {
ImGui::TableNextColumn();
if (i*16+j>=size) continue;
if (depth == 8) {
ImGui::Text("%.2x",regPool[i*16+j]);
} else if (depth == 16) {
ImGui::Text("%.4x",regPoolW[i*16+j]);
} else {
ImGui::Text("??");
}
}
}
ImGui::EndTable();
}
ImGui::PopFont();
}
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_REGISTER_VIEW;
ImGui::End();
}

View file

@ -18,8 +18,10 @@
*/
#include "gui.h"
#include "fonts.h"
#include "../ta-log.h"
#include "util.h"
#include "ImGuiFileDialog.h"
#include "IconsFontAwesome4.h"
#include "misc/cpp/imgui_stdlib.h"
#include <SDL_scancode.h>
@ -1425,3 +1427,398 @@ void FurnaceGUI::commitSettings() {
}
}
}
void FurnaceGUI::parseKeybinds() {
actionMapGlobal.clear();
actionMapPat.clear();
actionMapInsList.clear();
actionMapWaveList.clear();
actionMapSampleList.clear();
actionMapOrders.clear();
for (int i=GUI_ACTION_GLOBAL_MIN+1; i<GUI_ACTION_GLOBAL_MAX; i++) {
if (actionKeys[i]&FURK_MASK) {
actionMapGlobal[actionKeys[i]]=i;
}
}
for (int i=GUI_ACTION_PAT_MIN+1; i<GUI_ACTION_PAT_MAX; i++) {
if (actionKeys[i]&FURK_MASK) {
actionMapPat[actionKeys[i]]=i;
}
}
for (int i=GUI_ACTION_INS_LIST_MIN+1; i<GUI_ACTION_INS_LIST_MAX; i++) {
if (actionKeys[i]&FURK_MASK) {
actionMapInsList[actionKeys[i]]=i;
}
}
for (int i=GUI_ACTION_WAVE_LIST_MIN+1; i<GUI_ACTION_WAVE_LIST_MAX; i++) {
if (actionKeys[i]&FURK_MASK) {
actionMapWaveList[actionKeys[i]]=i;
}
}
for (int i=GUI_ACTION_SAMPLE_LIST_MIN+1; i<GUI_ACTION_SAMPLE_LIST_MAX; i++) {
if (actionKeys[i]&FURK_MASK) {
actionMapSampleList[actionKeys[i]]=i;
}
}
for (int i=GUI_ACTION_ORDERS_MIN+1; i<GUI_ACTION_ORDERS_MAX; i++) {
if (actionKeys[i]&FURK_MASK) {
actionMapOrders[actionKeys[i]]=i;
}
}
}
#define IGFD_FileStyleByExtension IGFD_FileStyleByExtention
#define GET_UI_COLOR(target,def) \
uiColors[target]=ImGui::ColorConvertU32ToFloat4(e->getConfInt(#target,ImGui::GetColorU32(def)));
#ifdef _WIN32
#define SYSTEM_FONT_PATH_1 "C:\\Windows\\Fonts\\segoeui.ttf"
#define SYSTEM_FONT_PATH_2 "C:\\Windows\\Fonts\\tahoma.ttf"
// TODO!
#define SYSTEM_FONT_PATH_3 "C:\\Windows\\Fonts\\tahoma.ttf"
// TODO!
#define SYSTEM_PAT_FONT_PATH_1 "C:\\Windows\\Fonts\\consola.ttf"
#define SYSTEM_PAT_FONT_PATH_2 "C:\\Windows\\Fonts\\cour.ttf"
// GOOD LUCK WITH THIS ONE - UNTESTED
#define SYSTEM_PAT_FONT_PATH_3 "C:\\Windows\\Fonts\\vgasys.fon"
#elif defined(__APPLE__)
#define SYSTEM_FONT_PATH_1 "/System/Library/Fonts/SFAANS.ttf"
#define SYSTEM_FONT_PATH_2 "/System/Library/Fonts/Helvetica.ttc"
#define SYSTEM_FONT_PATH_3 "/System/Library/Fonts/Helvetica.dfont"
#define SYSTEM_PAT_FONT_PATH_1 "/System/Library/Fonts/SFNSMono.ttf"
#define SYSTEM_PAT_FONT_PATH_2 "/System/Library/Fonts/Courier New.ttf"
#define SYSTEM_PAT_FONT_PATH_3 "/System/Library/Fonts/Courier New.ttf"
#else
#define SYSTEM_FONT_PATH_1 "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
#define SYSTEM_FONT_PATH_2 "/usr/share/fonts/TTF/DejaVuSans.ttf"
#define SYSTEM_FONT_PATH_3 "/usr/share/fonts/ubuntu/Ubuntu-R.ttf"
#define SYSTEM_PAT_FONT_PATH_1 "/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf"
#define SYSTEM_PAT_FONT_PATH_2 "/usr/share/fonts/TTF/DejaVuSansMono.ttf"
#define SYSTEM_PAT_FONT_PATH_3 "/usr/share/fonts/ubuntu/UbuntuMono-R.ttf"
#endif
void FurnaceGUI::applyUISettings() {
ImGuiStyle sty;
if (settings.guiColorsBase) {
ImGui::StyleColorsLight(&sty);
} else {
ImGui::StyleColorsDark(&sty);
}
if (settings.dpiScale>=0.5f) dpiScale=settings.dpiScale;
GET_UI_COLOR(GUI_COLOR_BACKGROUND,ImVec4(0.1f,0.1f,0.1f,1.0f));
GET_UI_COLOR(GUI_COLOR_FRAME_BACKGROUND,ImVec4(0.0f,0.0f,0.0f,0.85f));
GET_UI_COLOR(GUI_COLOR_MODAL_BACKDROP,ImVec4(0.0f,0.0f,0.0f,0.55f));
GET_UI_COLOR(GUI_COLOR_HEADER,ImVec4(0.2f,0.2f,0.2f,1.0f));
GET_UI_COLOR(GUI_COLOR_TEXT,ImVec4(1.0f,1.0f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_ACCENT_PRIMARY,ImVec4(0.06f,0.53f,0.98f,1.0f));
GET_UI_COLOR(GUI_COLOR_ACCENT_SECONDARY,ImVec4(0.26f,0.59f,0.98f,1.0f));
GET_UI_COLOR(GUI_COLOR_EDITING,ImVec4(0.2f,0.1f,0.1f,1.0f));
GET_UI_COLOR(GUI_COLOR_SONG_LOOP,ImVec4(0.3f,0.5f,0.8f,0.4f));
GET_UI_COLOR(GUI_COLOR_VOLMETER_LOW,ImVec4(0.2f,0.6f,0.2f,1.0f));
GET_UI_COLOR(GUI_COLOR_VOLMETER_HIGH,ImVec4(1.0f,0.9f,0.2f,1.0f));
GET_UI_COLOR(GUI_COLOR_VOLMETER_PEAK,ImVec4(1.0f,0.1f,0.1f,1.0f));
GET_UI_COLOR(GUI_COLOR_MACRO_VOLUME,ImVec4(0.2f,1.0f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_MACRO_PITCH,ImVec4(1.0f,0.8f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_MACRO_OTHER,ImVec4(0.0f,0.9f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_MACRO_WAVE,ImVec4(1.0f,0.4f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_FM,ImVec4(0.6f,0.9f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_STD,ImVec4(0.6f,1.0f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_GB,ImVec4(1.0f,1.0f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_C64,ImVec4(0.85f,0.8f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_AMIGA,ImVec4(1.0f,0.5f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_PCE,ImVec4(1.0f,0.8f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_AY,ImVec4(1.0f,0.5f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_AY8930,ImVec4(0.7f,0.5f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_TIA,ImVec4(1.0f,0.6f,0.4f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_SAA1099,ImVec4(0.3f,0.3f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_VIC,ImVec4(0.2f,1.0f,0.6f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_PET,ImVec4(1.0f,1.0f,0.8f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_VRC6,ImVec4(1.0f,0.9f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_OPLL,ImVec4(0.6f,0.7f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_OPL,ImVec4(0.3f,1.0f,0.9f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_FDS,ImVec4(0.8f,0.5f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_VBOY,ImVec4(1.0f,0.1f,0.1f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_N163,ImVec4(1.0f,0.4f,0.1f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_SCC,ImVec4(0.7f,1.0f,0.3f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_OPZ,ImVec4(0.2f,0.8f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_POKEY,ImVec4(0.5f,1.0f,0.3f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_BEEPER,ImVec4(0.0f,1.0f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_SWAN,ImVec4(0.3f,0.5f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_MIKEY,ImVec4(0.5f,1.0f,0.3f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_VERA,ImVec4(0.4f,0.6f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_X1_010,ImVec4(0.3f,0.5f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_INSTR_UNKNOWN,ImVec4(0.3f,0.3f,0.3f,1.0f));
GET_UI_COLOR(GUI_COLOR_CHANNEL_FM,ImVec4(0.2f,0.8f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_CHANNEL_PULSE,ImVec4(0.4f,1.0f,0.2f,1.0f));
GET_UI_COLOR(GUI_COLOR_CHANNEL_NOISE,ImVec4(0.8f,0.8f,0.8f,1.0f));
GET_UI_COLOR(GUI_COLOR_CHANNEL_PCM,ImVec4(1.0f,0.9f,0.2f,1.0f));
GET_UI_COLOR(GUI_COLOR_CHANNEL_WAVE,ImVec4(1.0f,0.5f,0.2f,1.0f));
GET_UI_COLOR(GUI_COLOR_CHANNEL_OP,ImVec4(0.2f,0.4f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_CHANNEL_MUTED,ImVec4(0.5f,0.5f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_CURSOR,ImVec4(0.1f,0.3f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_CURSOR_HOVER,ImVec4(0.2f,0.4f,0.6f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_CURSOR_ACTIVE,ImVec4(0.2f,0.5f,0.7f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_SELECTION,ImVec4(0.15f,0.15f,0.2f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_SELECTION_HOVER,ImVec4(0.2f,0.2f,0.3f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_SELECTION_ACTIVE,ImVec4(0.4f,0.4f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_HI_1,ImVec4(0.6f,0.6f,0.6f,0.2f));
GET_UI_COLOR(GUI_COLOR_PATTERN_HI_2,ImVec4(0.5f,0.8f,1.0f,0.2f));
GET_UI_COLOR(GUI_COLOR_PATTERN_ROW_INDEX,ImVec4(0.5f,0.8f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_ACTIVE,ImVec4(1.0f,1.0f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_INACTIVE,ImVec4(0.5f,0.5f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_INS,ImVec4(0.4f,0.7f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_VOLUME_MIN,ImVec4(0.0f,0.5f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_VOLUME_HALF,ImVec4(0.0f,0.75f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_VOLUME_MAX,ImVec4(0.0f,1.0f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_INVALID,ImVec4(1.0f,0.0f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_PITCH,ImVec4(1.0f,1.0f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_VOLUME,ImVec4(0.0f,1.0f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_PANNING,ImVec4(0.0f,1.0f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_SONG,ImVec4(1.0f,0.0f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_TIME,ImVec4(0.5f,0.0f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_SPEED,ImVec4(1.0f,0.0f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,ImVec4(0.5f,1.0f,0.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,ImVec4(0.0f,1.0f,0.5f,1.0f));
GET_UI_COLOR(GUI_COLOR_PATTERN_EFFECT_MISC,ImVec4(0.3f,0.3f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_EE_VALUE,ImVec4(0.0f,1.0f,1.0f,1.0f));
GET_UI_COLOR(GUI_COLOR_PLAYBACK_STAT,ImVec4(0.6f,0.6f,0.6f,1.0f));
for (int i=0; i<64; i++) {
ImVec4 col1=uiColors[GUI_COLOR_PATTERN_VOLUME_MIN];
ImVec4 col2=uiColors[GUI_COLOR_PATTERN_VOLUME_HALF];
ImVec4 col3=uiColors[GUI_COLOR_PATTERN_VOLUME_MAX];
volColors[i]=ImVec4(col1.x+((col2.x-col1.x)*float(i)/64.0f),
col1.y+((col2.y-col1.y)*float(i)/64.0f),
col1.z+((col2.z-col1.z)*float(i)/64.0f),
1.0f);
volColors[i+64]=ImVec4(col2.x+((col3.x-col2.x)*float(i)/64.0f),
col2.y+((col3.y-col2.y)*float(i)/64.0f),
col2.z+((col3.z-col2.z)*float(i)/64.0f),
1.0f);
}
float hue, sat, val;
ImVec4 primaryActive=uiColors[GUI_COLOR_ACCENT_PRIMARY];
ImVec4 primaryHover, primary;
primaryHover.w=primaryActive.w;
primary.w=primaryActive.w;
ImGui::ColorConvertRGBtoHSV(primaryActive.x,primaryActive.y,primaryActive.z,hue,sat,val);
if (settings.guiColorsBase) {
primary=primaryActive;
ImGui::ColorConvertHSVtoRGB(hue,sat*0.9,val*0.9,primaryHover.x,primaryHover.y,primaryHover.z);
ImGui::ColorConvertHSVtoRGB(hue,sat,val*0.5,primaryActive.x,primaryActive.y,primaryActive.z);
} else {
ImGui::ColorConvertHSVtoRGB(hue,sat*0.9,val*0.5,primaryHover.x,primaryHover.y,primaryHover.z);
ImGui::ColorConvertHSVtoRGB(hue,sat*0.8,val*0.35,primary.x,primary.y,primary.z);
}
ImVec4 secondaryActive=uiColors[GUI_COLOR_ACCENT_SECONDARY];
ImVec4 secondaryHover, secondary, secondarySemiActive;
secondarySemiActive.w=secondaryActive.w;
secondaryHover.w=secondaryActive.w;
secondary.w=secondaryActive.w;
ImGui::ColorConvertRGBtoHSV(secondaryActive.x,secondaryActive.y,secondaryActive.z,hue,sat,val);
if (settings.guiColorsBase) {
secondary=secondaryActive;
ImGui::ColorConvertHSVtoRGB(hue,sat*0.9,val*0.7,secondarySemiActive.x,secondarySemiActive.y,secondarySemiActive.z);
ImGui::ColorConvertHSVtoRGB(hue,sat*0.9,val*0.9,secondaryHover.x,secondaryHover.y,secondaryHover.z);
ImGui::ColorConvertHSVtoRGB(hue,sat,val*0.5,secondaryActive.x,secondaryActive.y,secondaryActive.z);
} else {
ImGui::ColorConvertHSVtoRGB(hue,sat*0.9,val*0.75,secondarySemiActive.x,secondarySemiActive.y,secondarySemiActive.z);
ImGui::ColorConvertHSVtoRGB(hue,sat*0.9,val*0.5,secondaryHover.x,secondaryHover.y,secondaryHover.z);
ImGui::ColorConvertHSVtoRGB(hue,sat*0.9,val*0.25,secondary.x,secondary.y,secondary.z);
}
sty.Colors[ImGuiCol_WindowBg]=uiColors[GUI_COLOR_FRAME_BACKGROUND];
sty.Colors[ImGuiCol_ModalWindowDimBg]=uiColors[GUI_COLOR_MODAL_BACKDROP];
sty.Colors[ImGuiCol_Text]=uiColors[GUI_COLOR_TEXT];
sty.Colors[ImGuiCol_Button]=primary;
sty.Colors[ImGuiCol_ButtonHovered]=primaryHover;
sty.Colors[ImGuiCol_ButtonActive]=primaryActive;
sty.Colors[ImGuiCol_Tab]=primary;
sty.Colors[ImGuiCol_TabHovered]=secondaryHover;
sty.Colors[ImGuiCol_TabActive]=secondarySemiActive;
sty.Colors[ImGuiCol_TabUnfocused]=primary;
sty.Colors[ImGuiCol_TabUnfocusedActive]=primaryHover;
sty.Colors[ImGuiCol_Header]=secondary;
sty.Colors[ImGuiCol_HeaderHovered]=secondaryHover;
sty.Colors[ImGuiCol_HeaderActive]=secondaryActive;
sty.Colors[ImGuiCol_ResizeGrip]=secondary;
sty.Colors[ImGuiCol_ResizeGripHovered]=secondaryHover;
sty.Colors[ImGuiCol_ResizeGripActive]=secondaryActive;
sty.Colors[ImGuiCol_FrameBg]=secondary;
sty.Colors[ImGuiCol_FrameBgHovered]=secondaryHover;
sty.Colors[ImGuiCol_FrameBgActive]=secondaryActive;
sty.Colors[ImGuiCol_SliderGrab]=primaryActive;
sty.Colors[ImGuiCol_SliderGrabActive]=primaryActive;
sty.Colors[ImGuiCol_TitleBgActive]=primary;
sty.Colors[ImGuiCol_CheckMark]=primaryActive;
sty.Colors[ImGuiCol_TextSelectedBg]=secondaryHover;
sty.Colors[ImGuiCol_PlotHistogram]=uiColors[GUI_COLOR_MACRO_OTHER];
sty.Colors[ImGuiCol_PlotHistogramHovered]=uiColors[GUI_COLOR_MACRO_OTHER];
if (settings.roundedWindows) sty.WindowRounding=8.0f;
if (settings.roundedButtons) {
sty.FrameRounding=6.0f;
sty.GrabRounding=6.0f;
}
if (settings.roundedMenus) sty.PopupRounding=8.0f;
sty.ScaleAllSizes(dpiScale);
ImGui::GetStyle()=sty;
for (int i=0; i<256; i++) {
ImVec4& base=uiColors[GUI_COLOR_PATTERN_EFFECT_PITCH];
pitchGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
}
for (int i=0; i<256; i++) {
ImVec4& base=uiColors[GUI_COLOR_PATTERN_ACTIVE];
noteGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
}
for (int i=0; i<256; i++) {
ImVec4& base=uiColors[GUI_COLOR_PATTERN_EFFECT_PANNING];
panGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
}
for (int i=0; i<256; i++) {
ImVec4& base=uiColors[GUI_COLOR_PATTERN_INS];
insGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
}
for (int i=0; i<256; i++) {
ImVec4& base=volColors[i/2];
volGrad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
}
for (int i=0; i<256; i++) {
ImVec4& base=uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY];
sysCmd1Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
}
for (int i=0; i<256; i++) {
ImVec4& base=uiColors[GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY];
sysCmd2Grad[i]=ImGui::GetColorU32(ImVec4(base.x,base.y,base.z,((float)i/255.0f)*base.w));
}
// set to 800 for now due to problems with unifont
static const ImWchar loadEverything[]={0x20,0x800,0};
if (settings.mainFont<0 || settings.mainFont>6) settings.mainFont=0;
if (settings.patFont<0 || settings.patFont>6) settings.patFont=0;
if (settings.mainFont==6 && settings.mainFontPath.empty()) {
logW("UI font path is empty! reverting to default font\n");
settings.mainFont=0;
}
if (settings.patFont==6 && settings.patFontPath.empty()) {
logW("pattern font path is empty! reverting to default font\n");
settings.patFont=0;
}
if (settings.mainFont==6) { // custom font
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.mainFontPath.c_str(),e->getConfInt("mainFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logW("could not load UI font! reverting to default font\n");
settings.mainFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.\n");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
} else if (settings.mainFont==5) { // system font
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_1,e->getConfInt("mainFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_2,e->getConfInt("mainFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_FONT_PATH_3,e->getConfInt("mainFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logW("could not load UI font! reverting to default font\n");
settings.mainFont=0;
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.\n");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
}
} else {
if ((mainFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFont[settings.mainFont],builtinFontLen[settings.mainFont],e->getConfInt("mainFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logE("could not load UI font! falling back to Proggy Clean.\n");
mainFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
ImFontConfig fc;
fc.MergeMode=true;
fc.GlyphMinAdvanceX=e->getConfInt("iconSize",16)*dpiScale;
static const ImWchar fontRange[]={ICON_MIN_FA,ICON_MAX_FA,0};
if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRange))==NULL) {
logE("could not load icon font!\n");
}
if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) {
logD("using main font for pat font.\n");
patFont=mainFont;
} else {
if (settings.patFont==6) { // custom font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(settings.patFontPath.c_str(),e->getConfInt("patFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logW("could not load pattern font! reverting to default font\n");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.\n");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
} else if (settings.patFont==5) { // system font
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_1,e->getConfInt("patFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_2,e->getConfInt("patFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromFileTTF(SYSTEM_PAT_FONT_PATH_3,e->getConfInt("patFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logW("could not load pattern font! reverting to default font\n");
settings.patFont=0;
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logE("could not load pattern font! falling back to Proggy Clean.\n");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
}
} else {
if ((patFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(builtinFontM[settings.patFont],builtinFontMLen[settings.patFont],e->getConfInt("patFontSize",18)*dpiScale,NULL,loadEverything))==NULL) {
logE("could not load pattern font!\n");
patFont=ImGui::GetIO().Fonts->AddFontDefault();
}
}
}
if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) {
logE("could not load big UI font!\n");
}
// TODO: allow changing these colors.
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeDir,"",ImVec4(0.0f,1.0f,1.0f,1.0f),ICON_FA_FOLDER_O);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByTypeFile,"",ImVec4(0.7f,0.7f,0.7f,1.0f),ICON_FA_FILE_O);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fur",ImVec4(0.5f,1.0f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fui",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fuw",ImVec4(1.0f,0.75f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmf",ImVec4(0.5f,1.0f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmp",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".dmw",ImVec4(1.0f,0.75f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".wav",ImVec4(1.0f,1.0f,0.5f,1.0f),ICON_FA_FILE_AUDIO_O);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgm",ImVec4(1.0f,1.0f,0.5f,1.0f),ICON_FA_FILE_AUDIO_O);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttf",ImVec4(0.3f,1.0f,0.6f,1.0f),ICON_FA_FONT);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".otf",ImVec4(0.3f,1.0f,0.6f,1.0f),ICON_FA_FONT);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttc",ImVec4(0.3f,1.0f,0.6f,1.0f),ICON_FA_FONT);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".tfi",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgi",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".s3i",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".sbi",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".fti",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".bti",ImVec4(1.0f,0.5f,0.5f,1.0f),ICON_FA_FILE);
if (fileDialog!=NULL) delete fileDialog;
fileDialog=new FurnaceGUIFileDialog(settings.sysFileDialog);
}

173
src/gui/songInfo.cpp Normal file
View file

@ -0,0 +1,173 @@
/**
* 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 "intConst.h"
void FurnaceGUI::drawSongInfo() {
if (nextWindow==GUI_WINDOW_SONG_INFO) {
songInfoOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!songInfoOpen) return;
if (ImGui::Begin("Song Information",&songInfoOpen)) {
if (ImGui::BeginTable("NameAuthor",2,ImGuiTableFlags_SizingStretchProp)) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Name");
ImGui::TableNextColumn();
float avail=ImGui::GetContentRegionAvail().x;
ImGui::SetNextItemWidth(avail);
if (ImGui::InputText("##Name",&e->song.name)) { MARK_MODIFIED
updateWindowTitle();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Author");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
if (ImGui::InputText("##Author",&e->song.author)) {
MARK_MODIFIED;
}
ImGui::EndTable();
}
if (ImGui::BeginTable("OtherProps",3,ImGuiTableFlags_SizingStretchProp)) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("TimeBase");
ImGui::TableNextColumn();
float avail=ImGui::GetContentRegionAvail().x;
ImGui::SetNextItemWidth(avail);
unsigned char realTB=e->song.timeBase+1;
if (ImGui::InputScalar("##TimeBase",ImGuiDataType_U8,&realTB,&_ONE,&_THREE)) { MARK_MODIFIED
if (realTB<1) realTB=1;
if (realTB>16) realTB=16;
e->song.timeBase=realTB-1;
}
ImGui::TableNextColumn();
ImGui::Text("%.2f BPM",calcBPM(e->song.speed1,e->song.speed2,e->song.hz));
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Speed");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
if (ImGui::InputScalar("##Speed1",ImGuiDataType_U8,&e->song.speed1,&_ONE,&_THREE)) { MARK_MODIFIED
if (e->song.speed1<1) e->song.speed1=1;
if (e->isPlaying()) play();
}
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
if (ImGui::InputScalar("##Speed2",ImGuiDataType_U8,&e->song.speed2,&_ONE,&_THREE)) { MARK_MODIFIED
if (e->song.speed2<1) e->song.speed2=1;
if (e->isPlaying()) play();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Highlight");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
if (ImGui::InputScalar("##Highlight1",ImGuiDataType_U8,&e->song.hilightA,&_ONE,&_THREE)) {
MARK_MODIFIED;
}
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
if (ImGui::InputScalar("##Highlight2",ImGuiDataType_U8,&e->song.hilightB,&_ONE,&_THREE)) {
MARK_MODIFIED;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Pattern Length");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
int patLen=e->song.patLen;
if (ImGui::InputInt("##PatLength",&patLen,1,3)) { MARK_MODIFIED
if (patLen<1) patLen=1;
if (patLen>256) patLen=256;
e->song.patLen=patLen;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Song Length");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
int ordLen=e->song.ordersLen;
if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED
if (ordLen<1) ordLen=1;
if (ordLen>127) ordLen=127;
e->song.ordersLen=ordLen;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::Selectable(tempoView?"Base Tempo##TempoOrHz":"Tick Rate##TempoOrHz")) {
tempoView=!tempoView;
}
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(avail);
float setHz=tempoView?e->song.hz*2.5:e->song.hz;
if (ImGui::InputFloat("##Rate",&setHz,1.0f,1.0f,"%g")) { MARK_MODIFIED
if (tempoView) setHz/=2.5;
if (setHz<10) setHz=10;
if (setHz>999) setHz=999;
e->setSongRate(setHz,setHz<52);
}
if (tempoView) {
ImGui::TableNextColumn();
ImGui::Text("= %gHz",e->song.hz);
} else {
if (e->song.hz>=49.98 && e->song.hz<=50.02) {
ImGui::TableNextColumn();
ImGui::Text("PAL");
}
if (e->song.hz>=59.9 && e->song.hz<=60.11) {
ImGui::TableNextColumn();
ImGui::Text("NTSC");
}
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::Text("Tuning (A-4)");
ImGui::TableNextColumn();
float tune=e->song.tuning;
ImGui::SetNextItemWidth(avail);
if (ImGui::InputFloat("##Tuning",&tune,1.0f,3.0f,"%g")) { MARK_MODIFIED
if (tune<220.0f) tune=220.0f;
if (tune>880.0f) tune=880.0f;
e->song.tuning=tune;
}
ImGui::EndTable();
}
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_SONG_INFO;
ImGui::End();
}

37
src/gui/songNotes.cpp Normal file
View file

@ -0,0 +1,37 @@
/**
* 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"
// NOTE: please don't ask me to enable text wrap.
// Dear ImGui doesn't have that feature. D:
void FurnaceGUI::drawNotes() {
if (nextWindow==GUI_WINDOW_NOTES) {
notesOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!notesOpen) return;
if (ImGui::Begin("Song Comments",&notesOpen)) {
ImGui::InputTextMultiline("##SongNotes",&e->song.notes,ImGui::GetContentRegionAvail());
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_NOTES;
ImGui::End();
}

50
src/gui/stats.cpp Normal file
View file

@ -0,0 +1,50 @@
/**
* 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 <fmt/printf.h>
void FurnaceGUI::drawStats() {
if (nextWindow==GUI_WINDOW_STATS) {
statsOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!statsOpen) return;
if (ImGui::Begin("Statistics",&statsOpen)) {
String adpcmAUsage=fmt::sprintf("%d/16384KB",e->adpcmAMemLen/1024);
String adpcmBUsage=fmt::sprintf("%d/16384KB",e->adpcmBMemLen/1024);
String qsoundUsage=fmt::sprintf("%d/16384KB",e->qsoundMemLen/1024);
String x1_010Usage=fmt::sprintf("%d/1024KB",e->x1_010MemLen/1024);
ImGui::Text("ADPCM-A");
ImGui::SameLine();
ImGui::ProgressBar(((float)e->adpcmAMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmAUsage.c_str());
ImGui::Text("ADPCM-B");
ImGui::SameLine();
ImGui::ProgressBar(((float)e->adpcmBMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),adpcmBUsage.c_str());
ImGui::Text("QSound");
ImGui::SameLine();
ImGui::ProgressBar(((float)e->qsoundMemLen)/16777216.0f,ImVec2(-FLT_MIN,0),qsoundUsage.c_str());
ImGui::Text("X1-010");
ImGui::SameLine();
ImGui::ProgressBar(((float)e->x1_010MemLen)/1048576.0f,ImVec2(-FLT_MIN,0),x1_010Usage.c_str());
}
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_STATS;
ImGui::End();
}

371
src/gui/sysConf.cpp Normal file
View file

@ -0,0 +1,371 @@
/**
* 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"
void FurnaceGUI::drawSysConf(int i) {
unsigned int flags=e->song.systemFlags[i];
bool restart=settings.restartOnFlagChange;
bool sysPal=flags&1;
switch (e->song.system[i]) {
case DIV_SYSTEM_YM2612:
case DIV_SYSTEM_YM2612_EXT: {
if (ImGui::RadioButton("NTSC (7.67MHz)",(flags&3)==0)) {
e->setSysFlags(i,(flags&0x80000000)|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("PAL (7.61MHz)",(flags&3)==1)) {
e->setSysFlags(i,(flags&0x80000000)|1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("FM Towns (8MHz)",(flags&3)==2)) {
e->setSysFlags(i,(flags&0x80000000)|2,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("AtGames Genesis (6.13MHz)",(flags&3)==3)) {
e->setSysFlags(i,(flags&0x80000000)|3,restart);
updateWindowTitle();
}
bool ladder=flags&0x80000000;
if (ImGui::Checkbox("Enable DAC distortion",&ladder)) {
e->setSysFlags(i,(flags&(~0x80000000))|(ladder?0x80000000:0),restart);
updateWindowTitle();
}
break;
}
case DIV_SYSTEM_SMS: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&3)==0)) {
e->setSysFlags(i,(flags&(~3))|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("PAL (3.55MHz)",(flags&3)==1)) {
e->setSysFlags(i,(flags&(~3))|1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&3)==2)) {
e->setSysFlags(i,(flags&(~3))|2,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&3)==3)) {
e->setSysFlags(i,(flags&(~3))|3,restart);
updateWindowTitle();
}
ImGui::Text("Chip type:");
if (ImGui::RadioButton("Sega VDP/Master System",((flags>>2)&3)==0)) {
e->setSysFlags(i,(flags&(~12))|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("TI SN76489",((flags>>2)&3)==1)) {
e->setSysFlags(i,(flags&(~12))|4,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("TI SN76489 with Atari-like short noise",((flags>>2)&3)==2)) {
e->setSysFlags(i,(flags&(~12))|8,restart);
updateWindowTitle();
}
/*if (ImGui::RadioButton("Game Gear",(flags>>2)==3)) {
e->setSysFlags(i,(flags&3)|12);
}*/
bool noPhaseReset=flags&16;
if (ImGui::Checkbox("Disable noise period change phase reset",&noPhaseReset)) {
e->setSysFlags(i,(flags&(~16))|(noPhaseReset<<4),restart);
updateWindowTitle();
}
break;
}
case DIV_SYSTEM_OPLL:
case DIV_SYSTEM_OPLL_DRUMS:
case DIV_SYSTEM_VRC7: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("NTSC (3.58MHz)",(flags&15)==0)) {
e->setSysFlags(i,(flags&(~15))|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("PAL (3.55MHz)",(flags&15)==1)) {
e->setSysFlags(i,(flags&(~15))|1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&15)==2)) {
e->setSysFlags(i,(flags&(~15))|2,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&15)==3)) {
e->setSysFlags(i,(flags&(~15))|3,restart);
updateWindowTitle();
}
if (e->song.system[i]!=DIV_SYSTEM_VRC7) {
ImGui::Text("Patch set:");
if (ImGui::RadioButton("Yamaha YM2413",((flags>>4)&15)==0)) {
e->setSysFlags(i,(flags&(~0xf0))|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Yamaha YMF281",((flags>>4)&15)==1)) {
e->setSysFlags(i,(flags&(~0xf0))|0x10,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Yamaha YM2423",((flags>>4)&15)==2)) {
e->setSysFlags(i,(flags&(~0xf0))|0x20,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Konami VRC7",((flags>>4)&15)==3)) {
e->setSysFlags(i,(flags&(~0xf0))|0x30,restart);
updateWindowTitle();
}
}
break;
}
case DIV_SYSTEM_YM2151:
if (ImGui::RadioButton("NTSC/X16 (3.58MHz)",flags==0)) {
e->setSysFlags(i,0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("PAL (3.55MHz)",flags==1)) {
e->setSysFlags(i,1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("X1/X68000 (4MHz)",flags==2)) {
e->setSysFlags(i,2,restart);
updateWindowTitle();
}
break;
case DIV_SYSTEM_NES:
if (ImGui::RadioButton("NTSC (1.79MHz)",flags==0)) {
e->setSysFlags(i,0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("PAL (1.67MHz)",flags==1)) {
e->setSysFlags(i,1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Dendy (1.77MHz)",flags==2)) {
e->setSysFlags(i,2,restart);
updateWindowTitle();
}
break;
case DIV_SYSTEM_C64_8580:
case DIV_SYSTEM_C64_6581:
if (ImGui::RadioButton("NTSC (1.02MHz)",flags==0)) {
e->setSysFlags(i,0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("PAL (0.99MHz)",flags==1)) {
e->setSysFlags(i,1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("SSI 2001 (0.89MHz)",flags==2)) {
e->setSysFlags(i,2,restart);
updateWindowTitle();
}
break;
case DIV_SYSTEM_AY8910:
case DIV_SYSTEM_AY8930: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("1.79MHz (ZX Spectrum NTSC/MSX)",(flags&15)==0)) {
e->setSysFlags(i,(flags&(~15))|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("1.77MHz (ZX Spectrum)",(flags&15)==1)) {
e->setSysFlags(i,(flags&(~15))|1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("1.75MHz (ZX Spectrum)",(flags&15)==2)) {
e->setSysFlags(i,(flags&(~15))|2,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("2MHz (Atari ST/Sharp X1)",(flags&15)==3)) {
e->setSysFlags(i,(flags&(~15))|3,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("1.5MHz (Vectrex)",(flags&15)==4)) {
e->setSysFlags(i,(flags&(~15))|4,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("1MHz (Amstrad CPC)",(flags&15)==5)) {
e->setSysFlags(i,(flags&(~15))|5,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("0.89MHz (Sunsoft 5B)",(flags&15)==6)) {
e->setSysFlags(i,(flags&(~15))|6,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("1.67MHz (?)",(flags&15)==7)) {
e->setSysFlags(i,(flags&(~15))|7,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("0.83MHz (Sunsoft 5B on PAL)",(flags&15)==8)) {
e->setSysFlags(i,(flags&(~15))|8,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("1.10MHz (Gamate/VIC-20 PAL)",(flags&15)==9)) {
e->setSysFlags(i,(flags&(~15))|9,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("2^21Hz (Game Boy)",(flags&15)==10)) {
e->setSysFlags(i,(flags&(~15))|10,restart);
updateWindowTitle();
}
if (e->song.system[i]==DIV_SYSTEM_AY8910) {
ImGui::Text("Chip type:");
if (ImGui::RadioButton("AY-3-8910",(flags&0x30)==0)) {
e->setSysFlags(i,(flags&(~0x30))|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("YM2149(F)",(flags&0x30)==16)) {
e->setSysFlags(i,(flags&(~0x30))|16,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Sunsoft 5B",(flags&0x30)==32)) {
e->setSysFlags(i,(flags&(~0x30))|32,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("AY-3-8914",(flags&0x30)==48)) {
e->setSysFlags(i,(flags&(~0x30))|48,restart);
updateWindowTitle();
}
}
bool stereo=flags&0x40;
ImGui::BeginDisabled((flags&0x30)==32);
if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) {
e->setSysFlags(i,(flags&(~0x40))|(stereo?0x40:0),restart);
updateWindowTitle();
}
ImGui::EndDisabled();
break;
}
case DIV_SYSTEM_SAA1099:
if (ImGui::RadioButton("SAM Coupé (8MHz)",flags==0)) {
e->setSysFlags(i,0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("NTSC (7.15MHz)",flags==1)) {
e->setSysFlags(i,1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("PAL (7.09MHz)",flags==2)) {
e->setSysFlags(i,2,restart);
updateWindowTitle();
}
break;
case DIV_SYSTEM_AMIGA: {
ImGui::Text("Stereo separation:");
int stereoSep=(flags>>8)&127;
if (ImGui::SliderInt("##StereoSep",&stereoSep,0,127)) {
if (stereoSep<0) stereoSep=0;
if (stereoSep>127) stereoSep=127;
e->setSysFlags(i,(flags&(~0x7f00))|((stereoSep&127)<<8),restart);
updateWindowTitle();
} rightClickable
if (ImGui::RadioButton("Amiga 500 (OCS)",(flags&2)==0)) {
e->setSysFlags(i,flags&(~2),restart);
}
if (ImGui::RadioButton("Amiga 1200 (AGA)",(flags&2)==2)) {
e->setSysFlags(i,(flags&(~2))|2,restart);
}
sysPal=flags&1;
if (ImGui::Checkbox("PAL",&sysPal)) {
e->setSysFlags(i,(flags&(~1))|sysPal,restart);
updateWindowTitle();
}
bool bypassLimits=flags&4;
if (ImGui::Checkbox("Bypass frequency limits",&bypassLimits)) {
e->setSysFlags(i,(flags&(~4))|(bypassLimits<<2),restart);
updateWindowTitle();
}
break;
}
case DIV_SYSTEM_PCSPKR: {
ImGui::Text("Speaker type:");
if (ImGui::RadioButton("Unfiltered",(flags&3)==0)) {
e->setSysFlags(i,(flags&(~3))|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Cone",(flags&3)==1)) {
e->setSysFlags(i,(flags&(~3))|1,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Piezo",(flags&3)==2)) {
e->setSysFlags(i,(flags&(~3))|2,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("Use system beeper (Linux only!)",(flags&3)==3)) {
e->setSysFlags(i,(flags&(~3))|3,restart);
updateWindowTitle();
}
break;
}
case DIV_SYSTEM_QSOUND: {
ImGui::Text("Echo delay:");
int echoBufSize=2725 - (flags & 4095);
if (ImGui::SliderInt("##EchoBufSize",&echoBufSize,0,2725)) {
if (echoBufSize<0) echoBufSize=0;
if (echoBufSize>2725) echoBufSize=2725;
e->setSysFlags(i,(flags & ~4095) | ((2725 - echoBufSize) & 4095),restart);
updateWindowTitle();
} rightClickable
ImGui::Text("Echo feedback:");
int echoFeedback=(flags>>12)&255;
if (ImGui::SliderInt("##EchoFeedback",&echoFeedback,0,255)) {
if (echoFeedback<0) echoFeedback=0;
if (echoFeedback>255) echoFeedback=255;
e->setSysFlags(i,(flags & ~(255 << 12)) | ((echoFeedback & 255) << 12),restart);
updateWindowTitle();
} rightClickable
break;
}
case DIV_SYSTEM_X1_010: {
ImGui::Text("Clock rate:");
if (ImGui::RadioButton("16MHz (Seta 1)",(flags&15)==0)) {
e->setSysFlags(i,(flags&(~15))|0,restart);
updateWindowTitle();
}
if (ImGui::RadioButton("16.67MHz (Seta 2)",(flags&15)==1)) {
e->setSysFlags(i,(flags&(~15))|1,restart);
updateWindowTitle();
}
bool x1_010Stereo=flags&16;
if (ImGui::Checkbox("Stereo",&x1_010Stereo)) {
e->setSysFlags(i,(flags&(~16))|(x1_010Stereo<<4),restart);
updateWindowTitle();
}
break;
}
case DIV_SYSTEM_GB:
case DIV_SYSTEM_SWAN:
case DIV_SYSTEM_VERA:
case DIV_SYSTEM_BUBSYS_WSG:
case DIV_SYSTEM_YM2610:
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL:
case DIV_SYSTEM_YM2610_FULL_EXT:
case DIV_SYSTEM_YM2610B:
case DIV_SYSTEM_YM2610B_EXT:
case DIV_SYSTEM_YMU759:
case DIV_SYSTEM_PET:
ImGui::Text("nothing to configure");
break;
default:
if (ImGui::Checkbox("PAL",&sysPal)) {
e->setSysFlags(i,sysPal,restart);
updateWindowTitle();
}
break;
}
}

111
src/gui/volMeter.cpp Normal file
View file

@ -0,0 +1,111 @@
/**
* 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 "imgui_internal.h"
void FurnaceGUI::drawVolMeter() {
if (nextWindow==GUI_WINDOW_VOL_METER) {
volMeterOpen=true;
ImGui::SetNextWindowFocus();
nextWindow=GUI_WINDOW_NOTHING;
}
if (!volMeterOpen) return;
if (--isClipping<0) isClipping=0;
ImGui::SetNextWindowSizeConstraints(ImVec2(6.0f*dpiScale,6.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0,0));
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing,ImVec2(0,0));
if (ImGui::Begin("Volume Meter",&volMeterOpen)) {
ImDrawList* dl=ImGui::GetWindowDrawList();
bool aspectRatio=(ImGui::GetWindowSize().x/ImGui::GetWindowSize().y)>1.0;
ImVec2 minArea=ImVec2(
ImGui::GetWindowPos().x+ImGui::GetCursorPos().x,
ImGui::GetWindowPos().y+ImGui::GetCursorPos().y
);
ImVec2 maxArea=ImVec2(
ImGui::GetWindowPos().x+ImGui::GetCursorPos().x+ImGui::GetContentRegionAvail().x,
ImGui::GetWindowPos().y+ImGui::GetCursorPos().y+ImGui::GetContentRegionAvail().y
);
ImRect rect=ImRect(minArea,maxArea);
ImGuiStyle& style=ImGui::GetStyle();
ImGui::ItemSize(ImVec2(4.0f,4.0f),style.FramePadding.y);
ImU32 lowColor=ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_LOW]);
float peakDecay=0.05f*60.0f*ImGui::GetIO().DeltaTime;
if (ImGui::ItemAdd(rect,ImGui::GetID("volMeter"))) {
ImGui::RenderFrame(rect.Min,rect.Max,ImGui::GetColorU32(ImGuiCol_FrameBg),true,style.FrameRounding);
for (int i=0; i<2; i++) {
peak[i]*=1.0-peakDecay;
if (peak[i]<0.0001) peak[i]=0.0;
for (int j=0; j<e->oscSize; j++) {
if (fabs(e->oscBuf[i][j])>peak[i]) {
peak[i]=fabs(e->oscBuf[i][j]);
}
}
float logPeak=(20*log10(peak[i])/36.0);
if (logPeak==NAN) logPeak=0.0;
if (logPeak<-1.0) logPeak=-1.0;
if (logPeak>0.0) {
isClipping=8;
logPeak=0.0;
}
logPeak+=1.0;
ImU32 highColor=ImGui::GetColorU32(
ImLerp(uiColors[GUI_COLOR_VOLMETER_LOW],uiColors[GUI_COLOR_VOLMETER_HIGH],logPeak)
);
ImRect s;
if (aspectRatio) {
s=ImRect(
ImLerp(rect.Min,rect.Max,ImVec2(0,float(i)*0.5)),
ImLerp(rect.Min,rect.Max,ImVec2(logPeak,float(i+1)*0.5))
);
if (i==0) s.Max.y-=dpiScale;
if (isClipping) {
dl->AddRectFilled(s.Min,s.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_PEAK]));
} else {
dl->AddRectFilledMultiColor(s.Min,s.Max,lowColor,highColor,highColor,lowColor);
}
} else {
s=ImRect(
ImLerp(rect.Min,rect.Max,ImVec2(float(i)*0.5,1.0-logPeak)),
ImLerp(rect.Min,rect.Max,ImVec2(float(i+1)*0.5,1.0))
);
if (i==0) s.Max.x-=dpiScale;
if (isClipping) {
dl->AddRectFilled(s.Min,s.Max,ImGui::GetColorU32(uiColors[GUI_COLOR_VOLMETER_PEAK]));
} else {
dl->AddRectFilledMultiColor(s.Min,s.Max,highColor,highColor,lowColor,lowColor);
}
}
}
if (ImGui::IsItemHovered()) {
if (aspectRatio) {
ImGui::SetTooltip("%.1fdB",36*((ImGui::GetMousePos().x-ImGui::GetItemRectMin().x)/(rect.Max.x-rect.Min.x)-1.0));
} else {
ImGui::SetTooltip("%.1fdB",-(36+36*((ImGui::GetMousePos().y-ImGui::GetItemRectMin().y)/(rect.Max.y-rect.Min.y)-1.0)));
}
}
}
}
ImGui::PopStyleVar(4);
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_VOL_METER;
ImGui::End();
}

View file

@ -1,3 +1,22 @@
/**
* 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 "plot_nolerp.h"
#include "misc/cpp/imgui_stdlib.h"