/** * 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 #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; inoteOff(activeNotes[i].chan); } activeNotes.clear(); } break; case GUI_ACTION_OCTAVE_DOWN: if (--curOctave<-5) { curOctave=-5; } else { for (size_t i=0; inoteOff(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()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()song.ordersLen-1) { e->setOrder(e->getOrder()+1); } break; case GUI_ACTION_ORDERS_LEFT: { DETERMINE_FIRST; do { orderCursor--; if (orderCursorsong.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; } }