mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-30 08:23:01 +00:00
GUI: prepare to add more macro editor layouts
This commit is contained in:
parent
bf5b088a54
commit
c7b2227ee0
3 changed files with 582 additions and 481 deletions
|
@ -1222,6 +1222,7 @@ class FurnaceGUI {
|
|||
int persistFadeOut;
|
||||
int exportLoops;
|
||||
double exportFadeOut;
|
||||
int macroLayout;
|
||||
unsigned int maxUndoSteps;
|
||||
String mainFontPath;
|
||||
String patFontPath;
|
||||
|
@ -1352,6 +1353,7 @@ class FurnaceGUI {
|
|||
persistFadeOut(1),
|
||||
exportLoops(0),
|
||||
exportFadeOut(0.0),
|
||||
macroLayout(0),
|
||||
maxUndoSteps(100),
|
||||
mainFontPath(""),
|
||||
patFontPath(""),
|
||||
|
@ -1684,6 +1686,7 @@ class FurnaceGUI {
|
|||
|
||||
void patternRow(int i, bool isPlaying, float lineHeight, int chans, int ord, const DivPattern** patCache, bool inhibitSel);
|
||||
|
||||
void drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index);
|
||||
void drawMacros(std::vector<FurnaceGUIMacroDesc>& macros);
|
||||
|
||||
void actualWaveList();
|
||||
|
|
|
@ -1294,140 +1294,13 @@ void FurnaceGUI::kvsConfig(DivInstrument* ins) {
|
|||
}
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
||||
float asFloat[256];
|
||||
int asInt[256];
|
||||
float loopIndicator[256];
|
||||
float bit30Indicator[256];
|
||||
bool doHighlight[256];
|
||||
int index=0;
|
||||
void FurnaceGUI::drawMacroEdit(FurnaceGUIMacroDesc& i, int totalFit, float availableWidth, int index) {
|
||||
static float asFloat[256];
|
||||
static int asInt[256];
|
||||
static float loopIndicator[256];
|
||||
static float bit30Indicator[256];
|
||||
static bool doHighlight[256];
|
||||
|
||||
float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize;
|
||||
|
||||
if (ImGui::BeginTable("MacroSpace",2)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
float lenAvail=ImGui::GetContentRegionAvail().x;
|
||||
//ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale));
|
||||
ImGui::SetNextItemWidth(120.0f*dpiScale);
|
||||
if (ImGui::InputInt("##MacroPointSize",¯oPointSize,1,16)) {
|
||||
if (macroPointSize<1) macroPointSize=1;
|
||||
if (macroPointSize>256) macroPointSize=256;
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace;
|
||||
int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale));
|
||||
if (macroDragScroll>255-totalFit) {
|
||||
macroDragScroll=255-totalFit;
|
||||
}
|
||||
ImGui::SetNextItemWidth(availableWidth);
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) {
|
||||
if (macroDragScroll<0) macroDragScroll=0;
|
||||
if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit;
|
||||
}
|
||||
|
||||
// draw macros
|
||||
for (FurnaceGUIMacroDesc& i: macros) {
|
||||
ImGui::PushID(index);
|
||||
ImGui::TableNextRow();
|
||||
|
||||
// description
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",i.displayName);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) {
|
||||
i.macro->open^=1;
|
||||
}
|
||||
if (i.macro->open&1) {
|
||||
if ((i.macro->open&6)==0) {
|
||||
ImGui::SetNextItemWidth(lenAvail);
|
||||
int macroLen=i.macro->len;
|
||||
if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED
|
||||
if (macroLen<0) macroLen=0;
|
||||
if (macroLen>255) macroLen=255;
|
||||
i.macro->len=macroLen;
|
||||
}
|
||||
}
|
||||
if (ImGui::Button(macroTypeLabels[(i.macro->open>>1)&3])) {
|
||||
unsigned char prevOpen=i.macro->open;
|
||||
i.macro->open+=2;
|
||||
if (i.macro->open>=6) {
|
||||
i.macro->open-=6;
|
||||
}
|
||||
|
||||
// check whether macro type is now ADSR/LFO or sequence
|
||||
if (((prevOpen&6)?1:0)!=((i.macro->open&6)?1:0)) {
|
||||
// swap memory
|
||||
// this way the macro isn't corrupted if the user decides to go
|
||||
// back to sequence mode
|
||||
i.macro->len^=i.macro->lenMemory;
|
||||
i.macro->lenMemory^=i.macro->len;
|
||||
i.macro->len^=i.macro->lenMemory;
|
||||
|
||||
for (int j=0; j<16; j++) {
|
||||
i.macro->val[j]^=i.macro->typeMemory[j];
|
||||
i.macro->typeMemory[j]^=i.macro->val[j];
|
||||
i.macro->val[j]^=i.macro->typeMemory[j];
|
||||
}
|
||||
|
||||
// if ADSR/LFO, populate min/max
|
||||
if (i.macro->open&6) {
|
||||
i.macro->val[0]=i.min;
|
||||
i.macro->val[1]=i.max;
|
||||
}
|
||||
}
|
||||
PARAMETER;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
switch (i.macro->open&6) {
|
||||
case 0:
|
||||
ImGui::SetTooltip("Macro type: Sequence");
|
||||
break;
|
||||
case 2:
|
||||
ImGui::SetTooltip("Macro type: ADSR");
|
||||
break;
|
||||
case 4:
|
||||
ImGui::SetTooltip("Macro type: LFO");
|
||||
break;
|
||||
default:
|
||||
ImGui::SetTooltip("Macro type: What's going on here?");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i.macro->open&6) {
|
||||
i.macro->len=16;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Delay/Step Length");
|
||||
}
|
||||
if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) {
|
||||
if (i.macro->speed<1) i.macro->speed=1;
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) {
|
||||
MARK_MODIFIED;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
// do not change this!
|
||||
// anything other than a checkbox will look ugly!
|
||||
// if you really need more than two macro modes please tell me.
|
||||
if (i.modeName!=NULL) {
|
||||
bool modeVal=i.macro->mode;
|
||||
String modeName=fmt::sprintf("%s##IMacroMode",i.modeName);
|
||||
if (ImGui::Checkbox(modeName.c_str(),&modeVal)) {
|
||||
i.macro->mode=modeVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// macro area
|
||||
ImGui::TableNextColumn();
|
||||
if ((i.macro->open&6)==0) {
|
||||
for (int j=0; j<256; j++) {
|
||||
bit30Indicator[j]=0;
|
||||
|
@ -1793,6 +1666,144 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define BUTTON_TO_SET_MODE(buttonType) \
|
||||
if (buttonType(macroTypeLabels[(i.macro->open>>1)&3])) { \
|
||||
unsigned char prevOpen=i.macro->open; \
|
||||
i.macro->open+=2; \
|
||||
if (i.macro->open>=6) { \
|
||||
i.macro->open-=6; \
|
||||
} \
|
||||
\
|
||||
/* check whether macro type is now ADSR/LFO or sequence */ \
|
||||
if (((prevOpen&6)?1:0)!=((i.macro->open&6)?1:0)) { \
|
||||
/* swap memory */ \
|
||||
/* this way the macro isn't corrupted if the user decides to go */ \
|
||||
/* back to sequence mode */ \
|
||||
i.macro->len^=i.macro->lenMemory; \
|
||||
i.macro->lenMemory^=i.macro->len; \
|
||||
i.macro->len^=i.macro->lenMemory; \
|
||||
\
|
||||
for (int j=0; j<16; j++) { \
|
||||
i.macro->val[j]^=i.macro->typeMemory[j]; \
|
||||
i.macro->typeMemory[j]^=i.macro->val[j]; \
|
||||
i.macro->val[j]^=i.macro->typeMemory[j]; \
|
||||
} \
|
||||
\
|
||||
/* if ADSR/LFO, populate min/max */ \
|
||||
if (i.macro->open&6) { \
|
||||
i.macro->val[0]=i.min; \
|
||||
i.macro->val[1]=i.max; \
|
||||
} \
|
||||
} \
|
||||
PARAMETER; \
|
||||
} \
|
||||
if (ImGui::IsItemHovered()) { \
|
||||
switch (i.macro->open&6) { \
|
||||
case 0: \
|
||||
ImGui::SetTooltip("Macro type: Sequence"); \
|
||||
break; \
|
||||
case 2: \
|
||||
ImGui::SetTooltip("Macro type: ADSR"); \
|
||||
break; \
|
||||
case 4: \
|
||||
ImGui::SetTooltip("Macro type: LFO"); \
|
||||
break; \
|
||||
default: \
|
||||
ImGui::SetTooltip("Macro type: What's going on here?"); \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
if (i.macro->open&6) { \
|
||||
i.macro->len=16; \
|
||||
}
|
||||
|
||||
#define BUTTON_TO_SET_PROPS \
|
||||
ImGui::Button(ICON_FA_ELLIPSIS_H "##IMacroSet"); \
|
||||
if (ImGui::IsItemHovered()) { \
|
||||
ImGui::SetTooltip("Delay/Step Length"); \
|
||||
} \
|
||||
if (ImGui::BeginPopupContextItem("IMacroSetP",ImGuiPopupFlags_MouseButtonLeft)) { \
|
||||
if (ImGui::InputScalar("Step Length (ticks)##IMacroSpeed",ImGuiDataType_U8,&i.macro->speed,&_ONE,&_THREE)) { \
|
||||
if (i.macro->speed<1) i.macro->speed=1; \
|
||||
MARK_MODIFIED; \
|
||||
} \
|
||||
if (ImGui::InputScalar("Delay##IMacroDelay",ImGuiDataType_U8,&i.macro->delay,&_ONE,&_THREE)) { \
|
||||
MARK_MODIFIED; \
|
||||
} \
|
||||
ImGui::EndPopup(); \
|
||||
}
|
||||
|
||||
void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
||||
int index=0;
|
||||
float reservedSpace=(settings.oldMacroVSlider)?(20.0f*dpiScale+ImGui::GetStyle().ItemSpacing.x):ImGui::GetStyle().ScrollbarSize;
|
||||
switch (settings.macroLayout) {
|
||||
case 0: {
|
||||
if (ImGui::BeginTable("MacroSpace",2)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0);
|
||||
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
float lenAvail=ImGui::GetContentRegionAvail().x;
|
||||
//ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale));
|
||||
ImGui::SetNextItemWidth(120.0f*dpiScale);
|
||||
if (ImGui::InputInt("##MacroPointSize",¯oPointSize,1,16)) {
|
||||
if (macroPointSize<1) macroPointSize=1;
|
||||
if (macroPointSize>256) macroPointSize=256;
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace;
|
||||
int totalFit=MIN(255,availableWidth/MAX(1,macroPointSize*dpiScale));
|
||||
if (macroDragScroll>255-totalFit) {
|
||||
macroDragScroll=255-totalFit;
|
||||
}
|
||||
ImGui::SetNextItemWidth(availableWidth);
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,255-totalFit,"")) {
|
||||
if (macroDragScroll<0) macroDragScroll=0;
|
||||
if (macroDragScroll>255-totalFit) macroDragScroll=255-totalFit;
|
||||
}
|
||||
|
||||
// draw macros
|
||||
for (FurnaceGUIMacroDesc& i: macros) {
|
||||
ImGui::PushID(index);
|
||||
ImGui::TableNextRow();
|
||||
|
||||
// description
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s",i.displayName);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) {
|
||||
i.macro->open^=1;
|
||||
}
|
||||
if (i.macro->open&1) {
|
||||
if ((i.macro->open&6)==0) {
|
||||
ImGui::SetNextItemWidth(lenAvail);
|
||||
int macroLen=i.macro->len;
|
||||
if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED
|
||||
if (macroLen<0) macroLen=0;
|
||||
if (macroLen>255) macroLen=255;
|
||||
i.macro->len=macroLen;
|
||||
}
|
||||
}
|
||||
BUTTON_TO_SET_MODE(ImGui::Button);
|
||||
ImGui::SameLine();
|
||||
BUTTON_TO_SET_PROPS;
|
||||
// do not change this!
|
||||
// anything other than a checkbox will look ugly!
|
||||
// if you really need more than two macro modes please tell me.
|
||||
if (i.modeName!=NULL) {
|
||||
bool modeVal=i.macro->mode;
|
||||
String modeName=fmt::sprintf("%s##IMacroMode",i.modeName);
|
||||
if (ImGui::Checkbox(modeName.c_str(),&modeVal)) {
|
||||
i.macro->mode=modeVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// macro area
|
||||
ImGui::TableNextColumn();
|
||||
drawMacroEdit(i,totalFit,availableWidth,index);
|
||||
ImGui::PopID();
|
||||
index++;
|
||||
}
|
||||
|
@ -1807,6 +1818,73 @@ void FurnaceGUI::drawMacros(std::vector<FurnaceGUIMacroDesc>& macros) {
|
|||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
ImGui::Text("Mobile");
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
for (FurnaceGUIMacroDesc& i: macros) {
|
||||
if (index>0) ImGui::Separator();
|
||||
|
||||
float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace;
|
||||
int totalFit=i.macro->len;
|
||||
if (totalFit<1) totalFit=1;
|
||||
|
||||
ImGui::PushID(index);
|
||||
|
||||
ImGui::TextUnformatted(i.displayName);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton((i.macro->open&1)?(ICON_FA_CHEVRON_UP "##IMacroOpen"):(ICON_FA_CHEVRON_DOWN "##IMacroOpen"))) {
|
||||
i.macro->open^=1;
|
||||
}
|
||||
|
||||
if (i.macro->open&1) {
|
||||
ImGui::SameLine();
|
||||
BUTTON_TO_SET_MODE(ImGui::Button);
|
||||
}
|
||||
|
||||
drawMacroEdit(i,totalFit,availableWidth,index);
|
||||
|
||||
if (i.macro->open&1) {
|
||||
if ((i.macro->open&6)==0) {
|
||||
ImGui::Text("Length");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(120.0f*dpiScale);
|
||||
int macroLen=i.macro->len;
|
||||
if (ImGui::InputScalar("##IMacroLen",ImGuiDataType_U8,¯oLen,&_ONE,&_THREE)) { MARK_MODIFIED
|
||||
if (macroLen<0) macroLen=0;
|
||||
if (macroLen>255) macroLen=255;
|
||||
i.macro->len=macroLen;
|
||||
}
|
||||
ImGui::SameLine();
|
||||
}
|
||||
BUTTON_TO_SET_PROPS;
|
||||
if (i.modeName!=NULL) {
|
||||
bool modeVal=i.macro->mode;
|
||||
String modeName=fmt::sprintf("%s##IMacroMode",i.modeName);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox(modeName.c_str(),&modeVal)) {
|
||||
i.macro->mode=modeVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
index++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
ImGui::Text("Single (with list)");
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
ImGui::Text("Single (combo box)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define DRUM_FREQ(name,db,df,prop) \
|
||||
|
|
|
@ -1326,6 +1326,23 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.susPosition=1;
|
||||
}
|
||||
|
||||
ImGui::Text("Macro editor layout:");
|
||||
if (ImGui::RadioButton("Unified##mel0",settings.macroLayout==0)) {
|
||||
settings.macroLayout=0;
|
||||
}
|
||||
if (ImGui::RadioButton("Mobile##mel1",settings.macroLayout==1)) {
|
||||
settings.macroLayout=1;
|
||||
}
|
||||
if (ImGui::RadioButton("Grid##mel2",settings.macroLayout==2)) {
|
||||
settings.macroLayout=2;
|
||||
}
|
||||
if (ImGui::RadioButton("Single (with list)##mel3",settings.macroLayout==3)) {
|
||||
settings.macroLayout=3;
|
||||
}
|
||||
if (ImGui::RadioButton("Single (combo box)##mel4",settings.macroLayout==4)) {
|
||||
settings.macroLayout=4;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Namco 163 chip name");
|
||||
|
@ -2405,6 +2422,7 @@ void FurnaceGUI::syncSettings() {
|
|||
settings.persistFadeOut=e->getConfInt("persistFadeOut",1);
|
||||
settings.exportLoops=e->getConfInt("exportLoops",0);
|
||||
settings.exportFadeOut=e->getConfDouble("exportFadeOut",0.0);
|
||||
settings.macroLayout=e->getConfInt("macroLayout",0);
|
||||
|
||||
clampSetting(settings.mainFontSize,2,96);
|
||||
clampSetting(settings.patFontSize,2,96);
|
||||
|
@ -2511,6 +2529,7 @@ void FurnaceGUI::syncSettings() {
|
|||
clampSetting(settings.centerPattern,0,1);
|
||||
clampSetting(settings.ordersCursor,0,1);
|
||||
clampSetting(settings.persistFadeOut,0,1);
|
||||
clampSetting(settings.macroLayout,0,4);
|
||||
|
||||
if (settings.exportLoops<0.0) settings.exportLoops=0.0;
|
||||
if (settings.exportFadeOut<0.0) settings.exportFadeOut=0.0;
|
||||
|
@ -2683,6 +2702,7 @@ void FurnaceGUI::commitSettings() {
|
|||
e->setConf("persistFadeOut",settings.persistFadeOut);
|
||||
e->setConf("exportLoops",settings.exportLoops);
|
||||
e->setConf("exportFadeOut",settings.exportFadeOut);
|
||||
e->setConf("macroLayout",settings.macroLayout);
|
||||
|
||||
// colors
|
||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||
|
|
Loading…
Reference in a new issue